public GarminProtoPhysicalLayer()
 {
     //base.auto = true;
     rxPacket = new RxPacket();
     TransTimeout = transactTimeout;			// (ms)
     #if DEBUG
     LibSys.StatusBar.Trace("GarminProtoPhysicalLayer() buffer=" + rxPacket.RxBuffer.Length + " timeout=" + transactTimeout);
     #endif
     Open();
 }
        private uint TransTimeout;                                              // (ms)

        public GarminProtoPhysicalLayer()
        {
            //base.auto = true;
            rxPacket     = new RxPacket();
            TransTimeout = transactTimeout;                             // (ms)
#if DEBUG
            LibSys.StatusBar.Trace("GarminProtoPhysicalLayer() buffer=" + rxPacket.RxBuffer.Length + " timeout=" + transactTimeout);
#endif
            Open();
        }
        /// <summary>
        ///  computes checksum on the Rx buffer
        /// </summary>
        /// <returns>checksum</returns>
        public byte RxChecksum(RxPacket rxPacket)
        {
            byte cs = (byte)(rxPacket.RxPacketId + rxPacket.RxDatalength);

            for (int i = 0; i < rxPacket.RxBufferP; i++)
            {
                cs += rxPacket.RxBuffer[i];
            }
            cs = (byte)(256 - cs);
            return(cs);
        }
 public void logIncoming(RxPacket rxPacket)
 {
     if (Project.gpsLogPackets)
     {
         string str = "in:   <" + pidToString(rxPacket.RxPacketId) + "> cnt=" + rxPacket.RxDatalength + " :";
         int    i;
         for (i = 0; i < rxPacket.RxBufferP && i < 100; i++)
         {
             str += " " + rxPacket.RxBuffer[i];
         }
         if (i < rxPacket.RxBufferP)
         {
             str += "...";
         }
         LibSys.StatusBar.Trace(str);
     }
 }
        // this function knows about the boundaries of the packets and receives complete packets,
        // sending ACK / NAK as needed.
        protected override void OnRxChar(byte ch)
        {
            bool prevDle = gotDle;
            gotDle = (ch == 0x10);
            uint uch = (uint)ch;

            /*
            if(gotDle || prevDle)
            {
                log("-- ch: " + ((byte)ch) + " gotDle=" + gotDle + " prevDle=" + prevDle + " p=" + rxPacket.RxBufferP + " state=" + packetState);
            }
            else
            {
                log("ch: " + ((byte)ch));
            }
            */

            switch(packetState)
            {
                case PacketState.resync:
                    //logError("resync -- ch: " + ((byte)ch));
                    resyncLostCount++;
                    if(prevDle && ch == 0x3)		// wait for opening DLE
                    {
                        logError("resync --> outside, lost " + resyncLostCount + " chars");
                        packetState = PacketState.outside;
                        resyncLostCount = 0;
                    }
                    else if(gotDle && prevCh == 0x3)
                    {
                        logError("resync --> pid, lost " + resyncLostCount + " chars");
                        packetState = PacketState.pid;
                        resyncLostCount = 0;
                    }
                    break;
                case PacketState.outside:
                    if(gotDle)		// wait for opening DLE
                    {
                        packetState = PacketState.pid;
                    }
                    else
                    {
                        if(ch != 0x3)
                        {
                            //logError("-- inbetween: " + ((byte)ch));
                        }
                        else
                        {
                            //log("-- inbetween: " + ((byte)ch));
                        }
                    }
                    break;
                case PacketState.pid:
                    if(gotDle || ch == 0x3)
                    {
                        // two DLE's is a wrong place ro resync, go on syncing:
                        packetState = PacketState.resync;
                        logError("-- two DLE's or 0x3 in pid");
                        break;
                    }
                    arxPacket = new RxPacket();
                    arxPacket.RxPacketId = ch;
                    //log("-- pid -- RxPacketId: " + arxPacket.RxPacketId);
                    packetState = PacketState.datalength;
                    break;
                case PacketState.datalength:
                    // first DLE in sequence of two is ignored:
                    if(gotDle && prevDle || !gotDle)		// DLE stuffing
                    {
                        if(prevDle && !gotDle)		// single DLE not allowed - resync
                        {
                            logError("-- datalength ch: " + ((byte)ch) + " after single DLE caused resync");
                            packetState = PacketState.resync;
                            break;
                        }
                        arxPacket.RxDatalength = (int)uch;
                        //log("-- datalength -- RxDatalength: " + arxPacket.RxDatalength);
                        packetState = PacketState.data;
                        arxPacket.RxBufferP = 0;
                        gotDle = false;	// so that prevDle won't be influenced by two legit DLE's
                    }
                    break;
                case PacketState.data:
                    // first DLE in sequence of two is ignored:
                    if(gotDle && prevDle || !gotDle)		// DLE stuffing
                    {
                        if(prevDle && !gotDle)		// single DLE not allowed - resync
                        {
                            logError("-- data ch: " + ((byte)ch) + " after single DLE caused resync");
                            packetState = PacketState.resync;
                            break;
                        }
                        arxPacket.RxBuffer[arxPacket.RxBufferP++] = ch;
                        if(arxPacket.RxBufferP >= arxPacket.RxDatalength)
                        {
                            packetState = PacketState.chksum;
                        }
                        gotDle = false;	// so that prevDle won't be influenced by two legit DLE's
                    }
                    break;
                case PacketState.chksum:
                    // first DLE in sequence of two is ignored:
                    if(gotDle && prevDle || !gotDle)		// DLE stuffing
                    {
                        if(prevDle && !gotDle)		// single DLE not allowed - resync
                        {
                            logError("-- chksum ch: " + ((byte)ch) + " after single DLE caused resync");
                            packetState = PacketState.resync;
                            break;
                        }
                        arxPacket.RxBuffer[arxPacket.RxBufferP] = ch;
                        packetState = PacketState.trailer;
                        gotDle = false;	// so that prevDle won't be influenced by two legit DLE's
                    }
                    break;
                case PacketState.trailer:
                    logIncoming(arxPacket);
                    if(arxPacket.RxPacketId != (byte)BasicPids.Pid_Ack_Byte && arxPacket.RxPacketId != (byte)BasicPids.Pid_Nak_Byte)
                    {
                        // some devices respond with two-byte ACK/NAK and do not understand standard
                        // one-byte ACK/NAK. Match our response with whatever they have sent us before:
                        byte[] rspBody = useTwoByteAck ? new byte[] { 0x0, 0x2, 0x0, 0x0 }
                                                       : new byte[] { 0x0, 0x1, 0x0 };
                        // incoming ACK/NAK are not responded to, others are:
                        byte cs = RxChecksum(arxPacket);
                        if(ch != 0x10 || cs != arxPacket.RxBuffer[arxPacket.RxBufferP])
                        {
                            logError("bad packet received (sending NAK) - ch=" + ((byte)ch) + " RxPacketId=" + arxPacket.RxPacketId + " cs=" + cs + " rec_cs=" + arxPacket.RxBuffer[arxPacket.RxBufferP]);
                            arxPacket.RxBufferP = 0;			// buffer data no good
                            // prepare to send NAK:
                            rspBody[0] = (byte)BasicPids.Pid_Nak_Byte;
                            arxPacket.RxBadPacket = true;		// signal bad packet has been received and NAK'ed
                            rspBody[2] = arxPacket.RxPacketId;
                            Send(rspBody);				// send NAK
                        }
                        else
                        {
                            //log("good packet received (sending ACK) - ch=" + ((byte)ch) + " RxPacketId=" + arxPacket.RxPacketId + " cs=" + cs);
                            // prepare to send ACK:
                            rspBody[0] = (byte)BasicPids.Pid_Ack_Byte;
                            arxPacket.RxBadPacket = false;
                            rspBody[2] = arxPacket.RxPacketId;
                            Send(rspBody);				// send ACK
                        }
                    }
                    else
                    {
                        // incoming ACK / NAK are not responded to
                        arxPacket.RxBadPacket = false;		// ACK / NAK considered good no matter what.
                        useTwoByteAck = (arxPacket.RxDatalength == 2);	// make sure we match their ACK size
                    }
                    rxPacket = arxPacket;
                    arxPacket = null;

                    gotDle = false;	// trailer is a real DLE and doesn't participate in DLE stuffing
                    resyncLostCount = 0;

                    /*
                    if (TransFlag.WaitOne(0,false))		// Transact/Receive waiting for result?
                    {
                        // we are not in Transact, let async OnRxPacket() work:
                        if(!RxBadPacket)
                        {
                            byte[] packetBody;
                            lock(RxBuffer)
                            {
                                packetBody = new Byte[RxBufferP - 1];
                                Array.Copy(RxBuffer, packetBody, (int)RxBufferP - 1);
                                RxBufferP = 0;
                            }
                            OnRxPacket(RxPacketId, packetBody);	// good unsolicited packet - call the callback function
                            // knowing that ACK or NAK has been already sent
                        }
                        else
                        {
                            RxBufferP = 0;
                            OnRxPacket(RxPacketId, null);	// bad unsolicited packet - call the callback function
                            // knowing that ACK or NAK has been already sent
                        }
                    }
                    else
                    */
                    {
                        TransFlag.Set();		// we are in Transact or Receive, let it pick the result, good or bad,
                                                // knowing that ACK or NAK has been already sent
                    }

                    packetState = PacketState.outside;	// 0x3 will be ignored in search for 0x10
                    break;
            }
            prevCh = ch;
        }
 /// <summary>
 ///  computes checksum on the Rx buffer
 /// </summary>
 /// <returns>checksum</returns>
 public byte RxChecksum(RxPacket rxPacket)
 {
     byte cs = (byte)(rxPacket.RxPacketId + rxPacket.RxDatalength);
     for(int i=0; i < rxPacket.RxBufferP ;i++)
     {
         cs += rxPacket.RxBuffer[i];
     }
     cs = (byte)(256 - cs);
     return cs;
 }
 public void logIncoming(RxPacket rxPacket)
 {
     if(Project.gpsLogPackets)
     {
         string str = "in:   <" + pidToString(rxPacket.RxPacketId) + "> cnt=" + rxPacket.RxDatalength + " :";
         int i;
         for(i=0; i < rxPacket.RxBufferP && i < 100 ;i++)
         {
             str += " " + rxPacket.RxBuffer[i];
         }
         if(i < rxPacket.RxBufferP)
         {
             str += "...";
         }
         LibSys.StatusBar.Trace(str);
     }
 }
        // this function knows about the boundaries of the packets and receives complete packets,
        // sending ACK / NAK as needed.
        protected override void OnRxChar(byte ch)
        {
            bool prevDle = gotDle;

            gotDle = (ch == 0x10);
            uint uch = (uint)ch;

            /*
             * if(gotDle || prevDle)
             * {
             *      log("-- ch: " + ((byte)ch) + " gotDle=" + gotDle + " prevDle=" + prevDle + " p=" + rxPacket.RxBufferP + " state=" + packetState);
             * }
             * else
             * {
             *      log("ch: " + ((byte)ch));
             * }
             */

            switch (packetState)
            {
            case PacketState.resync:
                //logError("resync -- ch: " + ((byte)ch));
                resyncLostCount++;
                if (prevDle && ch == 0x3)                                       // wait for opening DLE
                {
                    logError("resync --> outside, lost " + resyncLostCount + " chars");
                    packetState     = PacketState.outside;
                    resyncLostCount = 0;
                }
                else if (gotDle && prevCh == 0x3)
                {
                    logError("resync --> pid, lost " + resyncLostCount + " chars");
                    packetState     = PacketState.pid;
                    resyncLostCount = 0;
                }
                break;

            case PacketState.outside:
                if (gotDle)                                     // wait for opening DLE
                {
                    packetState = PacketState.pid;
                }
                else
                {
                    if (ch != 0x3)
                    {
                        //logError("-- inbetween: " + ((byte)ch));
                    }
                    else
                    {
                        //log("-- inbetween: " + ((byte)ch));
                    }
                }
                break;

            case PacketState.pid:
                if (gotDle || ch == 0x3)
                {
                    // two DLE's is a wrong place ro resync, go on syncing:
                    packetState = PacketState.resync;
                    logError("-- two DLE's or 0x3 in pid");
                    break;
                }
                arxPacket            = new RxPacket();
                arxPacket.RxPacketId = ch;
                //log("-- pid -- RxPacketId: " + arxPacket.RxPacketId);
                packetState = PacketState.datalength;
                break;

            case PacketState.datalength:
                // first DLE in sequence of two is ignored:
                if (gotDle && prevDle || !gotDle)                               // DLE stuffing
                {
                    if (prevDle && !gotDle)                                     // single DLE not allowed - resync
                    {
                        logError("-- datalength ch: " + ((byte)ch) + " after single DLE caused resync");
                        packetState = PacketState.resync;
                        break;
                    }
                    arxPacket.RxDatalength = (int)uch;
                    //log("-- datalength -- RxDatalength: " + arxPacket.RxDatalength);
                    packetState         = PacketState.data;
                    arxPacket.RxBufferP = 0;
                    gotDle = false;                             // so that prevDle won't be influenced by two legit DLE's
                }
                break;

            case PacketState.data:
                // first DLE in sequence of two is ignored:
                if (gotDle && prevDle || !gotDle)                               // DLE stuffing
                {
                    if (prevDle && !gotDle)                                     // single DLE not allowed - resync
                    {
                        logError("-- data ch: " + ((byte)ch) + " after single DLE caused resync");
                        packetState = PacketState.resync;
                        break;
                    }
                    arxPacket.RxBuffer[arxPacket.RxBufferP++] = ch;
                    if (arxPacket.RxBufferP >= arxPacket.RxDatalength)
                    {
                        packetState = PacketState.chksum;
                    }
                    gotDle = false;                             // so that prevDle won't be influenced by two legit DLE's
                }
                break;

            case PacketState.chksum:
                // first DLE in sequence of two is ignored:
                if (gotDle && prevDle || !gotDle)                               // DLE stuffing
                {
                    if (prevDle && !gotDle)                                     // single DLE not allowed - resync
                    {
                        logError("-- chksum ch: " + ((byte)ch) + " after single DLE caused resync");
                        packetState = PacketState.resync;
                        break;
                    }
                    arxPacket.RxBuffer[arxPacket.RxBufferP] = ch;
                    packetState = PacketState.trailer;
                    gotDle      = false;                        // so that prevDle won't be influenced by two legit DLE's
                }
                break;

            case PacketState.trailer:
                logIncoming(arxPacket);
                if (arxPacket.RxPacketId != (byte)BasicPids.Pid_Ack_Byte && arxPacket.RxPacketId != (byte)BasicPids.Pid_Nak_Byte)
                {
                    // some devices respond with two-byte ACK/NAK and do not understand standard
                    // one-byte ACK/NAK. Match our response with whatever they have sent us before:
                    byte[] rspBody = useTwoByteAck ? new byte[] { 0x0, 0x2, 0x0, 0x0 }
                                                                                                           : new byte[] { 0x0, 0x1, 0x0 };
                    // incoming ACK/NAK are not responded to, others are:
                    byte cs = RxChecksum(arxPacket);
                    if (ch != 0x10 || cs != arxPacket.RxBuffer[arxPacket.RxBufferP])
                    {
                        logError("bad packet received (sending NAK) - ch=" + ((byte)ch) + " RxPacketId=" + arxPacket.RxPacketId + " cs=" + cs + " rec_cs=" + arxPacket.RxBuffer[arxPacket.RxBufferP]);
                        arxPacket.RxBufferP = 0;                                                        // buffer data no good
                        // prepare to send NAK:
                        rspBody[0]            = (byte)BasicPids.Pid_Nak_Byte;
                        arxPacket.RxBadPacket = true;                                           // signal bad packet has been received and NAK'ed
                        rspBody[2]            = arxPacket.RxPacketId;
                        Send(rspBody);                                                          // send NAK
                    }
                    else
                    {
                        //log("good packet received (sending ACK) - ch=" + ((byte)ch) + " RxPacketId=" + arxPacket.RxPacketId + " cs=" + cs);
                        // prepare to send ACK:
                        rspBody[0]            = (byte)BasicPids.Pid_Ack_Byte;
                        arxPacket.RxBadPacket = false;
                        rspBody[2]            = arxPacket.RxPacketId;
                        Send(rspBody);                                                          // send ACK
                    }
                }
                else
                {
                    // incoming ACK / NAK are not responded to
                    arxPacket.RxBadPacket = false;                                      // ACK / NAK considered good no matter what.
                    useTwoByteAck         = (arxPacket.RxDatalength == 2);              // make sure we match their ACK size
                }
                rxPacket  = arxPacket;
                arxPacket = null;

                gotDle          = false;                // trailer is a real DLE and doesn't participate in DLE stuffing
                resyncLostCount = 0;

                /*
                 * if (TransFlag.WaitOne(0,false))		// Transact/Receive waiting for result?
                 * {
                 *      // we are not in Transact, let async OnRxPacket() work:
                 *      if(!RxBadPacket)
                 *      {
                 *              byte[] packetBody;
                 *              lock(RxBuffer)
                 *              {
                 *                      packetBody = new Byte[RxBufferP - 1];
                 *                      Array.Copy(RxBuffer, packetBody, (int)RxBufferP - 1);
                 *                      RxBufferP = 0;
                 *              }
                 *              OnRxPacket(RxPacketId, packetBody);	// good unsolicited packet - call the callback function
                 *              // knowing that ACK or NAK has been already sent
                 *      }
                 *      else
                 *      {
                 *              RxBufferP = 0;
                 *              OnRxPacket(RxPacketId, null);	// bad unsolicited packet - call the callback function
                 *              // knowing that ACK or NAK has been already sent
                 *      }
                 * }
                 * else
                 */
                {
                    TransFlag.Set();                                            // we are in Transact or Receive, let it pick the result, good or bad,
                    // knowing that ACK or NAK has been already sent
                }

                packetState = PacketState.outside;                              // 0x3 will be ignored in search for 0x10
                break;
            }
            prevCh = ch;
        }