public void Transact(byte[] packetBodyOut, GPacketReceived packetIn)
        {
            //log("Transact --------------------------- started");
            int tries = 0;
            while(tries++ <= 3)
            {
                if(tries > 1)
                {
                    logError("Transact - try " + tries);
                }
                Send(packetBodyOut);
                TransFlag.Reset();
                if (!TransFlag.WaitOne((int)TransTimeout, false))
                {
                    logError("Transact - Timeout waiting for ACK");
                    if(tries == 3)
                    {
                        ThrowException("Timeout - check GPS cable and baud rate");
                    }
                    else
                    {
                        // just send the packet again
                        continue;
                    }
                }

                // analyze response, hopefully should be ACK (for our Send()):
                if(rxPacket.RxPacketId != (int)BasicPids.Pid_Nak_Byte)
                {
                    // if this is ACK, wait for the real packet to come.
                    // if not, assume we received the response packet
                    if(rxPacket.RxPacketId == (int)BasicPids.Pid_Ack_Byte)
                    {
                        //log("Transact - got ACK");
                        // receive actual response:
                        TransFlag.Reset();
                        if (!TransFlag.WaitOne((int)TransTimeout, false))
                        {
                            logError("Transact - Timeout");
                            if(tries == 3)
                            {
                                ThrowException("Timeout - check GPS cable and baud rate");
                            }
                            else
                            {
                                // just send the packet again
                                continue;
                            }
                        }
                    }
                    if(rxPacket.RxBadPacket)
                    {
                        logError("Transact - received bad packet - pid=" + rxPacket.RxPacketId);
                        continue;
                    }
                    else
                    {
                        //log("Transact - received good packet - pid=" + rxPacket.RxPacketId);
                        lock(rxPacket)
                        {
                            packetIn.isGood = !rxPacket.RxBadPacket;
                            packetIn.size = (int)rxPacket.RxBufferP;
                            packetIn.pid = rxPacket.RxPacketId;
                            packetIn.bytes = new byte[packetIn.size];
                            Array.Copy(rxPacket.RxBuffer, packetIn.bytes, packetIn.size);
                        }
                        rxPacket.Dispose();
                        break;
                    }
                }
                else // NAK
                {
                    // just send the packet again
                    logError("Transact - got NAK for my packet (id=" + pidToString(packetBodyOut[0]) + ")");
                    continue;
                }
                /*
                else
                {
                    RxBufferP = 0;
                    logError("Transact - expected ACK for my packet (id=" + packetBodyOut[0] + ") -- came RxPacketId=" + RxPacketId);
                    // may be we missed ACK, instead next packet came.
                }
                */
            }
            //log("Transact --------------------------- finished");
        }
        public void Receive(GPacketReceived packetIn)
        {
            //log("Receive() - waiting...");
            TransFlag.Reset();
            if (!TransFlag.WaitOne((int)TransTimeout, false))
            {
                string str = "Timeout: receive state=" + packetState;
                if(arxPacket != null)
                {
                    byte packetId = arxPacket.RxBuffer[0];
                    // packet body structure: byte[] { pid, count, ...data... }
                    string hdr = arxPacket.RxBufferP > 0 ? ("<" + pidToString(packetId) + ">") : "";
                    str += "  received so far: " + hdr + " RxBufferP=" + arxPacket.RxBufferP + " :";
                    for(int i=1; i < arxPacket.RxBufferP && i < 20 ;i++)
                    {
                        str += " " + arxPacket.RxBuffer[i];
                    }
                }
                logError(str);

                ThrowException("Timeout - check GPS cable and baud rate");
            }
            lock(rxPacket)
            {
                packetIn.isGood = !rxPacket.RxBadPacket;
                packetIn.pid = rxPacket.RxPacketId;
                packetIn.size = (int)rxPacket.RxBufferP;
                packetIn.bytes = new byte[packetIn.size];
                Array.Copy(rxPacket.RxBuffer, packetIn.bytes, packetIn.size);
            }
            rxPacket.Dispose();
            //log("Receive() - received good packet - pid=" + packetIn.pid);
        }