using System; using System.Text; using System.IO; using System.Threading; using Microsoft.SPOT; using Microsoft.SPOT.IO; using GHI.IO.Storage; namespace abstractState { public class EngrLogger { private static StringBuilder columnNames = new StringBuilder(); private static SDCard sdCard; public static VolumeInfo sdVol; private static FileStream logFile; private static StringBuilder sbTemp = new StringBuilder(4096); private static StringBuilder sbWrite = new StringBuilder(4096); private static StringBuilder sbPrefix = new StringBuilder(4096); private static object loggerLock = new object(); private static byte[] writeArray = new byte[4096]; private static DateTime timeNow; private static char token = '\t'; private static bool fileOpen = false; private static bool SDMounted = false; public enum ColumnNums : int { //First the prefix for all records dateTime = 0, state, comment, //Then the verbosity level 0 stuff pressure, bellowsPosition, batteryBusVolts, //CTD Stuff CTDTemp, CTDSalinity, //PTH Stuff LPS331Pressure, LPS331Temperature, SHT21Humidity, SHT21Temperature, //Science data FLBB, TOpt, TPhase, RPhase, NO3, pH, //CTD stuff platformLPFVel, platformDiffVel, platformLPFAcc, pressureAverage, pressureVariance, //PID stuff PID_setPoint, PID_PV, PID_y1, PID_y2, PID_I, PID_v, PID_u, PID_uCPS, //ADC Stuff batteryBusAmps, Amps12V, Amps33V, debug, //GPS Stuff GPS, //Iridium Modem Stuff IModem, lastColumn, } private static StringBuilder[] columnName = new StringBuilder[(int)ColumnNums.lastColumn]; public static bool init() { for (int i = 0; i < (int)ColumnNums.lastColumn; i++) columnName[i] = new StringBuilder(32); columnName[(int)ColumnNums.dateTime].Append("Date\tTime"); columnName[(int)ColumnNums.state].Append("State"); columnName[(int)ColumnNums.comment].Append("Comment"); columnName[(int)ColumnNums.pressure].Append("Pressure"); columnName[(int)ColumnNums.bellowsPosition].Append("Bel Pos"); columnName[(int)ColumnNums.batteryBusVolts].Append("Batt Volt"); columnName[(int)ColumnNums.GPS].Append("GPS"); columnName[(int)ColumnNums.IModem].Append("Irid Modem"); columnName[(int)ColumnNums.LPS331Pressure].Append("LPS331 Press"); columnName[(int)ColumnNums.LPS331Temperature].Append("LPS311 Temp"); columnName[(int)ColumnNums.SHT21Humidity].Append("SHT21 Humid"); columnName[(int)ColumnNums.SHT21Temperature].Append("SHT21 Temp"); columnName[(int)ColumnNums.CTDTemp].Append("CTD Temp"); columnName[(int)ColumnNums.CTDSalinity].Append("CTD Sal"); columnName[(int)ColumnNums.FLBB].Append("FLBB"); columnName[(int)ColumnNums.TOpt].Append("Topt"); columnName[(int)ColumnNums.TPhase].Append("Tphase"); columnName[(int)ColumnNums.RPhase].Append("Rphase"); columnName[(int)ColumnNums.NO3].Append("NO3"); columnName[(int)ColumnNums.pH].Append("pH"); columnName[(int)ColumnNums.platformLPFVel].Append("LPF PVel"); columnName[(int)ColumnNums.platformDiffVel].Append("Diff PVel"); columnName[(int)ColumnNums.platformLPFAcc].Append("LPF PAcc"); columnName[(int)ColumnNums.pressureAverage].Append("Press Avg"); columnName[(int)ColumnNums.pressureVariance].Append("Press Var"); columnName[(int)ColumnNums.PID_setPoint].Append("PID SP"); columnName[(int)ColumnNums.PID_PV].Append("PID PV"); columnName[(int)ColumnNums.PID_y1].Append("PID Y1"); columnName[(int)ColumnNums.PID_y2].Append("PID Y2"); columnName[(int)ColumnNums.PID_I].Append("PID I"); columnName[(int)ColumnNums.PID_v].Append("PID v"); columnName[(int)ColumnNums.PID_u].Append("PID u"); columnName[(int)ColumnNums.PID_uCPS].Append("PID uCPS"); columnName[(int)ColumnNums.batteryBusAmps].Append("Batt Amps"); columnName[(int)ColumnNums.Amps12V].Append("12V Amps"); columnName[(int)ColumnNums.Amps33V].Append("3.3V Amps"); columnName[(int)ColumnNums.debug].Append("Debug"); columnNames.Clear(); for (int i = 0; i < (int)ColumnNums.lastColumn; i++) { columnNames.Append(columnName[i]); columnNames.Append("\t"); } columnNames.Append("\r\n"); for (int i = 0; i < sbFileNames.Length; i++) sbFileNames[i] = new StringBuilder(128); try { sdCard = new SDCard(); sdCard.Mount(); sdVol = new VolumeInfo("SD"); SDMounted = true; } catch { SDMounted = false; sbTemp.Clear(); sbTemp.Append("\r\n***Exception mounting SD card\r\n"); Debug.Print(sbTemp.ToString()); BTConsole.SendLine(sbTemp); } if (SDMounted) { openFile(); sbTemp.Clear(); sbTemp.Append("File Name = "); sbTemp.Append(fileName.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("Volume Total Size: "); sbTemp.Append(sdVol.TotalSize.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("Volume Free Space: "); sbTemp.Append(sdVol.TotalFreeSpace.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } } sbTemp.Clear(); sbTemp.Append("PlatVel/Pressure PID K = "); sbTemp.Append(configFile.KPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.KPressure.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("PlatVel/Pressure PID Ti = "); sbTemp.Append(configFile.TiPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.TiPressure.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("PlatVel/Pressure PID Td = "); sbTemp.Append(configFile.TdPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.TdPressure.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("PlatVel/Pressure PID Tf = "); sbTemp.Append(configFile.TfPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.TfPressure.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("PlatVel/Pressure PID Tt = "); sbTemp.Append(configFile.TtPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.TtPressure.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("PlatVel/Pressure PID B = "); sbTemp.Append(configFile.BPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.BPressure.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("PlatVel/Pressure PID uLow = "); sbTemp.Append(configFile.uLowPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.uLowPressure.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("PlatVel/Pressure PID uHigh = "); sbTemp.Append(configFile.uHighPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.uHighPressure.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("PlatVel/Pressure PID h = "); sbTemp.Append(configFile.hPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.hPressure.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } if (SDMounted) return (true); else return (false); } private static int lastValueIndex = 0; private static int columnNum = 0; private static int valueNum = 0; //If only one entry is in value array passed to his method, it gets treated as a comment and this method prepends date, time and state //All CR/LF are removed from the data until just before writing to SD card public static void writeToColumns(params object[] values) { lock (loggerLock) { timeNow = DateTime.Now; sbWrite.Clear(); if (values.Length == 1) { sbWrite.Append(timeNow.ToString("dd-MMM-yyyy")); sbWrite.Append(token); sbWrite.Append(timeNow.ToString("HH:mm:ss.fff")); sbWrite.Append(token); sbWrite.Append(Program.cpfState[(int)Program.CurrentState].stateName); sbWrite.Append(token); sbWrite.Append(values[0]); } else { lastValueIndex = values.Length - 1; for (columnNum = 0; columnNum < (int)ColumnNums.lastColumn; columnNum++) { for (valueNum = 0; valueNum < lastValueIndex; valueNum = valueNum + 2) { if ((int)values[valueNum] == columnNum) { //TODO need to do a better job formatting values to minimize length if (columnNum == (int)ColumnNums.dateTime) { timeNow = (DateTime)values[valueNum + 1]; sbWrite.Append(timeNow.ToString("dd-MMM-yyyy")); sbWrite.Append(token); sbWrite.Append(timeNow.ToString("HH:mm:ss.fff")); } else if (columnNum == (int)ColumnNums.state) sbWrite.Append(Program.cpfState[(int)Program.CurrentState].stateName); else if (columnNum == (int)ColumnNums.comment) sbWrite.Append(values[valueNum + 1]); else if ((columnNum == (int)ColumnNums.CTDSalinity) || (columnNum == (int)ColumnNums.TOpt) || (columnNum == (int)ColumnNums.IModem) || (columnNum == (int)ColumnNums.GPS) || (columnNum == (int)ColumnNums.FLBB)) { sbTemp.Clear(); sbTemp.Append(UTF8Encoding.UTF8.GetChars((byte[])values[valueNum + 1])); sbTemp.Replace('\r', ' '); sbTemp.Replace('\n', ' '); sbWrite.Append(sbTemp); } else sbWrite.Append(((double)values[valueNum + 1]).ToString("f6")); break; } } sbWrite.Append(token); } } if (SDMounted) { Array.Clear(writeArray, 0, writeArray.Length); Array.Copy(UTF8Encoding.UTF8.GetBytes(sbWrite.ToString()), writeArray, sbWrite.Length); logFile.Write(writeArray, 0, sbWrite.Length); } else { sbTemp.Clear(); sbTemp.Append("No SD: "); sbTemp.Append(sbWrite); sbWrite.Clear(); sbWrite.Append(sbTemp); } BTConsole.SendLine(sbWrite); } //Clear any terminating CR or LF since Debug.Print adds a CR/LF and TerraTerm should be set up to add a CR/LF sbWrite.Replace('\r', (char)32); sbWrite.Replace('\n', (char)32); Debug.Print(sbWrite.ToString()); } private static void printVolInfo() { sbTemp.Clear(); sbTemp.Append("Volume Total Size: "); sbTemp.Append(sdVol.TotalSize.ToString()); lock (loggerLock) { writeToColumns(ColumnNums.comment, sbTemp); } sbTemp.Clear(); sbTemp.Append("Volume Free Space: "); sbTemp.Append(sdVol.TotalFreeSpace.ToString()); lock (loggerLock) { writeToColumns(ColumnNums.comment, sbTemp); } } private const int numFilesToGet = 10; public static StringBuilder[] sbFileNames = new StringBuilder[numFilesToGet]; public static void getDirectory() { int j = numFilesToGet - 1; String[] fileNames = Directory.GetFiles(sdVol.RootDirectory); sbTemp.Clear(); sbTemp.Append("Processing GETDIR Console message"); EngrLogger.writeToColumns(sbTemp); for (int i = fileNames.Length - numFilesToGet; i < fileNames.Length; i++) { FileInfo fileInfo = new FileInfo(fileNames[i]); sbFileNames[j].Clear(); sbFileNames[j].Append(fileNames[i]); sbTemp.Clear(); sbTemp.Append("File ID = " + j.ToString() + " File Name = " + sbFileNames[j].ToString() + " Creation Date = " + fileInfo.CreationTime.ToString() + " Length = " + fileInfo.Length.ToString() + " FileNum = " + i.ToString()); Debug.Print(sbTemp.ToString()); sbTemp.AppendLine(); BTConsole.SendLine(sbTemp); j = j - 1; } } public static void closeFile() { if (fileOpen) logFile.Close(); fileOpen = false; } public static StringBuilder fileName = new StringBuilder(128); public static void openFile() { if (fileOpen) closeFile(); timeNow = DateTime.Now; fileName.Clear(); fileName.Append(sdVol.RootDirectory); fileName.Append("\\"); fileName.Append(timeNow.Year.ToString()); fileName.Append("-"); fileName.Append(timeNow.Month.ToString()); fileName.Append("-"); fileName.Append(timeNow.Day.ToString()); fileName.Append("T"); fileName.Append(timeNow.Hour.ToString()); fileName.Append("-"); fileName.Append(timeNow.Minute.ToString()); fileName.Append("-"); fileName.Append(timeNow.Second.ToString()); logFile = new FileStream(fileName.ToString(), FileMode.OpenOrCreate, FileAccess.Write); fileOpen = true; Thread.Sleep(1000); lock (loggerLock) { logFile.Write(UTF8Encoding.UTF8.GetBytes(columnNames.ToString()), 0, columnNames.Length); } BTConsole.SendLine(columnNames); Debug.Print(columnNames.ToString()); } public static void unMount() { sdCard.Unmount(); } public static StringBuilder getPrefix(StringBuilder comment) { timeNow = DateTime.Now; sbPrefix.Clear(); sbPrefix.Append(timeNow.ToString("MMM dd, yyyy")); sbPrefix.Append(token); sbPrefix.Append(timeNow.ToString("HH:mm:ss.fff")); sbPrefix.Append(token); sbPrefix.Append(Program.cpfState[(int)Program.CurrentState].stateName); sbPrefix.Append(token); sbPrefix.Append(comment); return (sbPrefix); } //"quickWriteToColumns (quickWTC) for writing a simple string public static void quickWTC(string message) { sbTemp.Clear(); sbTemp.Append(message); writeToColumns(sbTemp); sbTemp.Clear(); } } } //Column names need to be appended in the same order as ColumnNum enum above //columnNames.Clear(); //columnNames.Append("Date\tTime\tState\t"); //columnNames.Append("Comment\t"); //columnNames.Append("Pressure\tBel Pos\tBatt Volt\t"); //columnNames.Append("GPS\t"); //columnNames.Append("Iridium\t"); //columnNames.Append("LPS331Press\tLPS331Temp\tSHT21Humid\tSHT21Temp\t"); //columnNames.Append("CTD Temp.\tCTD Sal.\t"); //columnNames.Append("Topt\tTPhase\tC1Rphase\t"); //columnNames.Append("NO3\tpH\t"); //columnNames.Append("FSig\tBbSig\tTsig\t"); //columnNames.Append("Pres Timestamp\tPlat LPF Vel\tPlat Diff Vel\tPlat LPF Acc\tPress Avg\tPress Var\t"); //columnNames.Append("PID SP\tPID PV\ty1\ty2\tI\tv\tu\tuCPS\t"); //columnNames.Append("Batt Cur\t12V Cur\t3.3V Cur\t"); //columnNames.Append("\r\n"); //private static StringBuilder sbRecord = new StringBuilder(StructQueue.byteArrayWidth); //public static StringBuilder formatRecord(params object[] values) //{ // lock (loggerLock) // { // lastValueIndex = values.Length - 1; // sbRecord.Clear(); // for (columnNum = 0; columnNum < (int)ColumnNums.lastColumn; columnNum++) // { // for (valueNum = 0; valueNum < lastValueIndex; valueNum = valueNum + 2) // { // if ((int)values[valueNum] == columnNum) // { // //TODO need to do a better job formatting values to minimize length // if (columnNum == (int)ColumnNums.comment) // sbRecord.Append(values[valueNum + 1].ToString()); // else if ((columnNum == (int)ColumnNums.TOpt) // || (columnNum == (int)ColumnNums.CTDSalinity) // || (columnNum == (int)ColumnNums.GPS) // || (columnNum == (int)ColumnNums.IModem)) // { // sbTemp.Clear(); // sbTemp.Append(UTF8Encoding.UTF8.GetChars((byte[])values[valueNum + 1])); // sbRecord.Append(sbTemp); // } // else // sbRecord.Append(((double)values[valueNum + 1]).ToString("f6")); // break; // } // } // sbRecord.Append(token); // } // //Debug.Print(sbRecord.ToString()); // sbRecord.AppendLine(); // return sbRecord; // } //}