//#define USB_STORAGE using System; using System.Text; using System.IO; using System.Threading; using Microsoft.SPOT; using Microsoft.SPOT.IO; using GHI.Processor; using GHI.IO.Storage; #if(USB_STORAGE) using GHI.Usb; using GHI.Usb.Host; #endif namespace CPF { class EngrLogger { private static StringBuilder columnNames = new StringBuilder(); private static SDCard sdCard; public static VolumeInfo sdVol; private static FileStream logFile; private static FileStream newMissionFile; 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; private static bool USBMounted = 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]; #if(USB_STORAGE) private static AutoResetEvent usbInsertEvent = new AutoResetEvent(false); private static MassStorage usbStorage; #endif private static Register resetControllerStatus = new Register(0xFFFFFE04); public static bool init() { for (int i = 0; i < (int)ColumnNums.lastColumn; i++) columnName[i] = new StringBuilder(32); columnName[(int)ColumnNums.dateTime].Append("$\tDate\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); #if(USB_STORAGE) try { RemovableMedia.Insert += new InsertEventHandler(usbRemovableMedia_Insert); RemovableMedia.Eject += new EjectEventHandler(usbRemovableMedia_Eject); Controller.MassStorageConnected += (sender, massStorage) => { usbStorage = massStorage; usbStorage.Mount(); // fires the insert event when finished }; Controller.Start(); usbInsertEvent.WaitOne(); // yield here until mounting and initializing is finished sdVol = new VolumeInfo("USB"); USBMounted = true; } catch { USBMounted = false; sbTemp.Clear(); sbTemp.Append("\r\n***Exception mounting USB card\r\n"); Debug.Print(sbTemp.ToString()); Program.btConsole.SendLine(sbTemp); } #else 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()); Program.btConsole.SendLine(sbTemp); } #endif if (SDMounted || USBMounted) { openFile(); uint resetControllerStatusValue = resetControllerStatus.Value; sbTemp.Clear(); sbTemp.Append("Reset Controller Status Register Value = "); sbTemp.Append(resetControllerStatusValue.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } 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/Depth PID K = "); sbTemp.Append(configFile.KPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.KDepth.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("PlatVel/Depth PID Ti = "); sbTemp.Append(configFile.TiPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.TiDepth.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("PlatVel/Depth PID Td = "); sbTemp.Append(configFile.TdPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.TdDepth.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("PlatVel/Depth PID Tf = "); sbTemp.Append(configFile.TfPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.TfDepth.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("PlatVel/Depth PID Tt = "); sbTemp.Append(configFile.TtPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.TtDepth.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("PlatVel/Depth PID B = "); sbTemp.Append(configFile.BPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.BDepth.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("PlatVel/Depth PID uLow = "); sbTemp.Append(configFile.uLowPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.uLowDepth.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("PlatVel/Depth PID uHigh = "); sbTemp.Append(configFile.uHighPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.uHighDepth.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } sbTemp.Clear(); sbTemp.Append("PlatVel/Depth PID h = "); sbTemp.Append(configFile.hPlatVel.ToString()); sbTemp.Append(" "); sbTemp.Append(configFile.hDepth.ToString()); lock (loggerLock) { writeToColumns(sbTemp); } if (SDMounted || USBMounted) 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(); sbWrite.Append("$"); sbWrite.Append(token); 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.sbStateNames[(int)Program.CPFState]); 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.sbStateNames[(int)Program.CPFState]); 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 || USBMounted) { sbWrite.Replace('\r', ' '); sbWrite.Replace('\n', ' '); sbWrite.Append("\r\n"); 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); } Program.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 = 50; public static int numFilesOnDisk = 0; public static StringBuilder[] sbFileNames = new StringBuilder[numFilesToGet]; public static void getDirectory() { if (SDMounted == false) return; //dont try to open if there is no card String[] fileNames = Directory.GetFiles(sdVol.RootDirectory); sbTemp.Clear(); sbTemp.Append("Processing GETDIR Console message"); EngrLogger.writeToColumns(sbTemp); numFilesOnDisk = Directory.GetFiles(sdVol.RootDirectory).Length; int fileID = numFilesToGet - 1; int lastFile = numFilesOnDisk - numFilesToGet; if (lastFile < 0) lastFile = 0; if (numFilesOnDisk > 0) { for (int i = lastFile; i < numFilesOnDisk; i++) { fileID = numFilesOnDisk - (i + 1); FileInfo fileInfo = new FileInfo(fileNames[i]); sbFileNames[fileID].Clear(); sbFileNames[fileID].Append(fileNames[i]); sbTemp.Clear(); sbTemp.Append("File ID = " + fileID.ToString() + " File Name = " + fileInfo.Name + " Creation Date = " + fileInfo.CreationTime.ToString() + " Length = " + fileInfo.Length.ToString() + " FileNum = " + i.ToString()); Debug.Print(sbTemp.ToString()); sbTemp.AppendLine(); Program.btConsole.SendLine(sbTemp); fileID--; } } else { sbTemp.Clear(); sbTemp.Append("No files on disk!"); Debug.Print(sbTemp.ToString()); sbTemp.AppendLine(); Program.btConsole.SendLine(sbTemp); } } public static void closeFile() { if (fileOpen) logFile.Close(); fileOpen = false; } public static StringBuilder fileName = new StringBuilder(128); public static void openFile() { if (SDMounted == false) return; //dont try to open if there is no card 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); } Program.btConsole.SendLine(columnNames); Debug.Print(columnNames.ToString()); } public static void unMount() { if (SDMounted) sdCard.Unmount(); #if(USB_STORAGE) if (USBMounted) usbStorage.Unmount(); #endif } 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.sbStateNames[(int)Program.CPFState]); sbPrefix.Append(token); sbPrefix.Append(comment); return (sbPrefix); } // This event is fired by unmount static void usbRemovableMedia_Eject(object sender, MediaEventArgs e) { Debug.Print("USB unmounted, eject event fired"); } static void usbRemovableMedia_Insert(object sender, MediaEventArgs e) { Debug.Print("Insert event fired; USB Storage mount is finished."); //if (e.Volume.IsFormatted) //{ // rootDirectory = e.Volume.RootDirectory; // Debug.Print("Available folders:"); // string[] strs = Directory.GetDirectories(e.Volume.RootDirectory); // for (int i = 0; i < strs.Length; i++) // Debug.Print(strs[i]); // Debug.Print("Available files:"); // strs = Directory.GetFiles(e.Volume.RootDirectory); // for (int i = 0; i < strs.Length; i++) // Debug.Print(strs[i]); //} //else //{ // Debug.Print("Media is not formatted. Formatting..."); // e.Volume.Format("FAT", 0); // rootDirectory = e.Volume.RootDirectory; //} #if(USB_STORAGE) usbInsertEvent.Set(); // proceed with other processing #endif } } } //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; // } //}