using System; using System.Text; using System.Reflection; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using Microsoft.SPOT.IO; using System.IO; using System.IO.Ports; using CPF; using GHI.IO.Storage; using MFUnitTest; using CPF.FileTransfer; using GHI.Usb.Host; namespace CPFUnitTests { class CpfConsole { // Constants private const bool GC_LOCALECHO = true; private const byte GC_MAXTOKENS = 10; // Limits of FAT32 Filesystems private const int GC_MAXFILES = 125; private const byte GC_MAXFILEN = 0xFF; private const int GC_MAXPATHL = 0xFFF; private char[] GC_DELIMITERS = new char[] { ' ', ',' }; public enum CMD { HELP, PWD, DIR, CD, MKDIR, CP, RM, MV, SZ, RZ, UT, COM, REBOOT, POW, UNKNOWN, }; private enum UT { Console, ZmodemConsole, EngLogger, Iridium, Rudics, Ctd, Optode, Pump, Pth, Elmo, Gps, Watchdog, Unknown }; private enum PORT { COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, COM10, COM11, COM12, Unknown }; // IO private SerialPort sPort; private SerialPort comPort; private I2CSerialPort i2cComport; private bool isI2cPort; #if GEN2 private MotherBoard _mb; #endif // SD CARD private SDCard sdCard; private VolumeInfo viSDCard; // SerialPort BUFFER private const int GC_MAXMESSAGESIZE = 0xFFF; private StringBuilder sbInput = new StringBuilder(GC_MAXMESSAGESIZE); private byte[] txbuff; private byte[] rxbuff; private int rxbuffpos; int bytesAvailable; // Program Mode public CMD modeCMD { get; protected set; } //CommandParser private string[] cmdtok = new string[GC_MAXTOKENS]; //Directory buffers private string[] dirbuff = new string[GC_MAXFILES]; private StringBuilder srcdir = new StringBuilder(GC_MAXPATHL); private StringBuilder desdir = new StringBuilder(GC_MAXPATHL); private StringBuilder pwDir = new StringBuilder(GC_MAXPATHL); public CpfConsole(SerialPort port) { modeCMD = CMD.UNKNOWN; sPort = port; txbuff = new byte[GC_MAXMESSAGESIZE]; rxbuff = new byte[GC_MAXMESSAGESIZE]; #if GEN2 _mb = MotherBoard.Instance; #endif rxbuffpos = 0; sPort.Open(); // SD Card init try { //sdCard = new SDCard(); //sdCard.Mount(); viSDCard = new VolumeInfo("SD"); } catch (Exception e) { ////TODO Error here. Debug.Print("Can't Load SDCard:" + e.ToString()); } this.pwDir.Clear(); this.pwDir.Append(viSDCard.RootDirectory); } public void welcomeMessage() { Assembly asm = Assembly.GetExecutingAssembly(); writeLine("\r\nCoastal Profiling Float Console \r\n" + "Assembly: " + asm.FullName + "\r\n\r"); } public void printPrompt() { txbuff = Encoding.UTF8.GetBytes("\n\rCPF>"); sPort.Write(txbuff, 0, txbuff.Length); } public void read() { bytesAvailable = sPort.BytesToRead; if (bytesAvailable > 0) { sPort.Read(rxbuff, rxbuffpos, 1); if (GC_LOCALECHO) sPort.Write(rxbuff, rxbuffpos, 1); //echo the character rxbuffpos++; } else return; if (rxbuff[rxbuffpos - 1] == '\r' || rxbuff[rxbuffpos - 1] == '\n') { this.gotCommand(); } } public void readUntilLN() { bytesAvailable = sPort.BytesToRead; if (bytesAvailable <= 0) return; for (int i = 0; i < bytesAvailable; i++) { sPort.Read(rxbuff, rxbuffpos, 1); if (GC_LOCALECHO) { sPort.Write(rxbuff, rxbuffpos, 1); } // If we are in a serial Port command program if (modeCMD == CMD.COM) { try { if (rxbuff[rxbuffpos] == 0x03) //ETX CTRL-C Received { writeLine("CTRL-C Received, exiting program...\r\n\r"); modeCMD = CMD.UNKNOWN; if (isI2cPort) i2cComport.Close(); else comPort.Close(); } else if (isI2cPort) i2cComport.WriteByte(rxbuff[rxbuffpos]); else comPort.WriteByte(rxbuff[rxbuffpos]); return; } catch { writeLine("Error writing to com port, exiting com program.\r\n"); if (isI2cPort) i2cComport.Close(); else comPort.Close(); modeCMD = CMD.UNKNOWN; return; } } rxbuffpos++; //enable backspace functionality. if (rxbuff[rxbuffpos - 1] == '\b') { rxbuffpos -= 2; if (rxbuffpos < 0) rxbuffpos = 0; sPort.WriteByte(32); sPort.WriteByte(8); continue; } if ((rxbuff[rxbuffpos - 1] == '\r' || rxbuff[rxbuffpos - 1] == '\n')) { this.gotCommand(); } } } public void writeLine(string s) { txbuff = Encoding.UTF8.GetBytes(s); sPort.Write(txbuff, 0, txbuff.Length); } // BUFFER COMMANDS TODO MOVE TO SUBCLASS public void gotCommand() { // Test for Case in rcving \r\n from the console if (rxbuffpos == 1) { rxbuffpos = 0; Array.Clear(rxbuff, 0, rxbuff.Length); writeLine("\r"); printPrompt(); return; } //else sbInput.Clear(); try { sbInput.Append(UTF8Encoding.UTF8.GetChars(rxbuff, 0, rxbuffpos - 1)); Debug.Print("GOT LINE: " + sbInput.ToString()); //TODO take some actions this.ProcessCommand(); } catch { // ignored } rxbuffpos = 0; Array.Clear(rxbuff, 0, rxbuff.Length); } private void ProcessCommand() { CMD cmd = CMD.UNKNOWN; byte itok = 0; Array.Clear(cmdtok, 0, cmdtok.Length); cmdtok = sbInput.ToString().Trim().Split(GC_DELIMITERS, (int)GC_MAXTOKENS); //Decode Command cmd = decodeCommand(cmdtok[0]); //Output to DEBUG foreach (var s in cmdtok) { if (itok == 0) continue; Debug.Print("GOT TOK: " + s); itok++; } writeLine("\r\n"); switch (cmd) { case CMD.HELP: printHelp(); break; case CMD.PWD: presentWorkingDirectory(); break; case CMD.DIR: dir(); break; case CMD.CD: cd(); break; case CMD.MKDIR: mkdir(); break; case CMD.CP: cpormv(CMD.CP); break; case CMD.RM: rm(); break; case CMD.MV: cpormv(CMD.MV); break; case CMD.SZ: sz(); break; case CMD.RZ: rz(); break; case CMD.UT: ut(); break; case CMD.COM: com(); break; case CMD.POW: #if GEN2 pow(); #else writeLine("Incompatible command\r\n"); #endif break; case CMD.REBOOT: reboot(); break; case CMD.UNKNOWN: writeLine("ERROR: Unknown CMD\r\n"); break; } //at end print out new prompt printPrompt(); } private void pow() { int channel = -1; if (cmdtok.Length < 3) { writeLine("usage: pow "); return; } //channel number try { channel = int.Parse(cmdtok[1]); if (channel < 1 || channel >12) throw new ArgumentOutOfRangeException(); } catch { writeLine("Invalid channel number: "+cmdtok[1]+"\r\n"); return; } //state if (string.Equals("on", cmdtok[2])) { #if GEN2 _mb.EnableChannelPower(channel); #endif } else if (string.Equals("off", cmdtok[2])) { #if GEN2 _mb.DisableChannelPower(channel); #endif } } private void com() { if (cmdtok.Length < 2) { writeLine("usage: com \r\n" + "\t defaults are 9600 8 N 1"); return; } //Set Defaults int portnum = 2; int baud = 9600; int databits = 8; Parity parity = Parity.None; StopBits stopbits = StopBits.One; if (!ParseSerialConfig(ref portnum, ref baud, ref databits, ref parity)) return; //For traditional serialports if (portnum <= 6) { try { comPort = new SerialPort("COM" + portnum.ToString(), baud, parity, databits, stopbits); comPort.Open(); comPort.DataReceived += ComPortOnDataReceived; isI2cPort = false; } catch (Exception e) { writeLine("Error Opening SerialPort " + portnum.ToString() + ":" + e.ToString()); return; } } //For i2c ports (slots 3-6) if (portnum > 6) { i2cComport = new I2CSerialPort("COM" + portnum.ToString(), baud, databits, parity, stopbits); i2cComport.Open(); i2cComport.DataReceived += I2CPortOnDataReceived; isI2cPort = true; } writeLine("Serial Port Connected, press CTRL-C to exit program...\r\n\r"); modeCMD = CMD.COM; } private void I2CPortOnDataReceived(object sender, EventArgs e) { int bytesToRead = i2cComport.BytesToRead; int inChar; if (bytesToRead == 0) return; for (int i = 0; i < bytesToRead; ++i) { inChar = i2cComport.ReadByte(); if (inChar == -1) return; sPort.WriteByte((byte) inChar); } } private void ComPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs) { int bytesToRead = comPort.BytesToRead; int inChar; if (bytesToRead == 0) return; for (int i = 0; i < bytesToRead; ++i) { inChar = comPort.ReadByte(); if (inChar == -1) return; sPort.WriteByte((byte) inChar); } } private bool ParseSerialConfig(ref int portnum, ref int baud, ref int databits, ref Parity parity) { StopBits stopbits; for (int i = 1; i < cmdtok.Length; ++i) { switch (i) { case 1: //portnum try { portnum = int.Parse(cmdtok[1]); if (string.Equals("COM"+portnum.ToString(), sPort.PortName) || portnum < 1 || portnum > 12) throw new ArgumentOutOfRangeException("invalid portnum"); } catch { writeLine("Invalid Portnum Specified " + cmdtok[1] + "\r\n"); return false; } break; case 2: //baudrate try { baud = int.Parse(cmdtok[2]); } catch { writeLine("Invalid Baud Rate Specified: " + cmdtok[2] + "\r\n"); return false; } break; case 3: //databits try { databits = int.Parse(cmdtok[3]); if (databits < 5 || databits > 8) throw new ArgumentOutOfRangeException("invalid databits"); } catch { writeLine("Invalid Databits Specified: " + cmdtok[3] + "\r\n"); return false; } break; case 4: //parity try { if (string.Equals(cmdtok[4].ToLower(), "n")) parity = Parity.None; else if (string.Equals(cmdtok[4].ToLower(), "e")) parity = Parity.Even; else if (string.Equals(cmdtok[4].ToLower(), "o")) parity = Parity.Odd; else if (string.Equals(cmdtok[4].ToLower(), "m")) parity = Parity.Mark; else if (string.Equals(cmdtok[4].ToLower(), "s")) parity = Parity.Space; else throw new ArgumentOutOfRangeException("Invalid parity"); } catch { writeLine("Invalid Parity Specified: " + cmdtok[4] + "\r\n"); return false; } break; case 5: //stopbits try { double dStopbits = double.Parse(cmdtok[5]); if (dStopbits == 1) stopbits = StopBits.One; else if (dStopbits == 1.5) stopbits = StopBits.OnePointFive; else if (dStopbits == 2) stopbits = StopBits.Two; else if (dStopbits == 0) stopbits = StopBits.None; else throw new ArgumentOutOfRangeException("Invalid stopbits"); } catch { writeLine("Invalid Stopbits Specified: " + cmdtok[5] + "\r\n"); return false; } break; } } return true; } private void mkdir() { DirectoryInfo dinfo; if (cmdtok.Length < 2) { writeLine("usage: mkdir \r\n"); return; } changeWorkingDir(ref desdir, 1); try { if (Directory.Exists(desdir.ToString())) { writeLine("ERROR: directory already exists.\r\n"); return; } dinfo = Directory.CreateDirectory(desdir.ToString()); if (dinfo == null) { writeLine("ERROR: directory creation failed.\r\n"); return; } } catch { writeLine("ERROR: directory creation failed.\r\n"); return; } writeLine("Directory successfully created at " + dinfo.CreationTimeUtc.ToString() + "\r\n"); } private void rm() { int sarg = 0; if (cmdtok.Length < 2) { writeLine("usage: rm or rm -f \r\n"); return; } sarg = (cmdtok[1][0] == '-') ? 1 : 0; //change input to full path changeWorkingDir(ref srcdir, 1 + sarg); try { if (!File.Exists(srcdir.ToString()) && !Directory.Exists(srcdir.ToString())) { writeLine("ERROR: file/dir does not exist\r\n"); return; } } catch { writeLine("ERROR: file/dir does not exist\r\n"); return; } //delete file if (sarg == 0) { try { File.Delete(srcdir.ToString()); } catch { writeLine("ERROR: File delete failed.\r\n"); return; } writeLine("File(s) deleted.\r\n"); } else if (sarg == 1) { try { Directory.Delete(srcdir.ToString()); } catch { writeLine("ERROR: Directory delete failed.\r\n"); return; } writeLine("Directory deleted. \r\n"); } } private void rz() { writeLine("Beginning Zmodem Receive.\r\n"); ZmodemReceiver zr = new ZmodemReceiver(sPort, false); zr.filePrefix = "\\SD\\"; while (zr.doTasks()) { }; return; } private void sz() { if (cmdtok.Length < 2) { writeLine("usage sz \r\n"); return; } changeWorkingDir(ref srcdir, 1); try { if (File.Exists(srcdir.ToString()) == false) { writeLine("ERROR: No such source file.\r\n"); return; } } catch { writeLine("ERROR: No such source file.\r\n"); return; } //Ok, we can try to conduct a ZMODEM interaction... ZmodemSender zs = new ZmodemSender(sPort, srcdir.ToString()); //it will eventually give up or finish... single file at this point. while (zs.doTasks()) { }; writeLine("Zmodem Finished...\r\n"); return; } private void reboot() { PowerState.RebootDevice(false); } private void ut() { if (cmdtok.Length < 2) { writeLine("usage ut \r\n"); writeLine("\t available options are: \r\n" + "\t\t console \t- simple console print and read tests\r\n" + "\t\t zmodem \t- test zmodem send and receive.\r\n" + "\t\t englogger \t- test some write commands to the engrlogger\r\n" + "\t\t iridium \t- test iridium driver functions except for rudics\r\n" + "\t\t rudics \t- test iridium drivers for full rudics connections to the main server\r\n" + "\t\t ctd \t- test the seabird 41 drivers\r\n" + "\t\t optode \t- optode driver test\r\n" + "\t\t gps \t- test the GPS and driver" + "\t\t pump \t- test the elmo driver\r\n" + "\t\t pth \t- test pressure temp and humid sensor\r\n" + "\t\t elmo \t- test gps drivers\r\n" + "\t\t watchdog \t- test the watchdog\r\n"); return; } switch (DecodeUnitTest(cmdtok[1])) { case UT.Console: writeLine("Running Bluetooth Console Unit Test\n\r"); TestManager.RunTest(typeof(UnitTestBTConsole)); break; case UT.ZmodemConsole: // todo don't really need this either, we can just try zmodeming break; case UT.Ctd: //todo unimplemented break; case UT.Elmo: //todo unimplemented break; case UT.Gps: //todo unimplemented break; case UT.Optode: //todo unimplemented break; case UT.Pth: //todo unimplemented break; case UT.Pump: //todo unimplemented break; case UT.Watchdog: //todo unimplemented break; case UT.EngLogger: writeLine("Running Engineering Logger Unit Test\n\r"); TestManager.RunTest(typeof(UnitTestEngLogger)); break; case UT.Iridium: writeLine("Running Iridium Unit Test\n\r"); TestManager.RunTest(typeof(UnitTestIridium)); break; case UT.Rudics: writeLine("Running Rudics Unit Test\n\r"); TestManager.RunTest(typeof(UnitTestIridiumRUDICS)); break; default: writeLine("Unknown Unit Test \r\n"); break; } } private UT DecodeUnitTest(string s) { s = s.ToLower(); if (string.Equals(s, "console")) return UT.Console; if (string.Equals(s, "zmodem")) return UT.ZmodemConsole; if (string.Equals(s, "englogger")) return UT.EngLogger; if (string.Equals(s, "iridium")) return UT.Iridium; if (string.Equals(s, "rudics")) return UT.Rudics; if (string.Equals(s, "ctd")) return UT.Ctd; if (string.Equals(s, "optode")) return UT.Optode; if (string.Equals(s, "pump")) return UT.Pump; if (string.Equals(s, "pth")) return UT.Pth; if (string.Equals(s, "gps")) return UT.Gps; if (string.Equals(s, "elmo")) return UT.Elmo; if (string.Equals(s, "watchdog")) return UT.Watchdog; return UT.Unknown; } private void cpormv(CMD type) { int sarg = 0; bool overwrite = false; //ok this has to have multiple inputs if (cmdtok.Length < 3) { writeLine("usage: cp \r\n"); return; } //create offset if flag exists sarg = (cmdtok[1][0] == '-') ? 1 : 0; overwrite = (sarg == 1) ? true : false; // Change and verify inputs. changeWorkingDir(ref srcdir, 1 + sarg); try { if (File.Exists(srcdir.ToString()) == false) { writeLine("ERROR: No such source file.\r\n"); return; } } catch { writeLine("ERROR: No such source file.\r\n"); return; } changeWorkingDir(ref desdir, 2 + sarg); if (Path.GetDirectoryName(desdir.ToString()) == String.Empty || Path.GetDirectoryName(desdir.ToString()) == null) { writeLine("ERROR: No such destination directory.\r\n"); return; } try { if (File.Exists(desdir.ToString()) == true && overwrite == false) { writeLine(Path.GetFileName(desdir.ToString()) + ":exists, use -f flag to overwrite\r\n"); return; } } catch { writeLine("ERROR: No such destination directory.\r\n"); return; } //OK We can attempt the copy. try { if (type == CMD.CP) File.Copy(srcdir.ToString(), desdir.ToString(), overwrite); else if (type == CMD.MV) File.Move(srcdir.ToString(), desdir.ToString()); } catch { if (type == CMD.CP) writeLine("ERROR: Copy Failed\r\n"); else if (type == CMD.MV) writeLine("ERROR: Move Failed\r\n"); return; } if (type == CMD.CP) writeLine("1 File(s) copied.\r\n"); else if (type == CMD.MV) writeLine("1 File(s) moved.\r\n"); } private void cd() { changeWorkingDir(ref srcdir, 1); try { if (Directory.Exists(srcdir.ToString()) == false) { writeLine("ERROR: No such directory.\r\n"); return; } } catch { writeLine("ERROR: No such directory.\r\n"); return; } pwDir.Clear(); pwDir.Append(srcdir); writeLine("Changed working directory to " + pwDir.ToString()); } private void dir() { changeWorkingDir(ref srcdir, 1); try { if (Directory.Exists(srcdir.ToString()) == false) { writeLine("ERROR: No such directory.\r\n"); return; } } catch { writeLine("ERROR: Invalid Input\r\n"); return; } //list files in directory Array.Clear(dirbuff, 0, dirbuff.Length); dirbuff = Directory.GetFiles(srcdir.ToString()); writeLine("\r\nFiles in " + srcdir.ToString() + "\r\n"); for (int i = 0; i < dirbuff.Length; i++) writeLine("\t" + Path.GetFileName(dirbuff[i]) + "\r\n"); //list directories in directory Array.Clear(dirbuff, 0, dirbuff.Length); dirbuff = Directory.GetDirectories(srcdir.ToString()); writeLine("\r\nDirectories in " + srcdir.ToString() + "\r\n"); for (int i = 0; i < dirbuff.Length; i++) { writeLine("\t" + dirbuff[i] + "\r\n"); } } private void changeWorkingDir(ref StringBuilder sb, int offset) { sb.Clear(); //Form the directory input if (cmdtok.Length == 1) { sb.Append(pwDir); } else { if (cmdtok[offset][0] == '\\') //This a is fully qualified path. sb.Append(cmdtok[offset]); else { sb.Append(pwDir); sb.Append("\\"); sb.Append(cmdtok[offset]); } } } private void presentWorkingDirectory() { writeLine(this.pwDir.ToString() + "\r\n"); } private void printHelp() { writeLine("AVAILABLE COMMANDS:\r\n"); writeLine("HELP - This printout\r\n"); writeLine("PWD - Present Working Dir\r\n"); writeLine("DIR - List files in PWD\r\n"); writeLine("CD - Change Directory\r\n"); writeLine("MKDIR - Make Directory\r\n"); writeLine("CP - Copy\r\n"); writeLine("RM - Delete/Remove\r\n"); writeLine("MV - Move\r\n"); writeLine("SZ - Send via ZMODEM\r\n"); writeLine("RZ - Receive via ZMODEM\r\n" + "UT - Conduct Unit Test\r\n" + "REBOOT- Hard Reboot Processor\r\n" + "COM - Open an native or i2c serial port\r\n" + " (enable power first)\r\n" + "POW - Switch power on available channels.\r\n"); } private CMD decodeCommand(string s) { s = s.ToLower(); if (String.Equals(s, "help")) return CMD.HELP; if (String.Equals(s, "pwd")) return CMD.PWD; if (String.Equals(s, "dir")) return CMD.DIR; if (String.Equals(s, "cd")) return CMD.CD; if (String.Equals(s, "mkdir")) return CMD.MKDIR; if (String.Equals(s, "cp")) return CMD.CP; if (String.Equals(s, "rm")) return CMD.RM; if (String.Equals(s, "mv")) return CMD.MV; if (String.Equals(s, "sz")) return CMD.SZ; if (String.Equals(s, "rz")) return CMD.RZ; if (String.Equals(s, "ut")) return CMD.UT; if (String.Equals(s, "com")) return CMD.COM; if (String.Equals(s, "pow")) return CMD.POW; if (String.Equals(s, "reboot")) return CMD.REBOOT; return CMD.UNKNOWN; } public void SendLine(StringBuilder builder) { writeLine(builder.ToString()); } } }