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 System.Threading;
using GHI.IO.Storage;
using GHI.Processor;
using GHI.Usb.Client;
using SWModules;
using Zmodem;

namespace HWModules
{
    public class FactoryConsole
    {
        // 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,
            SCAN,
            CD,
            MKDIR,
            CP,
            RM,
            MV,
            SZ,
            RZ,
            COM,
            REBOOT,
            POW,
            DATE,
            CPF,
            SLEEP,
            CHARGEMON,
            UNKNOWN,
            READSTRINGPOT,
            VALVE,
            PUMP,
            PUMPMON,
            TOUCH,
            ENABLE,
            DISABLE,
            MASSSTORAGE,
            STATUS
        };

        private enum UT
        {
            Iridium,
            Rudics,
            Ctd,
            Optode,
            Pump,
            Elmo,
            Pth,
            Flbb,
            Gps,
            Watchdog,
            EMonBatt,
            EMonPump,
            Msc,
            IncBuoy,
            DecBuoy,
            FileFlood,
            SurfaceOps,
            DualLead,
            MotorizedValve,
            BellowsPosition,
            
            Unknown,

            Ocr
        };

        //To add a UT to this list
        // 1) Add the name to the enumerator above this
        // 2) Add a string look up DecodeUnitTest method
        // 3) Add a callback to UT method

        // IO 
        private SerialPort sPort;
        private SerialPort comPort;
        private I2CSerialPort i2cComport;
        private bool isI2cPort;
        private MotherBoard _mb;
        private HWModules.LheBoard _lhe;
        private StringBuilder sbTemp = new StringBuilder(GC_MAXMESSAGESIZE);
        private MessageQueue _messageQueue;
        private QRecord _msgQEntry;

        // 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;
        private bool closeOnEtx = true;

        // Program Mode
        public CMD modeCMD { get; protected set; }

        // Console Active flage
        public bool Enabled { 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);
        private SDStorage _sdStorage;

        public FactoryConsole(SerialPort port)
        {
            modeCMD = CMD.UNKNOWN;
            Enabled = false;

            sPort = port;
            txbuff = new byte[GC_MAXMESSAGESIZE];
            rxbuff = new byte[GC_MAXMESSAGESIZE];
            _mb = HWModules.MotherBoard.Instance;
            _lhe = HWModules.LheBoard.Instance;
            rxbuffpos = 0;
            if (!sPort.IsOpen)
                sPort.Open();

            _messageQueue = MessageQueue.Instance;
            _msgQEntry = new QRecord(ProcessMessage);

        }

        private void initFileSystem()
        {
            if (_sdStorage != null)
                return;

            // SD Card init
            _sdStorage = SDStorage.Instance;
            try
            {
                viSDCard = new VolumeInfo("\\SD");
            }
            catch (Exception e)
            {
                writeLine("Can't Load SDCard:" + e.ToString());
            }

            pwDir.Clear();
            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\n");

        }

        private readonly byte[] prompt = Encoding.UTF8.GetBytes("CPF> ");
        public void printPrompt()
        {
            sPort.Write(prompt, 0, prompt.Length);
        }

        public void printPowerTable()
        {
            writeLine(" 1:  CTD\r\n 2:  Elmo12\r\n 3:  BT\r\n 4:  IRIDIUM\r\n 5:  MSC\r\n"+
                      " 6:  Optode\r\n 7:  Slot3-J2\r\n 8:  OCR\r\n 9:  FLBB\r\n 10: Open\r\n"+
                      " 11: Open\r\n 12: Open\r\n 13: N/A\r\n 14: BellowPos\r\n 15: GPS\r\n"+
                      " 16: Valve\r\n 17: I2C ISB-J4\r\n 18: I2C ISB-J5\r\n 19: SPI ISB-J6\r\n");
        }

        public void sleep()
        {
            if (cmdtok.Length < 2) {
                writeLine("usage sleep <2^(n-1) Minutes [0-7]>\r\n");
                return;
            }

            int n;
            try
            {
                n = int.Parse(cmdtok[1]);
                if (n < 1 || n > 7)
                    throw new ArgumentException("Invalid input, please choose a value between 1 and 7");
            }
            catch (Exception e)
            {
                writeLine("Input failure for command sleep.\r\n"+e+"\r\n");
                return;
            }

            writeLine("Sleeping system for "+((int)System.Math.Pow(2,(n-1)))+ " minutes.\r\n");
            _lhe.Sleep((byte)n);
        }

        public void touch()
        {
            if (cmdtok.Length < 2)
            {
                writeLine("usage touch <filename>\r\n");
                return;
            }

            var fs = File.Create(cmdtok[1]);
            var info = new UTF8Encoding().GetBytes("TEST FILE");
            fs.Write(info, 0, info.Length);
            fs.Close();
            EngrLogger.Comment(" Touch: "+cmdtok[1]);
        }

        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 bool getch(ref byte ch, bool nonblock=true)
        {
            bytesAvailable = sPort.BytesToRead;

            if (bytesAvailable <= 0) {
                if (nonblock) return false;
                getch(ref ch, false);
            }

            sPort.Read(rxbuff, rxbuffpos, 1);
            ch = rxbuff[rxbuffpos];
            rxbuffpos++;
            return true;
        }

        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 && closeOnEtx) //ETX CTRL-C Received
                        {
                            writeLine("CTRL-C Received, exiting program...\r\n\r\n");
                            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);
        }

        public void writeLine(StringBuilder s)
        {
            writeLine(s.ToString());
        }

        // BUFFER COMMANDS 
        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\n"); 
                printPrompt();
                return;
            }

            //else


            sbInput.Clear();
            try
            {
                sbInput.Append(SafeEncoding.GetChars(rxbuff, 0, rxbuffpos - 1));
                Debug.Print("GOT LINE: " + sbInput.ToString());

                this.ProcessCommand();

            }
            catch
            {
                // ignored
            }

            rxbuffpos = 0;
            Array.Clear(rxbuff, 0, rxbuff.Length);
        }

        public void ProcessMessage(QRecord qRecord)
        {
            //TODO P5 copy the message and call ProcessCommand?
        }

        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.SCAN:
                    scanFiles();
                    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.COM:
                    com();
                    break;
                case CMD.POW:
                    pow();
                    break;
                case CMD.REBOOT:
                    reboot();
                    break;
                case CMD.DATE:
                    date();
                    break;
                case CMD.CPF:
                    cpfChange();
                    break;
                case CMD.SLEEP:
                    sleep();
                    break;
                case CMD.READSTRINGPOT:
                    readStringPot();
                    break;
                case CMD.TOUCH:
                    touch();
                    break;
                case CMD.VALVE:
                    valve();
                    break;
                case CMD.PUMP:
                    pump();
                    break;
                case CMD.CHARGEMON:
                    //TODO implement locally
                    chargemon();
                    break;
                case CMD.PUMPMON:
                    monitor_pump();
                    break;
                case CMD.STATUS:
                    status();
                    break;
                case CMD.ENABLE:
                    Enabled = true;
                    break;
                case CMD.DISABLE:
                    Enabled = false;
                    break;
                case CMD.MASSSTORAGE:
                    mass_storage_mode();
                    break;
                case CMD.UNKNOWN:
                    writeLine("ERROR: Unknown CMD\r\n");
                    break;

            }
            //at end print out new prompt
            printPrompt();
        }

        private void status()
        {
            var em = EnergyMonitorHotel.Instance;
            var data = em.getVandI();
            sbTemp.Clear().Append("STATUS: ").Append(data);
            writeLine(sbTemp);
        }
       
        private void chargemon()
        {
            var mb = MotherBoard.Instance;
            mb.Enable5V();
            var lhe = LheBoard.Instance;
            var inLoop = true;

            writeLine("Beginning Charge Monitor, press CTRL-C to end program...\r\n");
            while (inLoop)
            {
                //POLL BATTERIES
                if (!lhe.UpdateBatteryBank())
                {
                    EngrLogger.Comment("[Error] Polling Battery Pack\r\n");
                    Thread.Sleep(5000);
                    continue;
                }
                //LOG DATA COLUMNS IN ENGRLOGGER AND DEBUGGER
                writeLine("----------------\r\n");
                lhe.PrintBatteryData();
                //SLEEP, wait for escape
                Thread.Sleep(5000);
                //Check for keyboard interrupt
                byte input = 0;
                while (getch(ref input, true))
                    inLoop = (input != 0x03);//CTRL-C
            }
           
        }
        private void mass_storage_mode()
        {
            if (_sdStorage != null)
            {
                sbTemp.Clear().Append("Cannot enter USB Mass Storage Mode, SD Card has been initialized.\r\n");
                SendLine(sbTemp);
                return;
            }
            sbTemp.Clear().Append("Entering USB Mass Storage Mode, make sure the Mode pin is set on the bulkhead...\r\n");
            SendLine(sbTemp);
            // Start MS
            MassStorage ms = new MassStorage();
            Controller.ActiveDevice = ms;

            // Assume SD card is connected
            SDCard sd;
            Thread.Sleep(250);
            try
            {
                sd = new SDCard();
            }
            catch
            {
                throw new Exception("SD card not detected");
            }
            Thread.Sleep(250);
            ms.AttachLogicalUnit(sd, 0, " ", " ");
            Thread.Sleep(250);
            // enable host access 
            ms.EnableLogicalUnit(0);

            Thread.Sleep(Timeout.Infinite);
        }

        private void monitor_pump()
        {
            
            var emPump = EnergyMonitorPump.Instance;
            EngrLogger.Comment(emPump.getVoltsAndMilliAmps().ToString());
        }

        private void cpfChange()
        {
            if (cmdtok.Length < 2)
            {
                writeLine("usage: cpf <action> \r\n"+
                          "\t Actions: \r\n"+
                          "\t   GO: Start profiling operations\r\n"+
                          "\t   RECOVERYTRUE: Enable recovery mode\r\n"+
                          "\t   RECOVERYFALSE: Disable recovery mode\r\n"+
                          "\t   STARTDOG: Start watchdog timer\r\n"+
                          "\t   FAKEMTSBD: Send fase MTSBD using Iridium\r\n"+
                          "\t   EXIT: Halt state machine\r\n");
                return;
            }

            switch (cmdtok[1].ToLower())
            {
                case "go":
                    SV.SurfaceOpsGo = true;
                    break;
                case "recoverytrue":
                    SV.ManualProfileMode = true;
                    EngrLogger.writeToColumns("Recovery mode set true");
                    break;
                case "recoveryfalse":
                    SV.ManualProfileMode = false;
                    EngrLogger.writeToColumns("Recovery mode set false");
                    break;
                case "startdog":
                    WatchDog.startWatchdog();
                    EngrLogger.writeToColumns("Starting watchdog");
                    break;
                case "fakemtsbd":
                    NAL_A3LAR.fakeMTSBD();
                    break;
                case "exit":
                    SV.CurrentState = CPFStates.exit;
 //                   EngrLogger.CurrentState = cpfStatesArray[(int)SV.CurrentState].stateName;
                    break;
                default:
                    writeLine("ERROR: Unknown cpf action requested\r\n");
                    break;
            }

        }

        /*
        private void changeSetting()
        {
            if (cmdtok.Length < 3)
            {
                writeLine("usage: set <field> <value>\r\n");
                return;
            }

            // Parse field
            double argValue = -1;
            try
            {
                argValue = double.Parse(cmdtok[2]);
            }
            catch
            {
                writeLine("ERROR: Cannot parse setting field.\r\n");
            }

            // Field name
            switch (cmdtok[1].ToLower())
            {
                case "simp":
                    // TODO P2 do we use this?
                    break;
                case "upengr":
                    SV.UploadEngrFile = true;
                    break;
                case "maxprofiles":
                    if ((int) argValue <= 0 || (int) argValue >= 200)
                    {
                        writeLine("ERROR: Invalid profile setting\r\n");
                        return;
                    }

                    SV.MaxProfiles = (int) argValue;
                    sbTemp.Clear().Append("Setting Max Number of Profiles to: ").Append(SV.MaxProfiles);
                    EngrLogger.writeToColumns(sbTemp);
                    break;

                case "missiontimeout":
                    if ((int) argValue <= 0 || (int) argValue >= 120)
                    {
                        writeLine("ERROR: Invalid mission timeout\r\n");
                        return;
                    }

                    SV.MissionTimeoutTS = new TimeSpan(0, (int) argValue, 0, 0);
                    SV.MissionTimedOut = false;
                    sbTemp.Clear().Append("Set MissionTimeout hours to: ").Append(SV.MissionTimeoutTS);
                    EngrLogger.writeToColumns(sbTemp);
                    break;

                case "parktime":
                    if ((int) argValue <= 0 || (int) argValue >= 172800) //2*24*3600
                    {
                        writeLine("ERROR: Invalid park time\r\n");
                        return;
                    }
                    
                    Mission.descendTable[0].parkTime = new TimeSpan(0, 0, (int)argValue, 0);
                    sbTemp.Clear().Append("Park time minutes to: ");
                    sbTemp.Append(Mission.descendTable[0].parkTime);
                    EngrLogger.writeToColumns(sbTemp);
                    break;

                case "parkpressure":
                    if ((float) argValue <= 4 || (float) argValue >= 300)
                    {
                        writeLine("ERROR: Invalid park pressure\r\n");
                        return;
                    }

                    Mission.descendTable[9].pressure = (float) argValue;
                    sbTemp.Clear().Append("Setting Park Pressure to: ");
                    sbTemp.Append(Mission.descendTable[0].pressure);
                    EngrLogger.writeToColumns(sbTemp);
                    break;

                default:
                    writeLine("ERROR: Unknown field.\r\n");
                    break;
            }

        }
        */

        private void date()
        {
            if (cmdtok.Length < 7)
            {
                writeLine(DateTime.Now.ToString()+"\r\n");
                writeLine("usage: date <year> <month> <day> <hour> <minute> <second> [NUMERIC]\r\n");
                return;
            }

            int year   = int.Parse(cmdtok[1]);
            int month  = int.Parse(cmdtok[2]);
            int day    = int.Parse(cmdtok[3]);
            int hour   = int.Parse(cmdtok[4]);
            int minute = int.Parse(cmdtok[5]);
            int second = int.Parse(cmdtok[6]);

            var set_time = new DateTime(year, month, day, hour, minute, second);
            Utility.SetLocalTime(set_time);
            RealTimeClock.SetDateTime(set_time);
            EngrLogger.openNewEngFile();
        }

        private void pow()
        {
            int channel = -1;
            if (cmdtok.Length < 3)
            {
                writeLine("usage: pow <channel [1..19] [20=pump]> <on/off>\r\n");
                printPowerTable();
                for (int i = 1; i <= 19; i++)
                {
                    writeLine("CH"+i+":"+_mb.QueryChannelPower(i)+"\r\n");
                }
                return;
            }

            //channel number
            try
            {
                channel = int.Parse(cmdtok[1]);
                if (channel < 1 || channel >20)
                    throw new ArgumentOutOfRangeException();
            }
            catch
            { writeLine("Invalid channel number: "+cmdtok[1]+"\r\n"); return; }

            //state
            if (string.Equals("on", cmdtok[2]))
            {
                if (channel <= 19)
                    _mb.EnableChannelPower(channel);
                else
                    _lhe.EnablePumpPower(true);
            }
            else if (string.Equals("off", cmdtok[2]))
            {
                if (channel <= 19)
                    _mb.DisableChannelPower(channel);
                else
                    _lhe.EnablePumpPower(false);
            }

        }

        private void com()
        {
            if (cmdtok.Length < 2)
            {
                writeLine("usage: com <portnum [2-12]> <baudrate> <databits 8/7/6/5> <parity O/E/N/M/S> <stopbits 1/1.5/2/0> <close on ETX> \r\n" +
                          "\t defaults are 9600 8 N 1 1\r\n\r\n");
                return;
            }

            //Set Defaults
            int portnum = 2;
            int baud = 19200;
            int databits = 8;
            Parity parity = Parity.None;
            StopBits stopbits = StopBits.One;

            if (!ParseSerialConfig(ref portnum, ref baud, ref databits, ref parity, ref closeOnEtx)) return;

            //For traditional serialports
            if (portnum <= 6)
            {
                try
                {
                    comPort = new SerialPort("COM" + portnum.ToString(), baud, parity, databits, stopbits);
                    if (!comPort.IsOpen) comPort.Open();
                    comPort.DataReceived += ComPortOnDataReceived;
                    isI2cPort = false;

                }
                catch (Exception e)
                {
                    writeLine("Error Opening SerialPort " + portnum.ToString() + ":" + e.ToString()+"\r\n\r\n");
                    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(closeOnEtx
                ? "Serial Port Connected, press CTRL-C to exit program...\r\n\r\n"
                : "Serial Port Connected, reboot to exit...\r\n\r\n");

            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, ref bool closeOnEtx)
        {
            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;
                    case 6: // close on etx
                        try
                        {
                            int iCloseOnETX = int.Parse(cmdtok[6]);
                            if (iCloseOnETX == 1 || iCloseOnETX == 0)
                            {
                                closeOnEtx = (iCloseOnETX == 1);
                            }
                            else throw new ArgumentOutOfRangeException("0 or 1 for close on etx");
                        }
                        catch
                        {
                            writeLine("Invalid CloseOnEtx Specified, use a 0 or 1\r\n");
                            return false;
                        }
                        break;
                }
            }
            return true;
        }

        private void mkdir()
        {
            initFileSystem();
            DirectoryInfo dinfo;
            if (cmdtok.Length < 2)
            {
                writeLine("usage: mkdir <dir>\r\n\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()
        {
            initFileSystem();
            int sarg = 0;

            if (cmdtok.Length < 2)
            {
                writeLine("usage: rm <file> or rm -f <dir>\r\n");
                return;
            }

            sarg = (cmdtok[1][0] == '-') ? 1 : 0;
            bool wildcard = cmdtok[1][0] == '*';

            //change input to full path
            changeWorkingDir(ref srcdir, 1 + sarg);


            try {
                if (wildcard) //delete all files
                {
                    string[] dirbuff = Directory.GetFiles(pwDir.ToString());
                    foreach (var fname in dirbuff) {
                        writeLine("Deleting: " + fname + "\r\n");
                        try
                        {
                            File.Delete(fname);
                        }
                        catch (IOException)
                        {
                            writeLine("Cannot delete file.\r\n");
                        }
                    }
                    return;
                }
                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()
        {
            initFileSystem();
            writeLine("Beginning Zmodem Receive.\r\n");
            ZmodemReceiver zr = new ZmodemReceiver(sPort, false);

            zr.filePrefix = "\\SD\\";

            int ret = 0;
            do
            {
                ret = zr.doTasks();
            } while (ret == 0);
        }
        private void sz()
        {
            initFileSystem();
            if (cmdtok.Length < 2)
            {
                writeLine("usage sz <srcfile>\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. 
            int ret = 0;
            do
            {
                ret = zs.doTasks();
            } while (ret == 0);

            writeLine("Zmodem Finished... Result code: "+ret+"\r\n");
        }

        private void reboot()
        {
            PowerState.RebootDevice(false);
        }

        private void readStringPot()
        {
            var buoyancyEngine = BuoyancyEngine.Instance;

            _mb.EnableChannelPower(MotherBoard.ChannelNames.PositionSensorChannel);

            int bellowsVoltsRaw = buoyancyEngine.getBellowsADCValue();
            int bellowsVolts = (int)(bellowsVoltsRaw ^ 0x80000000);
            var bellowsPosition = buoyancyEngine.getBellowsPositionStringPot();
            EngrLogger.Comment("\tUnit Test Bellows Position = " +
                            bellowsPosition.ToString("f3") +
                            " Volts = "+bellowsVolts +
                            " Raw = "+bellowsVoltsRaw.ToString("X"));
        }

        private void valve()
        {
            if (cmdtok.Length < 2)
            {
                writeLine("usage valve <open/close>\r\n");
                return; 
            }

            //parse the valve instruction
            var desiredOpenState = false;
            if (string.Equals(cmdtok[1], "open"))
                desiredOpenState = true;
            else if (string.Equals(cmdtok[1], "close"))
                desiredOpenState = false;
            else
            {
                writeLine("Please enter open or close\r\n");
            }

            //power the valve
            var buoyancyEngine = BuoyancyEngine.Instance;
            _mb.EnableChannelPower(MotherBoard.ChannelNames.MotorizedValve);

            var attempts = 10;
            while (--attempts > 0 && _mb.getMVReadyStatus())
            {
                EngrLogger.Comment("MV Not Ready");
                Thread.Sleep(2000);
            }

            if (desiredOpenState)
                buoyancyEngine.openMV();
            else
                buoyancyEngine.closeMV();
            
        }

        private void pump()
        {
            if (cmdtok.Length < 2)
            {
                writeLine("usage: pump <jog velocity +/- =  inc/dec buoyancy>\r\n");
                return;
            }

            int jv;
            try
            {
                jv = int.Parse(cmdtok[1]);
            }
            catch (Exception)
            {
                writeLine("bad int value\r\nusage: pump <jog velocity +/- =  inc/dec buoyancy> \r\n");
                return;
            }

            _mb.EnableChannelPower((int)HWModules.MotherBoard.ChannelNames.PumpMotorControllerElexChannel);
            Thread.Sleep(250);
            var lheBoard = HWModules.LheBoard.Instance;
            lheBoard.EnablePumpPower(true);
            Thread.Sleep(250);

            var buoyancyEngine = BuoyancyEngine.Instance;
            Thread.Sleep(250);

            buoyancyEngine.initPumpMotor();

            if (jv == 0)
            {
                buoyancyEngine.stopMotor();
            }
            else if (jv > 0)
            {
                buoyancyEngine.increaseBuoyancy(jv);
                writeLine("Increasing buoyancy at " + jv + " bellows at " + buoyancyEngine.getBellowsPositionStringPot() + "\r\n");
            }
            else if (jv < 0)
            {
                buoyancyEngine.decreaseBuoyancy(jv);
                writeLine("Decreasing buoyancy at " + (-1 * jv) + " bellows at " + buoyancyEngine.getBellowsPositionStringPot() + "\r\n");
            }
        }

        /*
        private void ut()
        {
            if (cmdtok.Length < 2)
            {
                writeLine("usage ut <utname> <numattempts>\r\n");
                writeLine("\t available options are: \r\n" +
                          "\t\t iridium   - test iridium driver functions except for rudics\r\n" +
                          "\t\t rudics    - test iridium drivers for full rudics connections to the main server\r\n" +
                          "\t\t ctd       - test the seabird 41 drivers\r\n" +
                          "\t\t optode    - optode driver test\r\n" +
                          "\t\t ocr       - ocr driver test"+
                          "\t\t gps       - test the GPS and driver\r\n" +
                          "\t\t pump      - test the elmo driver\r\n" +
                          "\t\t bellows   - test the string pot adc\r\n" + 
                          "\t\t IncBuoy   - Increase buoyancy\r\n" +
                          "\t\t DecBuoy   - Decrease buoyancy\r\n" +
                          "\t\t pth       - test pressure temp and humid sensor\r\n" +
                          "\t\t msc       - test MBARI multi-sensor controller\r\n" +
                          "\t\t flbb      - test the flbb driver\r\n" +
                          "\t\t emonbatt  - test energy monitors on the battery\r\n" +
                          "\t\t emonpump  - test energy monitor on the pump\r\n" +
                          "\t\t valve     - test motorized valve\r\n" +
                          //"\t\t fileflood - flood the sd with files\r\n" +
                          //"\t\t surfaceops \t - test the surfaceops state\r\n" +
                          //"\t\t duallead \t - test the dual lead controller\r\n" + 
                          "\t\t watchdog  - test the watchdog\r\n");


                return;
            }

            int nattempts = 1;
            int natt;
            if (cmdtok.Length == 3)
            {
                try { natt = int.Parse(cmdtok[2]); }
                catch { 
                    writeLine("Bad Input, try again \r\n");
                    return;
                }

                if (natt > 1)
                {
                    nattempts = natt;
                }
            }

            for (int i = 0; i < nattempts; i++)
            {
                switch (DecodeUnitTest(cmdtok[1]))
                {
                    case UT.Ctd:
                        writeLine("Running Unit Test\r\n");
                        TestManager.RunTest(typeof(CTDUnitTests));
                        break;
                    case UT.Gps:
                        writeLine("Running GPS Unit Test\r\n");
                        TestManager.RunTest(typeof(UnitTest_MotherBoard_GPS));
                        break;
                    case UT.Optode:
                        writeLine("Running Optode Unit Test\r\n");
                        TestManager.RunTest(typeof(OptodeUnitTests));
                        break;
                    case UT.Pth:
                        writeLine("Running PTH Unit Test\r\n");
                        TestManager.RunTest(typeof(UnitTest_BoschPTH));
                        break;
                    case UT.Flbb:
                        writeLine("Running Flbb Unit Test\r\n");
                        TestManager.RunTest(typeof(FLBBUnitTest));
                        break;
                    case UT.Ocr:
                        writeLine("Running OCR Unit Test\r\n");
                        TestManager.RunTest(typeof(OCR504UnitTest));
                        break;
                    case UT.Pump:
                        writeLine("Running Pump Unit Test\r\n");
                        TestManager.RunTest(typeof(PumpMotorUnitTests));
                        break;
                    case UT.Elmo:
                        writeLine("Running Elmo Twitter Unit Test\r\n");
                        TestManager.RunTest(typeof(ElmoTwitterUnitTest));
                        break;
                    case UT.Watchdog:
                        //TODO P3 unimplemented
                        writeLine("Running Watchdog Unit Test\r\n");
                        break;
                    case UT.Iridium:
                        writeLine("Running Iridium Unit Test\r\n");
                        TestManager.RunTest(typeof(UnitTestIridium));
                        break;
                    case UT.Rudics:
                        writeLine("Running Rudics Unit Test\r\n");
                        TestManager.RunTest(typeof(UnitTestIridiumRUDICS));
                        break;
                    case UT.EMonBatt:
                        writeLine("Running Battery Energy Monitor Test\r\n");
                        TestManager.RunTest(typeof(UnitTest_MotherBoard_EnergyMonitor),"TestEnergyMonitorVI");
                        break;
                    case UT.EMonPump:
                        writeLine("Running Pump Energy Monitor Pump\r\n");
                        TestManager.RunTest(typeof(LheBoardUnitTests), "TestLhePumpEnergyMonitor");
                        break;
                    case UT.Msc:
                        writeLine("Running MSC Unit Test\r\n");
                        TestManager.RunTest(typeof(UnitTestMsc), "TestPHandNO3SampleT1T2");
                        break;
                    case UT.IncBuoy:
                        writeLine("Running IncreaseBuoyancy Unit Test\r\n");
                        TestManager.RunTest(typeof(PumpMotorUnitTests), "IncreaseBuoyancy");
                        break;
                    case UT.DecBuoy:
                        writeLine("Running DecreaseBuoyancy Unit Test\r\n");
                        TestManager.RunTest(typeof(PumpMotorUnitTests), "DecreaseBuoyancy");
                        break;
                    //case UT.FileFlood:
                    //    writeLine("Running FileFlood Unit Test\r\n");
                    //    TestManager.RunTest(typeof(UnitTestEngLogger), "TestManyFileCreations");
                    //    break;
                    case UT.SurfaceOps:
                        writeLine("Running SurfaceOps Unit Test\r\n");
                        TestManager.RunTest(typeof(SurfaceOpsUnitTests), "TestSurfaceOps");
                        break;
                    case UT.DualLead:
                        writeLine("Running Dual Lead Controller Unit Test\r\n");
                        TestManager.RunTest(typeof(BEUnitTests), "TestDualLeadController");
                        break;
                    case UT.MotorizedValve:
                        writeLine("Running Motorized Valve Unit Test\r\n");
                        TestManager.RunTest(typeof(MotorizedValveUnitTests));
                        break;
                    case UT.BellowsPosition:
                        writeLine("Running Bellows ADC Test\r\n");
                        TestManager.RunTest(typeof(StringPotUT));
                        break;
                    default:
                        writeLine("Unknown Unit Test \r\n");
                        break;
                }
            }

        }

        private UT DecodeUnitTest(string s)
        {
            s = s.ToLower();
            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, "elmo"))
                return UT.Elmo;
            if (string.Equals(s, "decbuoy"))
                return UT.DecBuoy;
            if (string.Equals(s, "incbuoy"))
                return UT.IncBuoy;
            if (string.Equals(s, "pth"))
                return UT.Pth;
            if (string.Equals(s, "gps"))
                return UT.Gps;
            if (string.Equals(s, "emonbatt"))
                return UT.EMonBatt;
            if (string.Equals(s, "emonpump"))
                return UT.EMonPump;
            if (string.Equals(s, "watchdog"))
                return UT.Watchdog;
            if (string.Equals(s, "msc"))
                return UT.Msc;
            if (string.Equals(s, "flbb"))
                return UT.Flbb;
            if (string.Equals(s, "ocr"))
                return UT.Ocr;
            //if (string.Equals(s, "fileflood"))
            //    return UT.FileFlood;
            if (string.Equals(s, "surfaceops"))
                return UT.SurfaceOps;
            if (string.Equals(s, "duallead"))
                return UT.DualLead;
            if (string.Equals(s, "valve"))
                return UT.MotorizedValve;
            if (string.Equals(s, "bellows"))
                return UT.BellowsPosition;
            return UT.Unknown;
        }
        */

        private void cpormv(CMD type)
        {
            initFileSystem();
            int sarg = 0;
            bool overwrite = false;
            //ok this has to have multiple inputs
            if (cmdtok.Length < 3)
            {
                writeLine("usage: cp <src> <dest>\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 breakLogs()
        {
            writeLine("Breaking all log files\r\n");
            SciLogger.closeFiles();
            EngrLogger.closeEngrLogFile();
            EngrLogger.openNewEngFile();
            SciLogger.openNewFiles();

            //writeLine("Writing blob\r\n");
            //FileSystemCheck.WriteManyBytes(int.MaxValue);
            //writeLine("Blob written\r\n");
        }
        */

        private void cd()
        {
            initFileSystem();
            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()+"\r\n");
        }

        private void dir()
        {
            initFileSystem();
            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;
            }

            Path path;
            //list files in directory
            string[] dirbuff = Directory.GetFiles(srcdir.ToString());
            
            writeLine("\r\nFiles in " + srcdir.ToString() + "\r\n");

            FileInfo fi;
            for (int i = 0; i < dirbuff.Length; i++)
            {
                fi = new FileInfo(dirbuff[i]);
                if (fi.Exists)
                {
                    if (fi.Length > 999)
                        writeLine("\t" + Path.GetFileName(dirbuff[i]) + "\t" + fi.Length/1000 + " KB\r\n");
                    else
                        writeLine("\t" + Path.GetFileName(dirbuff[i]) + "\t" + fi.Length + " B\r\n");
                }
            }

            //list directories in directory
            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");
                Debug.Print(dirbuff.Length.ToString());
            }
        }

        private void scanFiles()
        {
            initFileSystem();
            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;
            }

            String fileName = "2011-6-1T0-0-34.eng";

            StreamReader fileStream;
            String inString;
            try
            {
                fileStream = new StreamReader(fileName);
                int numLoops = 1000;
                for (int i = 0; i < numLoops; i++)
                {
                   inString = fileStream.ReadLine();
                   Debug.Print(inString);
                }
                fileStream.Close();
            }
            catch
            {
                Debug.Print("Couldn't open " + fileName);
            }




        }

        private void changeWorkingDir(ref StringBuilder sb, int offset)
        {
            initFileSystem();
            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()
        {
            initFileSystem();
            writeLine(this.pwDir.ToString() + "\r\n");
        }

        private void printHelp()
        {
            writeLine("AVAILABLE COMMANDS:\r\n");
            writeLine("HELP          - This message\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("TOUCH         - Create a file\r\n");
            writeLine("MV            - Move\r\n");
            writeLine("SZ            - Send via ZMODEM\r\n");
            writeLine("RZ            - Receive via ZMODEM\r\n");
            writeLine("REBOOT        - Hard Reboot Processor\r\n");
            writeLine("COM           - Open an native or i2c serial port\r\n");
            writeLine("                (enable power first)\r\n");
            writeLine("POW           - Switch power on available channels.\r\n");
            writeLine("CHARGEMON     - Print status of the batteries.\r\n");
            writeLine("PUMPMON       - Read out the energymonitor for the pump\r\n");
            writeLine("SLEEP         - Sleep the system for a fixed time.\r\n");
            writeLine("READSTRINGPOT - Read the position of the bellows.\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, "scan"))
                return CMD.SCAN;
            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, "com"))
                return CMD.COM;
            if (String.Equals(s, "pow"))
                return CMD.POW;
            if (String.Equals(s, "reboot"))
                return CMD.REBOOT;
            if (String.Equals(s, "date"))
                return CMD.DATE;
            if (String.Equals(s, "cpf"))
                return CMD.CPF;
            if (String.Equals(s, "sleep"))
                return CMD.SLEEP;
            if (String.Equals(s, "chargemon"))
                return CMD.CHARGEMON;
            if (string.Equals(s, "pumpmon"))
                return CMD.PUMPMON;
            if (string.Equals(s, "status"))
                return CMD.STATUS;            
            if (String.Equals(s, "readstringpot"))
                return CMD.READSTRINGPOT;
            if (String.Equals(s, "touch"))
                return CMD.TOUCH;
            if (String.Equals(s, "valve"))
                return CMD.VALVE;
            if (String.Equals(s, "pump"))
                return CMD.PUMP;
            if (String.Equals(s, "$$$"))
                return CMD.ENABLE;
            if (String.Equals(s, "exit"))
                return CMD.DISABLE;
            if (String.Equals(s, "usb"))
                return CMD.MASSSTORAGE;
            return CMD.UNKNOWN;

        }

        public void SendLine(StringBuilder builder)
        {
            writeLine(builder.ToString());
        }
    }
}
