using System;
using Microsoft.SPOT;

using Microsoft.SPOT.Hardware;
using Microsoft.SPOT.IO;

using System.Threading;
using System.Text;
using System.IO;
using System.IO.Ports;

using GHI.Premium.IO;
using GHI.Premium.System;
using GHI.Premium.Hardware;
using GHI.Hardware.EMX;

//TODO List
//1) Add bellows position limit checking
//2) Add emergency ascend mode
//3) Add try/catch/finally resulting in recovery mode
//4) Add recovery mode
//5) Add bluetooth console
//6) Investigate whether we reallly need a lock for methods in the same thread
//7) Run CTD in CP mode
//8) Add serial port error received error handlers
//9) Convert ADuC voltages to engineering units
//10) Figure out a solid way to start and stop CTD, Buoyancy control, and everything else that needs stopping/starting
//11) Change state timedout functionality to force state transition, maybe use execution constraints

namespace miniCPF
{
    public class Program
    {
        //Need to make sure string descriptions of states are properly assigned to correct value every time states are changed see setStateNames() in CPFUtilities
        public enum CPFStates : int
        {
            NotRunning = 0,
            PreMissionDelay,
            Initialize,
            SurfaceOps,
            AutoballastInitBellows,
            AutoballastRetract,
            Descend,
            DescendPark,
            Anchor,
            DeAnchor,
            Ascend,
            AscendPark,
            Surface,
            EmergencyAscend,
            Recovery,
            ProcessErrors,
            Exit,
            lastState,
        }
        public static CPFStates CPFState;

        private static Timer CPFStateTimer = new Timer(new TimerCallback(CPFStateTimerCallback), null, 1000000, 1000000);

        public static bool timeSynched = false;
        private static bool telemetryDone = false;
        private static bool missionRun = true;
        private static bool stateTimedout = false;
        private static bool stateEntry = true;
        private static bool extending = false;
        private static bool retracting = false;
        private static bool runVelocityPID = false;

        public static ByteQueue MessageQueue = new ByteQueue();

        private static double PVSetPoint = 0.0;

        private static int profileDescendIndex = 0;
        private static int profileIndex = -1;

        private static Object programLock = new Object();

        private static StringBuilder sbTemp = new StringBuilder(256);
        public static StringBuilder[] sbStateNames = new StringBuilder[(int)CPFStates.lastState + 1];
        private static StringBuilder sbStateEntry = new StringBuilder("State Entry");
        private static StringBuilder sbStateExit = new StringBuilder("Normal state exit");
        private static StringBuilder sbStateTimedout = new StringBuilder("State timed out, exiting state");
        private static StringBuilder lastFileName = new StringBuilder(128);

        public static void Main()
        {
            Utility.SetLocalTime(RealTimeClock.GetTime());          //TODO Add synch to GPS
            CPFUtilities.setStateNames();
            BTConsole.OpenConsolePort();
            CPFState = CPFStates.NotRunning;
            sbTemp.Clear();
            sbTemp.Append("Program Started");
            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbTemp).ToString())); }

            Logger.init();
            SBQue.init();
            SBE41.Init();
            ADuC.Init();
            Elmo.init();

            CPFState = CPFStates.Initialize;
            CPFStateTimer.Change(configFile.initializeTimeout, 5000);

            //int speed = 20000;
            //int delay = 100000;
            //Elmo.extendBellows(speed);
            //Thread.Sleep(delay);
            //Elmo.stopMotor();

            while (missionRun)
            {
                switch (CPFState)
                {
                    case (CPFStates.PreMissionDelay):
                        if (stateEntry)
                        {
                            runVelocityPID = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateEntry).ToString())); }
                            stateEntry = false;
                        }

                        if (stateTimedout)
                        {
                            stateEntry = true;
                            stateTimedout = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateTimedout).ToString())); }
                            CPFStateTimer.Change(configFile.initializeTimeout, 5000);
                            CPFState = CPFStates.Initialize;
                        }
                        break;
                    case (CPFStates.Initialize):
                        if (stateEntry)
                        {
                            runVelocityPID = false;
                            stateEntry = false;
                            profileIndex = profileIndex + 1;
                            profileDescendIndex = 0;
                            sbConsoleCommand.Clear();
                            sbConsoleCommand.Append("NONE");
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateEntry).ToString())); }
                        }

                        if (stateTimedout)
                        {
                            stateEntry = true;
                            stateTimedout = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateTimedout).ToString())); }
                            CPFStateTimer.Change(configFile.surfaceOpsTimeout, 5000);
                            CPFState = CPFStates.SurfaceOps;
                        }
                        break;
                    case (CPFStates.SurfaceOps):
                        if (stateEntry)
                        {
                            runVelocityPID = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateEntry).ToString())); }
                            stateEntry = false;

                            //Send up the data file (if not the first profile)
                            if (profileIndex > 0)
                            {
                                lastFileName.Clear();
                                lastFileName.Append(Logger.fileName);
                                //lastFileName.Append(@"\SD\2014-3-7T14-41-43");        //just for testing

                                Logger.closeFile();
                                Logger.openFile();
                                BTConsole.uploadDataFileWhole(lastFileName);            //TODO The BTConsole might need to go in a separate thread
                            }

                            //Synch time with GPS
                            //TODO Eventually
                        }

 

                        //timeSynched = true;         //Uncomment this to skip time synch
                        // telemetryDone = true;         //Uncomment this to skip time synch
                        if ((timeSynched && telemetryDone) || (sbConsoleCommand.ToString().ToUpper() == "GO"))
                        {
                            timeSynched = false;
                            telemetryDone = false;
                            BTConsole.CloseConsolePort();
                            stateEntry = true;
                            stateTimedout = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateExit).ToString())); }
                            CPFStateTimer.Change(configFile.autoballastInitBellowsTimeout, 5000);
                            CPFState = CPFStates.AutoballastInitBellows;
                        }

                        if (stateTimedout)
                        {
                            timeSynched = false;
                            telemetryDone = false;
                            BTConsole.CloseConsolePort();
                            stateEntry = true;
                            stateTimedout = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateTimedout).ToString())); }
                            CPFStateTimer.Change(configFile.autoballastInitBellowsTimeout, 5000);
                            CPFState = CPFStates.AutoballastInitBellows;
                        }
                        break;
                    case (CPFStates.AutoballastInitBellows):
                        if (stateEntry)
                        {
                            runVelocityPID = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateEntry).ToString())); }
                            stateEntry = false;
                        }

                        //Decide what direction to go and keep checking
                        if (bellowsPosition > (configFile.ABInitBelowsPosition + 1))
                        {
                            if (!retracting)
                            {
                                Elmo.retractBellows(configFile.ABInitBelowsJV);
                                retracting = true;
                                extending = false;
                            }
                        }
                        else if (bellowsPosition < (configFile.ABInitBelowsPosition - 1))
                        {
                            if (!extending)
                            {
                                Elmo.extendBellows(configFile.ABInitBelowsJV);
                                extending = true;
                                retracting = false;
                            }
                        }
                        else  //Normal state exit criteria
                        {
                            Elmo.stopMotor();
                            retracting = false;
                            extending = false;
                            CPFStateTimer.Change(configFile.ABRetractTimeout, 5000);
                            CPFState = CPFStates.AutoballastRetract;
                            stateEntry = true;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateExit).ToString())); }
                            stateTimedout = false;
                        }

                        if (stateTimedout)
                        {
                            Elmo.stopMotor();
                            retracting = false;
                            extending = false;
                            stateEntry = true;
                            stateTimedout = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateTimedout).ToString())); }
                            CPFStateTimer.Change(configFile.ABRetractTimeout, 5000);
                            CPFState = CPFStates.AutoballastRetract;
                        }
                        break;
                    case (CPFStates.AutoballastRetract):
                        if (stateEntry)
                        {
                            runVelocityPID = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateEntry).ToString())); }
                            Elmo.retractBellows(configFile.ABRetractJV);
                            stateEntry = false;
                        }

                        //Normal state exit criteria
                        if (lpfResults.diffVel < configFile.ABVelocityThreshold)            //This should probably use LPFVel with faster LPF 
                        {
                            Elmo.stopMotor();
                            CPFStateTimer.Change(configFile.descendTimeout, 5000);
                            CPFState = CPFStates.Descend;
                            stateEntry = true;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateExit).ToString())); }
                            stateTimedout = false;
                        }

                        if (stateTimedout)
                        {
                            Elmo.stopMotor();
                            stateEntry = true;
                            stateTimedout = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateTimedout).ToString())); }
                            CPFStateTimer.Change(configFile.descendTimeout, 5000);
                            CPFState = CPFStates.Descend;
                        }
                        break;
                    case (CPFStates.Descend):
                        if (stateEntry)
                        {
                            PVSetPoint = MissionConfigFile.desiredPV[profileDescendIndex];
                            runVelocityPID = true;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateEntry).ToString())); }
                            stateEntry = false;
                        }

                        InstrumentHandler.sampleInstrumentsDepth(pressure);

                        //Normal state exit criteria
                        //A negative park depth in the mission config file means we're anchoring not descend/park cycling
                        if (MissionConfigFile.descendParkDepth[profileDescendIndex] < 0.0)
                        {
                            if (AnchorHandler.bottomDetect())         //stub for future work
                            {
                                Elmo.stopMotor();
                                profileDescendIndex = profileDescendIndex + 1;
                                stateEntry = true;
                                stateTimedout = false;
                                lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateExit).ToString())); }
                                CPFStateTimer.Change(configFile.descendParkTimeout, 5000);
                                CPFState = CPFStates.DescendPark;
                            }
                        }
                        else if (pressure > MissionConfigFile.descendParkDepth[profileDescendIndex])
                        {
                            Elmo.stopMotor();
                            profileDescendIndex = profileDescendIndex + 1;
                            stateEntry = true;
                            stateTimedout = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateExit).ToString())); }
                            CPFStateTimer.Change(configFile.descendParkTimeout, 5000);
                            CPFState = CPFStates.DescendPark;
                        }

                        if (stateTimedout)
                        {
                            Elmo.stopMotor();
                            stateEntry = true;
                            stateTimedout = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateTimedout).ToString())); }
                            CPFStateTimer.Change(configFile.descendParkTimeout, 5000);
                            CPFState = CPFStates.DescendPark;
                        }
                        break;
                    case (CPFStates.DescendPark):
                        if (stateEntry)
                        {
                            PVSetPoint = 0.0;
                            runVelocityPID = true;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateEntry).ToString())); }
                            stateEntry = false;
                        }

                        //normal state exit criteria goes here
                        //if (true)
                        //{
                        //    stateEntry = true;
                        //    stateTimedout = false;
                        //    lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateExit).ToString())); }
                        //    CPFStateTimer.Change(configFile.anchorTimeout, 5000);
                        //    CPFState = CPFStates.Anchor;
                        //}

                        if (stateTimedout)
                        {
                            stateEntry = true;
                            stateTimedout = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateTimedout).ToString())); }
                            CPFStateTimer.Change(configFile.anchorTimeout, 5000);
                            CPFState = CPFStates.Anchor;
                        }
                        break;
                    case (CPFStates.Anchor):
                        if (stateEntry)
                        {
                            runVelocityPID = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateEntry).ToString())); }
                            stateEntry = false;
                        }

                        //normal state exit criteria goes here
                        //if (true)
                        //{
                        //    stateEntry = true;
                        //    stateTimedout = false;
                        //    lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateExit).ToString())); }
                        //    CPFStateTimer.Change(configFile.deAnchorTimeout, 5000);
                        //    CPFState = CPFStates.DeAnchor;
                        //}

                        if (stateTimedout)
                        {
                            stateEntry = true;
                            stateTimedout = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateTimedout).ToString())); }
                            CPFStateTimer.Change(configFile.deAnchorTimeout, 5000);
                            CPFState = CPFStates.DeAnchor;
                        }
                        break;
                    case (CPFStates.DeAnchor):
                        if (stateEntry)
                        {
                            runVelocityPID = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateEntry).ToString())); }
                            stateEntry = false;
                        }

                        //normal state exit criteria goes here
                        //if (true)
                        //{
                        //    stateEntry = true;
                        //    stateTimedout = false;
                        //    lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateExit).ToString())); }
                        //    CPFStateTimer.Change(configFile.ascendTimeout, 5000);
                        //    CPFState = CPFStates.Ascend;
                        //}

                        if (stateTimedout)
                        {
                            stateEntry = true;
                            stateTimedout = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateTimedout).ToString())); }
                            CPFStateTimer.Change(configFile.ascendTimeout, 5000);
                            CPFState = CPFStates.Ascend;
                        }
                        break;
                    case (CPFStates.Ascend):
                        if (stateEntry)
                        {
                            runVelocityPID = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateEntry).ToString())); }
                            stateEntry = false;
                        }

                        //normal state exit criteria goes here
                        if (pressure < configFile.surfacePressure)
                        {
                            stateEntry = true;
                            stateTimedout = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateExit).ToString())); }
                            CPFStateTimer.Change(configFile.ascendParkTimeout, 5000);
                            CPFState = CPFStates.AscendPark;
                        }

                        if (stateTimedout)
                        {
                            stateEntry = true;
                            stateTimedout = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateTimedout).ToString())); }
                            CPFStateTimer.Change(configFile.ascendParkTimeout, 5000);
                            CPFState = CPFStates.AscendPark;
                        }
                        break;
                    case (CPFStates.AscendPark):
                        if (stateEntry)
                        {
                            runVelocityPID = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateEntry).ToString())); }
                            stateEntry = false;
                        }

                        //normal state exit criteria goes here
                        //if (true)
                        //{
                        //    stateEntry = true;
                        //    stateTimedout = false;
                        //    lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateExit).ToString())); }
                        //    CPFStateTimer.Change(configFile.surfaceTimeout, 5000);
                        //    CPFState = CPFStates.Surface;
                        //}

                        if (stateTimedout)
                        {
                            stateEntry = true;
                            stateTimedout = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateTimedout).ToString())); }
                            CPFStateTimer.Change(configFile.surfaceTimeout, 5000);
                            CPFState = CPFStates.Surface;
                        }
                        break;
                    case (CPFStates.Surface):
                        if (stateEntry)
                        {
                            runVelocityPID = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateEntry).ToString())); }
                            stateEntry = false;
                        }

                        //normal state exit criteria goes here
                        //if (true)
                        //{
                        //    stateEntry = true;
                        //    stateTimedout = false;
                        //    lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateExit).ToString())); }
                        //    CPFStateTimer.Change(configFile.initializeTimeout, 5000);
                        //    CPFState = CPFStates.Initialize;
                        //}

                        if (stateTimedout)
                        {
                            stateEntry = true;
                            stateTimedout = false;
                            lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateTimedout).ToString())); }
                            CPFStateTimer.Change(configFile.initializeTimeout, 5000);
                            CPFState = CPFStates.Initialize;
                        }
                        break;
                    case (CPFStates.EmergencyAscend):
                        runVelocityPID = false;
                        lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateEntry).ToString())); }
                        CPFState = CPFStates.EmergencyAscend;
                        break;
                    case (CPFStates.Recovery):
                        runVelocityPID = false;
                        lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateEntry).ToString())); }
                        CPFState = CPFStates.Recovery;
                        break;
                    case (CPFStates.ProcessErrors):
                        runVelocityPID = false;
                        lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateEntry).ToString())); }
                        break;
                    case (CPFStates.Exit):
                        runVelocityPID = false;
                        lock (programLock) { Program.MessageQueue.Enqueue(UTF8Encoding.UTF8.GetBytes(Logger.getPrefix(sbStateEntry).ToString())); }
                        missionRun = false;
                        break;
                }
                if (MessageQueue.Count > 0)
                {
                    processMessageQueue();
                }
                Thread.Sleep(100);
            }
            Logger.closeFile();
            Logger.unMount();
        }

        private static BuoyancyControl.PIDLogValues pidLogValues;

        private static byte[] dequeueMessage = new byte[256];

        private static double pressure = double.NaN;
        private static double[] ADuCVolts = new double[12];
        public static double bellowsPosition = double.NaN;
        public static double batteryBusVolts = double.NaN;

        private static SBE41.LPFResults lpfResults;

        private static StringBuilder SBE41Header = new StringBuilder("SBE41 Message");
        private static StringBuilder ADuCHeader = new StringBuilder("ADuC Message");
        private static StringBuilder velPIDHeader = new StringBuilder("Vel PID Values");
        private static StringBuilder sbPMQ = new StringBuilder(256);
        private static StringBuilder sbConsoleCommand = new StringBuilder(32);
        private static StringBuilder consoleCommandNONE = new StringBuilder("NONE");

        private static void processMessageQueue()
        {
            do
            {
                Array.Clear(dequeueMessage, 0, dequeueMessage.Length);
                lock (programLock) { dequeueMessage = Program.MessageQueue.Dequeue(); }
                if ((dequeueMessage[0] == (byte)'C') && (dequeueMessage[1] == (byte)'T') && (dequeueMessage[2] == (byte)'D'))     //TODO Probably need a more robust way to do this
                {
                    pressure = SBE41.parse(dequeueMessage);
                    lpfResults = SBE41.LPFPressure(pressure);
                    if (runVelocityPID)
                    {
                        pidLogValues = BuoyancyControl.PIDPlatformVelocity(PVSetPoint, lpfResults.LPFVel);
                        Logger.write(Logger.ColumnNums.comment, Logger.getPrefix(velPIDHeader),
                                        Logger.ColumnNums.velPID_setPoint, pidLogValues.setPoint,
                                        Logger.ColumnNums.velPID_PV, pidLogValues.PV,
                                        Logger.ColumnNums.velPID_y1, pidLogValues.y1,
                                        Logger.ColumnNums.velPID_y2, pidLogValues.y2,
                                        Logger.ColumnNums.velPID_I, pidLogValues.I,
                                        Logger.ColumnNums.velPID_v, pidLogValues.v,
                                        Logger.ColumnNums.velPID_u, pidLogValues.u,
                                        Logger.ColumnNums.velPID_uCPS, pidLogValues.uCPS);   //TODO Should do this in a way that the message is time stamped at the source
                    }
                    Logger.write(Logger.ColumnNums.comment, Logger.getPrefix(SBE41Header),
                                    Logger.ColumnNums.pressure, pressure,
                                    Logger.ColumnNums.platformLPFVel, lpfResults.LPFVel,
                                    Logger.ColumnNums.platformDiffVel, lpfResults.diffVel,
                                    Logger.ColumnNums.platformLPFAcc, lpfResults.LPFAcc);   //TODO Should do this in a way that the message is time stamped at the source
                }
                else if ((dequeueMessage[0] == (byte)'$') && (dequeueMessage[1] == (byte)'A') && (dequeueMessage[2] == (byte)'D') &&
                        (dequeueMessage[3] == (byte)'U'))
                {
                    ADuCVolts = ADuC.parseADuC(dequeueMessage);
                    bellowsPosition = ADuCVolts[0];
                    batteryBusVolts = (ADuCVolts[1] * configFile.aducCH0Scale) - configFile.aducCH0Offset;

                    Logger.write(Logger.ColumnNums.comment, Logger.getPrefix(ADuCHeader),                       //TODO Should do this in a way that the message is time stamped at the source
                                    Logger.ColumnNums.bellowsPosition, bellowsPosition, Logger.ColumnNums.batteryBusVolts, batteryBusVolts,
                                    Logger.ColumnNums.batteryBusAmps, ADuCVolts[2], Logger.ColumnNums.Amps12V, ADuCVolts[3],
                                    Logger.ColumnNums.Amps33V, ADuCVolts[4]);
                }
                else if ((dequeueMessage[0] == (byte)'C') && (dequeueMessage[1] == (byte)'O') &&        //Need to cover lower case possibilities also
                        (dequeueMessage[2] == (byte)'N'))
                {
                    processConsoleCommand(dequeueMessage);
                }
                else
                {
                    sbPMQ.Clear();
                    sbPMQ.Append(UTF8Encoding.UTF8.GetChars(dequeueMessage));
                    Logger.write(Logger.ColumnNums.comment, sbPMQ);
                }
            } while (Program.MessageQueue.Count > 0);
        }

        private static void CPFStateTimerCallback(object o)
        {
            stateTimedout = true;
        }

        private static StringBuilder consoleCommandComment = new StringBuilder();

        private static void processConsoleCommand(byte[] consoleCommandMessage)
        {
            sbConsoleCommand.Clear();
            sbConsoleCommand.Append(UTF8Encoding.UTF8.GetChars(consoleCommandMessage, 3, (Array.IndexOf(consoleCommandMessage, (byte)13) - 3)));
            
            consoleCommandComment.Clear();
            consoleCommandComment.Append("Processing Console Command: ");
            consoleCommandComment.Append(sbConsoleCommand);
            Logger.write(Logger.ColumnNums.comment, Logger.getPrefix(consoleCommandComment));
  
            switch (sbConsoleCommand.ToString().ToUpper())
            {
                case "DIR":
                    {
                        break;
                    }
                case "DOWNENGR":
                    {
                        break;
                    }
                case "DOWNMIS":
                    {
                        break;
                    }
                case "UPDATA":
                    {
                        break;
                    }
                case "UPDATAFILE":
                    {
                        break;
                    }
                case "UPENGR":
                    {
                        break;
                    }
                default:
                    {
                        break;
                    }
            }
            sbConsoleCommand.Clear();
            sbConsoleCommand.Append("NONE");
        }
    }
}

