using System;
using Microsoft.SPOT;

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

namespace HWModules
{
    // This is a Singleton instantiation of FIFOQueue class based on
    // C# in Depth, Third Edition Jon Skeet
    // http://csharpindepth.com/Articles/General/Singleton.aspx
    // "a singleton is a class which only allows a single instance of itself to be created, and usually gives simple access to that instance"
    public sealed class IridiumModem1 : NAL_A3LAR
    {
        private IridiumModem1()
            : base("IridiumModem1", "COM3", 19200, Parity.None, 8, StopBits.One, 5000, 20, false, (byte)0)
        {
            MotherBoard mb = MotherBoard.Instance;
        }

        private static IridiumModem1 instance;
        public static IridiumModem1 Instance
        {
            get
            {
                instance = instance ?? (new IridiumModem1());
                return instance;
            }
        }
    }

    public class NAL_A3LAR
    {
        public enum ReturnCodes : int
        {
            none = 0,
            CSQ,
            SBDWT,
            SBDIX,
        }

        public int returnCode;

        public NativeUART IOPort;

        private MotherBoard motherboard = MotherBoard.Instance;
        private string id; 

        private BTConsole btConsole;

        public NAL_A3LAR(string id, string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits, int readTimeout, int writeTimeout, bool useSTX, byte STX)
        {
            btConsole = BTConsole.Instance;
            id = "IModem";
            IOPort = new NativeUART(id, QRecordType.IModem ,processMessage, portName, baudRate, parity, dataBits, stopBits, readTimeout, writeTimeout, useSTX, STX);
        }

        public NAL_A3LAR()
        { }

        public void init()
        {
            if (!IOPort.IsOpen)
            {
                IOPort.Open();
                AttachDataHandler();
            }

            IOPort.DiscardInBuffer();
            IOPort.DiscardOutBuffer();

            Thread.Sleep(3000);
            sendD0();
            Thread.Sleep(1000);
            sendK0();
            Thread.Sleep(1000);
            sendSBDD2();
            Thread.Sleep(1000);
            sendGSN();
            Thread.Sleep(1000);
            sendSBDC();
            Thread.Sleep(1000);
            sendNoEcho();
            Thread.Sleep(1000);
            sendCICCID();
        }

        public void simpleInit()
        {
            if (!IOPort.IsOpen)
            {
                IOPort.Open();
                AttachDataHandler();
            }

            IOPort.DiscardInBuffer();
            IOPort.DiscardOutBuffer();
        }

        public void powerUp()
        {
            EngrLogger.writeToColumns("IModem Powering up");
            motherboard.EnableChannelPower(MotherBoard.ChannelNames.IridiumChannel);
            init();
        }

        public void powerDown()
        {
            EngrLogger.writeToColumns("IModem Powering down");
            motherboard.DisableChannelPower(MotherBoard.ChannelNames.IridiumChannel);
        }

        private static readonly StringBuilder IModemHeader = new StringBuilder("IModem Message");

        public void processMessage(QRecord qRecord)
        {

            if (qRecord.byteArray[0] == (byte)'$')
            {
                EngrLogger.Comment("Sending $ Line to BTConsole.");
                btConsole.processConsoleCommand(qRecord.byteArray); 
            }

            EngrLogger.writeToColumns(EngrLiterals.ColumnNums.dateTime, qRecord.timeStamp,
                                        EngrLiterals.ColumnNums.state, qRecord.state,
                                        EngrLiterals.ColumnNums.comment, IModemHeader,
                                        EngrLiterals.ColumnNums.IModem, qRecord.byteArray);

            //Check for expected response
            if (waitingForResponse && !gotResponse)
                checkResponse(qRecord.byteArray);
        }

        private static readonly byte[] a3laAT = Encoding.UTF8.GetBytes("AT\r");
        public int sendAT()
        {
            WriteArray(a3laAT);
            return (1);
        }
        //Reset the MOMSN (mobile origniated message sequence number
        private static readonly byte[] a3laSBDC = Encoding.UTF8.GetBytes("AT+SBDC\r");
        public int sendSBDC()
        {
            //Debug.Print(DateTime.Now + " Sending SBDC");
            WriteArray(a3laSBDC);

            return (1);
        }

        //Get the IMEI number
        private static readonly byte[] a3laGSN = Encoding.UTF8.GetBytes("AT+GSN\r");
        public int sendGSN()
        {
            //Debug.Print(DateTime.Now + " Sending GSN");
            WriteArray(a3laGSN);
            IOPort.WriteByte(13);

            return (1);
        }

        private static readonly byte[] a3laCSQ = Encoding.UTF8.GetBytes("AT+CSQ\r");
        public int sendCSQ()
        {
            //Debug.Print(DateTime.Now + " Sending CSQ");
            WriteArray(a3laCSQ);

            return (1);
        }

        private static readonly byte[] a3laD0 = Encoding.UTF8.GetBytes("AT&D0\r");
        public void sendD0()
        {
            //Debug.Print(DateTime.Now + " Sending D0");
            WriteArray(a3laD0);
        }

        private static readonly byte[] setFactoryDefault = Encoding.UTF8.GetBytes("AT&F0\r");
        public void sendFactoryDefault()
        {
            //Debug.Print(DateTime.Now + " Sending D0");
            WriteArray(setFactoryDefault);
        }

        private static readonly byte[] baEscapeSeq = Encoding.UTF8.GetBytes("+");
        public void sendEscapeSequence()
        {
            //Debug.Print(DateTime.Now + " Sending Escape Sequence");
            WriteArray(baEscapeSeq);
            Thread.Sleep(150);
            WriteArray(baEscapeSeq);
            Thread.Sleep(250);
            WriteArray(baEscapeSeq);
            
        }

        private static readonly byte[] noEcho = Encoding.UTF8.GetBytes("ATEn=0\r");
        public void sendNoEcho()
        {
            //Debug.Print(DateTime.Now + " Sending No Echo");
            WriteArray(noEcho);
        }

        private static readonly byte[] a3laK0 = Encoding.UTF8.GetBytes("AT&K0\r");
        public void sendK0()
        {
            //Debug.Print(DateTime.Now + " Sending K0");
            WriteArray(a3laK0);
        }

        private StringBuilder sbdwtMsg = new StringBuilder("EMPTY");
        public StringBuilder SBDWTMsg
        {
            get { return sbdwtMsg; }
            set { sbdwtMsg = value; }
        }
        private static readonly StringBuilder sbTemp = new StringBuilder(2000);

        private static byte[] baCR = new byte[] { 13 };
        public int loadSBDWTBuffer()
        {
            int msgLength = 0;

            if (sbdwtMsg.Length > 1910)
            {
                EngrLogger.Comment("[ERROR] SBDWT Buffer length exceeds 1910 characters");
                msgLength = 1910;
            }
            else
                msgLength = sbdwtMsg.Length;

            IOPort.Write(UTF8Encoding.UTF8.GetBytes(sbdwtMsg.ToString()), 0, msgLength);
            IOPort.Write(baCR, 0, 1);

            sbTemp.Clear();
            sbTemp.Append("IModem Loaded SBDWT Buffer with->");
            sbTemp.Append(sbdwtMsg);
            sbTemp.Append("<-");
            EngrLogger.writeToColumns(sbTemp);

            return (1);
        }

        private static readonly byte[] baSBDWT = Encoding.UTF8.GetBytes("AT+SBDWT\r");
        public void sendSBDWTCommand()
        {
            //Debug.Print(DateTime.Now + " Sending SBDWT");
            WriteArray(baSBDWT);

            sbTemp.Clear();
            sbTemp.Append("Sent SBDWT Command");
            EngrLogger.writeToColumns(sbTemp);
        }

        private void WriteArray(byte[] ba)
        {
            IOPort.Write(ba, 0, ba.Length);
        }

        private static readonly byte[] baSBDRT = Encoding.UTF8.GetBytes("AT+SBDRT\r");
        public void sendSBDRT()
        {
            //Debug.Print(DateTime.Now + " Sending SBDRT");
            WriteArray(baSBDRT);

            sbTemp.Clear();
            sbTemp.Append("IModem Sent SBDRT Command");
            EngrLogger.writeToColumns(sbTemp);
        }

        private static readonly byte[] baSBDD2 = Encoding.UTF8.GetBytes("AT+SBDD2\r");
        public int sendSBDD2()
        {
            //Debug.Print(DateTime.Now + " Sending SBDD2");
            WriteArray(baSBDD2);

            return (1);
        }

        private static readonly byte[] baSBDI = Encoding.UTF8.GetBytes("AT+SBDI\r");
        public int sendSBDI()
        {
            //Debug.Print(DateTime.Now + " Sending SBDI");
            WriteArray(baSBDI);

            return (1);
        }

        //private static readonly StringBuilder sbSBDIX = new StringBuilder("AT+SBDIX\r");
        private static readonly byte[] baSBDIX = Encoding.UTF8.GetBytes("AT+SBDIX\r");
        public void sendSBDIX()
        {
            //Debug.Print(DateTime.Now + " Sending SBDIX");
            WriteArray(baSBDIX);
    
            sbTemp.Clear();
            sbTemp.Append("IModem Sent SBDIX Command");
            EngrLogger.writeToColumns(sbTemp);
        }

        //        private static readonly StringBuilder sbCREG = new StringBuilder("AT+CREG?\r");
        private static readonly byte[] baCREG = Encoding.UTF8.GetBytes("AT+CREG?\r");
        public void sendCREG()
        {
            //Debug.Print(DateTime.Now + " Sending CREG?");
            WriteArray(baCREG);
        }

        //        private static readonly StringBuilder sbPAPUBX00 = new StringBuilder("AT+PA=A\r");
        private static readonly byte[] baPAPUBX00 = Encoding.UTF8.GetBytes("AT+PA=A\r");
        public void sendPAPUBX00()
        {
            //Debug.Print(DateTime.Now + " Sending PA=A");
            WriteArray(baPAPUBX00);
        }

        private static readonly byte[] baCMEEVerbose = Encoding.UTF8.GetBytes("AT+CMEE=2\r");
        private static readonly byte[] baCMEE = Encoding.UTF8.GetBytes("AT+CMEE\r");
        public void sendCMEE()
        {
            WriteArray(baCMEEVerbose);
            Thread.Sleep(1000);
            WriteArray(baCMEE);
        }

        private static readonly byte[] baCICCID = Encoding.UTF8.GetBytes("AT+CICCID\r");
        public void sendCICCID()
        {
            WriteArray(baCICCID);
        }

        private static readonly byte[] baCIER11 = Encoding.UTF8.GetBytes("AT+CIER=1,1\r");
        public void sendCIER11()
        {
            WriteArray(baCIER11);
        }

        //        private static readonly StringBuilder sbPAPUBX04 = new StringBuilder("AT+PA=C\r");
        private static readonly byte[] baPAPUBX04 = Encoding.UTF8.GetBytes("AT+PA=C\r");
        public void sendPAPUBX04()
        {
            //Debug.Print(DateTime.Now + " Sending PA=C");
            WriteArray(baPAPUBX04);
        }

        private static readonly byte[] baATH0 = Encoding.UTF8.GetBytes("ATH0\r");
        public void sendATH0()
        {
            WriteArray(baATH0);
        }

        private static readonly byte[] baCHUP = Encoding.UTF8.GetBytes("AT+CHUP\r");
        public void sendCHUP()
        {
            WriteArray(baCHUP);
        }

        public void parseSQ(byte[] inBytes)
        {
            int colonIndex = -1;
            //if ((inBytes[0] == 43) && (inBytes[1] == 67) && (inBytes[2] == 83) && (inBytes[3] == 81))
            //    SignalQuality = (int)inBytes[5] - 48; 

            colonIndex = Array.IndexOf(inBytes, (byte)':');
            if (colonIndex >= 0)
                SignalQuality = (int)inBytes[colonIndex + 1] - 48;
            else
                SignalQuality = -1;
        }

        private static byte LF = 10;
        private static byte[] bytesRead = new byte[2048];
        public static byte[] messageBytes = new byte[2048];
        private static int bytesToRead;
        private static int messageIndex = 0;
        //private static StructQueue.qStruct qS = new StructQueue.qStruct();

        //Singnal quality property moved from Program class to IModem class
        //in  CPF_43 this var was set to -1 on state and substate entry, and exit, but was only every recorded
        //in EngrLog - never used to evaluate or determine action.
        private static int signalQuality = -1;
        public static int SignalQuality
        {
            get { return signalQuality; }
            set { signalQuality = value; }
        }

        private static readonly byte[] baATD = Encoding.UTF8.GetBytes("ATD");
        private static readonly byte[] baATDRUDICS = Encoding.UTF8.GetBytes("atd00881600005391\r");

        public int dialNumber(byte[] baNumber)
        {

            int retval = 0;
            //input check
            if (baNumber.Length <= 0) return -1;

            //WriteArray(baATDRUDICS);
            WriteArray(baNumber);


            //check if baNumber has /r
            if (baNumber[baNumber.Length - 1] != (byte)'\r')
                IOPort.WriteByte((byte)'\r');

            return retval;
        }

        public int dialDefaultRudics()
        {
            WriteArray(baATDRUDICS);
            return 0;
        }

        public void ReleaseDataHandler()
        {
                //Debug.Print("Releasing Handler");
                IOPort.ReleaseDefaultDataHandler();
        }

        public void AttachDataHandler()
        {
                // return the serial port handler
                //Debug.Print("Attaching Handler");
                IOPort.AttachDefaultDataHandler();
        }


        private static byte[] fakeMTSBDMessage = UTF8Encoding.UTF8.GetBytes("$PARKTIME,5;$PARKPRESSURE,30;\r\n");

        public static void fakeMTSBD()
        {
            //qS.timeStamp = DateTime.Now;
            //qS.state = SV.CurrentState;

            //sbTemp.Clear();
            //sbTemp.Append(SafeEncoding.GetChars(fakeMTSBDMessage));
            ////Debug.Print(DateTime.Now + " iModem Message = " + sbTemp.ToString());

            //Array.Clear(qS.byteArray, 0, qS.byteArray.Length);
            //Array.Copy(fakeMTSBDMessage, qS.byteArray, fakeMTSBDMessage.Length);
            //qS.qRecordType = StructQueue.QRecordType.IModem;
            //Program.sQueue.Enqueue(qS);
        }

        public enum CallSpeed
        {
            AUTO = 0,
            BPS300 = 1,
            BPS1200 = 2,
            BPS2400 = 3,
            BPS4800 = 6,
            BPS9600 = 7,
            BPS300V110 = 65,
            BPS1200V110 = 66,
            BPS2400V110 = 68,
            BPS4800V110 = 70,
            BPS9600V110 = 71
        }

        public void SelectBearerServiceType(CallSpeed speed)
        {

            int iSpeed = (int)speed;
            WriteArray(Encoding.UTF8.GetBytes("AT+CBST=" + iSpeed.ToString() + ",0,1\r"));

        }

        public enum commands : int
        {
            none = 0,
            d0,
            k0,
            sbdd2,
            creg,
            csq,
            sendSBDWT,
            loadSBDWTBuffer,
            sbdi,
            sbdix,
            papubx00,
            papubx04,
            nocarrier,
            connected,
            escapeSeq,
            ath0,
            chup,
            sbdrt
        }

        public bool waitingForResponse = false;
        public static bool gotResponse = false;
        private static readonly StringBuilder d0Response = new StringBuilder("AT&D0");  //TODO P2 maybe these should all be UTF8Encoding.GetBytes on string literals
        private static readonly StringBuilder k0Response = new StringBuilder("AT&K0");
        private static readonly StringBuilder sbdd2Response = new StringBuilder("OK");
        private static readonly StringBuilder cregResponse = new StringBuilder("+CREG:");
        private static readonly StringBuilder csqResponse = new StringBuilder("+CSQ:");
        private static readonly StringBuilder sendSBDWTResponse = new StringBuilder("READY");
        private static readonly StringBuilder loadSBDWTResponse = new StringBuilder("OK");
        private static readonly StringBuilder sbdiResponse = new StringBuilder("+SBDI:");
        private static readonly StringBuilder sbdixResponse = new StringBuilder("+SBDIX:");
        private static readonly StringBuilder sbdrtResponse = new StringBuilder("+SBDRT:");
        //private static readonly StringBuilder sbdixResponse0 = new StringBuilder("+SBDIX: 0,");
        //private static readonly StringBuilder sbdixResponse1 = new StringBuilder("+SBDIX: 1,");
        //private static readonly StringBuilder sbdixResponse2 = new StringBuilder("+SBDIX: 2,");
        //private static readonly StringBuilder sbdixResponse3 = new StringBuilder("+SBDIX: 3,");
        //private static readonly StringBuilder sbdixResponse4 = new StringBuilder("+SBDIX: 4,");
        //private static readonly StringBuilder[] sbdixResponses = new StringBuilder[] { sbdixResponse0, sbdixResponse1, sbdixResponse2, sbdixResponse3, sbdixResponse4, };
        private static readonly StringBuilder papubx00Response = new StringBuilder("$PUBX,00");
        private static readonly StringBuilder papubx04Response = new StringBuilder("$PUBX,04");
        private static readonly StringBuilder noCarrierResponse = new StringBuilder("NO CARRIER");
        private static readonly StringBuilder connectedResponse = new StringBuilder("CONNECT");
        private static readonly StringBuilder okResponse = new StringBuilder("OK");
 
        public int sbdixMTQueued = -1;
        public int sbdixMTStatus = -1;          
        public int sbdixMOStatus = -1;

        //private static readonly StringBuilder expectedResponseSB = new StringBuilder(64);
        private byte[] expectedResponse = new byte[64];

        private int expectedResponseLength = 0;
        private int numRetries = 0;
        private static readonly int maxNumRetries = 3;

        private DateTime wfrStartTime = new DateTime();
        private readonly TimeSpan wfrTimeout = new TimeSpan(0, 0, 40);

        private static readonly string wfrFail = "IModem waitingForResponse expended all retries";

        private commands currentCommand = commands.none;
        
        //TODO P2 find and use OO oriented version of this method
        public int waitForResponse(commands commandNum)
        {
            if (waitingForResponse)
            //Do this after the first call to this method
            {
                if (gotResponse)
                //success
                {
                    waitingForResponse = false;
                    numRetries = 0;
                    currentCommand = commands.none;
                    return (1);
                }
                else if ((DateTime.Now - wfrStartTime) > wfrTimeout)
                //if timeout has expired, try again up to the max number of retries
                {
                    if (numRetries > maxNumRetries)
                    {
                        waitingForResponse = false;
                        numRetries = 0;
                        gotResponse = false;
                        currentCommand = commands.none;
       
                        EngrLogger.writeToColumns(wfrFail);
   
                        return (-1);
                    }
                    else
                    {
                        waitingForResponse = false;
                        return (-2);
                    }
                }
                else
                    return (0);
            }
            else
            //Do this the first time the method is called and after a timeout
            {
                currentCommand = commandNum;
                Array.Clear(expectedResponse, 0, expectedResponse.Length);
                switch (commandNum)
                {
                    case commands.d0:
                        Array.Copy(UTF8Encoding.UTF8.GetBytes(d0Response.ToString()), expectedResponse, d0Response.Length);
                        expectedResponseLength = d0Response.Length;
                        //Debug.Print(DateTime.Now.TimeOfDay.ToString() + " Sending ds command");
                        EngrLogger.writeToColumns("IModem Sending D0 cmd");
                        sendD0();
                        break;
                    case commands.k0:
                        Array.Copy(UTF8Encoding.UTF8.GetBytes(k0Response.ToString()), expectedResponse, k0Response.Length);
                        expectedResponseLength = k0Response.Length;
                        EngrLogger.writeToColumns("IModem Sending K0 cmd");
                        sendK0();
                        break;
                    case commands.sbdd2:
                        Array.Copy(UTF8Encoding.UTF8.GetBytes(sbdd2Response.ToString()), expectedResponse, sbdd2Response.Length);
                        expectedResponseLength = sbdd2Response.Length;
                        EngrLogger.writeToColumns("IModem Sending SBDD2 cmd");
                        sendSBDD2();
                        break;
                    case commands.creg:
                        Array.Copy(UTF8Encoding.UTF8.GetBytes(cregResponse.ToString()), expectedResponse, cregResponse.Length);
                        expectedResponseLength = cregResponse.Length;
                        EngrLogger.writeToColumns("IModem Sending CREG cmd");
                        sendCREG();
                        break;
                    case commands.csq:
                        Array.Copy(UTF8Encoding.UTF8.GetBytes(csqResponse.ToString()), expectedResponse, csqResponse.Length);
                        expectedResponseLength = csqResponse.Length;
                        EngrLogger.writeToColumns("IModem Sending CSQ cmd");
                        sendCSQ();
                        break;
                    case commands.sendSBDWT:
                        Array.Copy(UTF8Encoding.UTF8.GetBytes(sendSBDWTResponse.ToString()), expectedResponse, sendSBDWTResponse.Length);
                        expectedResponseLength = sendSBDWTResponse.Length;
                        EngrLogger.writeToColumns("IModem Sending SBDWT cmd");
                        sendSBDWTCommand();
                        break;
                    case commands.loadSBDWTBuffer:
                        Array.Copy(UTF8Encoding.UTF8.GetBytes(loadSBDWTResponse.ToString()), expectedResponse, loadSBDWTResponse.Length);
                        expectedResponseLength = loadSBDWTResponse.Length;
                        EngrLogger.writeToColumns("IModem Sending loadSBDWT cmd");
                        loadSBDWTBuffer();
                        break;
                    case commands.sbdi:
                        Array.Copy(UTF8Encoding.UTF8.GetBytes(sbdiResponse.ToString()), expectedResponse, sbdiResponse.Length);
                        expectedResponseLength = sbdiResponse.Length;
                        EngrLogger.writeToColumns("IModem Sending SBDI cmd");
                        sendSBDI();
                        break;
                    case commands.sbdix:
                        sbdixMTQueued = -1;
                        sbdixMOStatus = -1;
                        sbdixMTStatus = -1;
                        EngrLogger.writeToColumns("IModem Sending SBDIX cmd");
                        sendSBDIX();
                        break;
                    case commands.sbdrt:
                        Array.Copy(UTF8Encoding.UTF8.GetBytes(sbdrtResponse.ToString()), expectedResponse, sbdrtResponse.Length);
                        EngrLogger.writeToColumns("IModem Sending SBDRT cmd");
                        expectedResponseLength = sbdrtResponse.Length;
                        sendSBDRT();
                        break;
                    case commands.papubx00:
                        Array.Copy(UTF8Encoding.UTF8.GetBytes(papubx00Response.ToString()), expectedResponse, papubx00Response.Length);
                        expectedResponseLength = papubx00Response.Length;
                        EngrLogger.writeToColumns("IModem Sending PAPUBX00 cmd");
                        sendPAPUBX00();
                        break;
                    case commands.papubx04:
                        Array.Copy(UTF8Encoding.UTF8.GetBytes(papubx04Response.ToString()), expectedResponse, papubx04Response.Length);
                        expectedResponseLength = papubx04Response.Length;
                        EngrLogger.writeToColumns("IModem Sending PAPUBX04 cmd");
                        sendPAPUBX04();
                        break;
                    case commands.nocarrier:
                        Array.Copy(Encoding.UTF8.GetBytes(noCarrierResponse.ToString()), expectedResponse, noCarrierResponse.Length);
                        expectedResponseLength = noCarrierResponse.Length;
                        break;
                    case commands.ath0:
                        Array.Copy(Encoding.UTF8.GetBytes(okResponse.ToString()), expectedResponse, okResponse.Length);
                        expectedResponseLength = okResponse.Length;
                        EngrLogger.writeToColumns("IModem Sending ATH0 cmd");
                        sendATH0();
                        break;
                    case commands.chup:
                        Array.Copy(Encoding.UTF8.GetBytes(okResponse.ToString()), expectedResponse, okResponse.Length);
                        expectedResponseLength = okResponse.Length;
                        EngrLogger.writeToColumns("IModem Sending CHUP cmd");
                        sendCHUP();
                        break;
                        
                    case commands.escapeSeq:
                        Array.Copy(Encoding.UTF8.GetBytes(okResponse.ToString()), expectedResponse, okResponse.Length);
                        expectedResponseLength = okResponse.Length;
                        EngrLogger.writeToColumns("IModem Sending Escape sequence");
                        sendEscapeSequence();
                        break;
                        
                }
                wfrStartTime = DateTime.Now;
                numRetries++;
                gotResponse = false;
                waitingForResponse = true;
                return (0);
            }
        }

        private static StringBuilder sbResponse = new StringBuilder(512);
        private static StringBuilder sbExpectedResponse = new StringBuilder(512);
        private static byte[] returnField = new byte[16];
        private static byte[] returnField2 = new byte[16];
        private const byte commaByte = (byte)',';
        private const byte colonByte = (byte)':';

        /// <summary>
        /// MO status: MO session status provides an indication of the disposition of the mobile originated transaction. The field can take on the following values:
        ///    Gateway-reported values:
        ///    0 MO message, if any, transferred successfully
        ///    1 MO message, if any, transferred successfully, but the MT message in the queue
        ///    was too big to be transferred
        ///    2 MO message, if any, transferred successfully, but the requested Location Update
        ///    was not accepted
        ///    3..4 Reserved, but indicate MO session success if used 5..8 Reserved, but indicate MO session failure if used
        ///    10 GSS reported that the call did not complete in the allowed time
        ///    11 MO message queue at the GSS is full
        ///    12 MO message has too many segments
        ///    13 GSS reported that the session did not complete
        ///    14 Invalid segment size
        ///    15 Access is denied
        ///  A3LA-RG-reported values:
        ///    16 Modem has been locked and may not make SBD calls (see +CULK command)
        ///    17 Gateway not responding (local session timeout)
        ///    18 Connection lost (RF drop)
        ///    19 Link failure (A protocol error caused termination of the call)
        ///    20..31 Reserved, but indicate failure if used
        ///    32 No network service, unable to initiate call 33..34 Reserved, but indicate failure if used
        ///    35 A3LA-RG is busy, unable to initiate call 36.. Reserved, but indicate failure if used
        /// </summary>
        /// <returns></returns>
        public bool MobileOriginationSuccess()
        {
            return (sbdixMOStatus >=0 && sbdixMOStatus <= 4);
        }

        public bool MobileSuccessAndMtEmpty()
        {
            return MobileOriginationSuccess() && sbdixMTStatus <= 0;
        }

        public enum SbdixMoStat:int 
        {
            MOSuccess = 0, 
            MTInQueue = 1 
        };

        public enum SbdixMtStat : int
        {
            NoneAvailable = 0,
            SbdReceived,
            ErrorInRx = 2
        }

        public void checkResponse(byte[] response)
        {
            int msgLength = response.Length;

            //check for expectedResponse anywhere in the IModem response message
            if (waitingForResponse)
            {
                if (msgLength > expectedResponseLength)
                {
                    //start at the beginning of the qStructure byte array and test for the right character sequence
                    //then start at the 2nd character in the qStrucutre byte array and so on
                    if (currentCommand != commands.sbdix)
                    {
                        sbExpectedResponse.Clear();
                        sbExpectedResponse.Append("IModem Looking for IModem-->");
                        sbExpectedResponse.Append(SafeEncoding.GetChars(expectedResponse));
                        sbExpectedResponse.AppendLine("<--");

                        sbResponse.Clear();
                        sbResponse.Append("IModem Got-->");
                        sbResponse.Append(SafeEncoding.GetChars(response));
                        sbResponse.AppendLine("<--");

                        if (GHI.Utilities.Arrays.Contains(response, 0, expectedResponse, 0, expectedResponseLength) >= 0)
                        {
                            gotResponse = true;
                            sbTemp.Clear();
                            sbTemp.Append("IModem correct response: ");
                            sbTemp.Append(sbExpectedResponse);
                            sbTemp.Append(sbResponse);
                            EngrLogger.writeToColumns(sbTemp);
                            if (currentCommand == commands.csq)
                                parseSQ(response);
                        }
                        else
                        {
                            sbTemp.Clear();
                            sbTemp.Append("IModem invalid response: ");
                            sbTemp.Append(sbExpectedResponse);
                            sbTemp.Append(sbResponse);
                            EngrLogger.writeToColumns(sbTemp);
                        }
                    }
                    else {
                        Array.Copy(UTF8Encoding.UTF8.GetBytes(sbdixResponse.ToString()), expectedResponse, sbdixResponse.Length);
                        expectedResponseLength = sbdixResponse.Length;

                        if (GHI.Utilities.Arrays.Contains(response, 0, expectedResponse, 0, expectedResponseLength) >= 0)
                        {
                            gotResponse = true;

                            DecodeSbdixResponse(response);
                        }
                        else {
                            sbTemp.Clear();
                            sbTemp.Append("IModem got invalid SBDIX response: ");
                            sbTemp.Append(SafeEncoding.GetChars(response));
                            EngrLogger.writeToColumns(sbTemp);
                        }
                    }
                }
            }
        }

        private void DecodeSbdixResponse(byte[] response)
        {
            sbTemp.Clear();
            Array.Clear(returnField, 0, returnField.Length);
            Array.Clear(returnField2, 0, returnField2.Length);
            Utils.getField(response, commaByte, 0, ref returnField);
            Utils.getField(returnField, colonByte, 1, ref returnField2);
            sbTemp.Append(SafeEncoding.GetChars(returnField2));
            sbdixMOStatus = int.Parse(sbTemp.ToString());

            sbTemp.Clear();
            Array.Clear(returnField, 0, returnField.Length);
            Utils.getField(response, commaByte, 2, ref returnField);
            sbTemp.Append(SafeEncoding.GetChars(returnField));
            sbdixMTStatus = int.Parse(sbTemp.ToString());
            sbTemp.Clear();
            Array.Clear(returnField, 0, returnField.Length);
            Utils.getField(response, commaByte, 5, ref returnField);
            sbTemp.Append(SafeEncoding.GetChars(returnField));
            sbdixMTQueued = int.Parse(sbTemp.ToString());
            sbTemp.Clear();
            sbTemp.Append("IModem SBDIX Response: ");
            sbTemp.Append(SafeEncoding.GetChars(response));
            sbTemp.Append("   sbdixMOStatus = ");
            sbTemp.Append(sbdixMOStatus.ToString());
            sbTemp.Append("   sbdixMTStatus = ");
            sbTemp.Append(sbdixMTStatus.ToString());
            sbTemp.Append("   sbdixMTQueued = ");
            sbTemp.Append(sbdixMTQueued.ToString());
            EngrLogger.writeToColumns(sbTemp);
        }
    }
}
