/// <summary>
        /// The thread that handles sending all messages.  
        /// </summary>
        public void SendMessageThread()
        {
            while (mSendMessageThreadActive)
            {

                if (Connected == true)
                {
                    try
                    {
                        //Get the next message if there is not a current one
                        if (mCurrentMsgToSend == null && SendMsgQueue.Count > 0)
                        {
                            lock (MsgSeqLock)
                            {
                                mCurrentMsgToSend = SendMsgQueue.Peek();
                            }
                        }
                        else if (mCurrentMsgToSend == null)
                        {
                            //Is it time to send a keep alive?
                            TimeSpan TimeSinceResponse = DateTime.Now.Subtract(mLastResponse);
                            TimeSpan TimeSinceLastMsgSent = DateTime.Now.Subtract(mLastMsgSent);

                            if ((TimeSinceResponse.TotalMilliseconds > (double)(iSleep * 1000)) && (TimeSinceLastMsgSent.TotalMilliseconds > (double)(iSleep * 1000)))
                            {
                                PFCSSendKeepAlive();
                            }

                        }

                        if (mCurrentMsgToSend != null)
                        {
                            bool blnSendItOut = false;
                            //Send it out if it hasn't been sent out before
                            if (mCurrentMsgToSend.SendInfo.LastSendTime == null) blnSendItOut = true;
                            else
                            {
                                //Send it out again if a response has been received, but it was an error
                                if (mCurrentMsgToSend.SendInfo.Response_Received == true &&
                                    mCurrentMsgToSend.SendInfo.Response_Error != MessageErrors.ERR_NAK_A)
                                {
                                    if (mCurrentMsgToSend.SendInfo.SendCount > miRetries)
                                    {
                                        lock (MsgSeqLock)
                                        {
                                            //Give up completely.
                                            //We receive 3 bad responses.  Must be something wrong with the message.
                                            SendMsgQueue.Dequeue();
                                            mCurrentMsgToSend = null;
                                        }
                                    }
                                    else blnSendItOut = true;
                                }
                                else if (mCurrentMsgToSend.SendInfo.Response_Received == true &&
                                         mCurrentMsgToSend.SendInfo.Response_Error == MessageErrors.ERR_NAK_A &&
                                         mCurrentMsgToSend.SendInfo.LastSendTime.Value.AddSeconds(miInterval) < DateTime.Now)
                                {
                                    //For some reason, for a NAK-A response we treat it as if we send it again 5 seconds later, instead of immediately.
                                    //So don't set the Response Received for a NAK-A. Let the send message thread take care of automatic resend
                                    if (mCurrentMsgToSend.SendInfo.SendCount > miRetries)
                                    {
                                        lock (MsgSeqLock)
                                        {
                                            //Give up completely.
                                            //We receive 3 bad responses.  Must be something wrong with the message.
                                            SendMsgQueue.Dequeue();
                                            mCurrentMsgToSend = null;
                                        }
                                    }
                                    else blnSendItOut = true;

                                }
                                else if (mCurrentMsgToSend.SendInfo.LastSendTime.Value.AddSeconds(miInterval) < DateTime.Now)
                                {
                                    //Send it out again if we haven't received a response yet.
                                    if (mCurrentMsgToSend.SendInfo.SendCount > miRetries)
                                    {
                                        lock (MsgSeqLock)
                                        {
                                            //Leave it on the queue, bur reset the send dates and counts
                                            mCurrentMsgToSend.SendInfo.SendCount = 0;
                                            mCurrentMsgToSend.SendInfo.FirstSendTime = null;
                                            mCurrentMsgToSend.SendInfo.LastSendTime = null;
                                            mCurrentMsgToSend.SendInfo.Response_Received = false;
                                            mCurrentMsgToSend.SendInfo.Response_Error = MessageErrors.ERR_NONE;
                                            mCurrentMsgToSend = null;
                                        }
                                        blnSendItOut = false;
                                        TCP_ErrorRecovery();

                                        //Force a keep alive to send next
                                        lock (MsgSeqLock)
                                        {
                                            SendMsg myMsg = new SendMsg();
                                            myMsg.Initialize(new MsgSendInfo(), KeepAliveMessage());
                                            mCurrentMsgToSend = myMsg;
                                        }
                                        blnSendItOut = true;
                                    }
                                    else
                                    {
                                        blnSendItOut = true;
                                    }
                                }
                            }

                            //Send the message
                            if (blnSendItOut == true && mCurrentMsgToSend != null)
                            {
                                //Set the sequence number if its the first time sending the message
                                // But don't set the sequence number for an ACK/NAK
                                if (mCurrentMsgToSend.SendInfo.SendCount == 0)
                                {
                                    if (mCurrentMsgToSend.MsgToSend.ResponseType == MessageResponseType.DataMessage)
                                    {
                                        if (mCurrentMsgToSend.MsgToSend.MsgType != MessageType.KeepAlive)
                                        {
                                            GetNextSeqNum();
                                        }
                                        lock (MsgSeqLock)
                                        {
                                            mCurrentMsgToSend.MsgToSend.SequenceNum = LastMsgSeqNum;
                                        }
                                    }
                                }

                                //Update the send information, such as date/time,send count and set response received to false
                                DateTime TimeSent = DateTime.Now;
                                lock (MsgSeqLock)
                                {
                                    mCurrentMsgToSend.SendInfo.LastSendTime = TimeSent;
                                    if (mCurrentMsgToSend.SendInfo.FirstSendTime == null) mCurrentMsgToSend.SendInfo.FirstSendTime = TimeSent;
                                    mCurrentMsgToSend.SendInfo.SendCount++;
                                    mCurrentMsgToSend.SendInfo.Response_Received = false;
                                    mCurrentMsgToSend.SendInfo.Response_Error = MessageErrors.ERR_NONE;
                                }
                                mLastMsgSent = DateTime.Now;

                                Send(mCurrentMsgToSend.MsgToSend.ToByteArray());

                                if (MessageSent != null) MessageSent(this, new MessageReceivedEventArgs(mCurrentMsgToSend.MsgToSend));
                                if (mCurrentMsgToSend != null)
                                {
                                    if (mCurrentMsgToSend.MsgToSend.ResponseType == MessageResponseType.ACK ||
                                       mCurrentMsgToSend.MsgToSend.ResponseType == MessageResponseType.NAK)
                                        lock (MsgSeqLock)
                                        {
                                            if (SendMsgQueue.Count > 0 && mCurrentMsgToSend == SendMsgQueue.Peek()) RemoveFromQueue();
                                            mCurrentMsgToSend = null; //don't wait for a response or resend an ACK or NAK.  just remove it from the queue
                                        }
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        if (StateChanged != null) StateChanged(this, new StateChangeEventArgs(StateChange.ErrorHappened, ex.ToString()));
                        TCP_ErrorRecovery();
                    }
                }
                else //not connected
                {
                    if (!Connected && PortType == PORT_TYPE.Soliciated && mBuffering == false)
                    {
                        SendMsgQueue.Clear();
                        if (mCurrentMsgToSend != null)
                        {
                            if (mCurrentMsgToSend.MsgToSend.MsgType == MessageType.SendingTestResults) mCurrentMsgToSend = null;
                        }
                    }
                }

                Thread.Sleep(100);
            }
        }
        private void CheckConnectionThread()
        {
            bool lastConnectState = false;
            DateTime lastConnectionTry;
            DateTime.TryParse("1/1/2000", out lastConnectionTry);

            while (mConnectionThreadActive)
            {
                try
                {
                    //Raise connected event if connected state changed.  Need to check before and after the connection section to make sure event gets raised.
                    if (lastConnectState != Connected)
                    {
                        lastConnectState = Connected;
                        DateTime.TryParse("1/1/2000", out mLastResponse);
                        DateTime.TryParse("1/1/2000", out mLastMsgSent);
                        if (lastConnectState == true)
                        {
                            mLastResponse = DateTime.Now;
                            lastConnectionTry = DateTime.Now;
                            if (mCurrentMsgToSend == null)
                            {
                                //Force a keep alive to send next
                                lock (MsgSeqLock)
                                {
                                    SendMsg myMsg = new SendMsg();
                                    myMsg.Initialize(new MsgSendInfo(), KeepAliveMessage());
                                    mCurrentMsgToSend = myMsg;
                                }
                            }
                            if (StateChanged != null) StateChanged(this, new StateChangeEventArgs(StateChange.Connected, "Connected"));
                        }
                        else
                        {
                            if (StateChanged != null) StateChanged(this, new StateChangeEventArgs(StateChange.Disconnected, "Disconnected"));

                            //Clear the send dates and counts for the current message
                            lock (CurrMsgLock)
                            {
                                if (mCurrentMsgToSend != null)
                                {
                                    mCurrentMsgToSend.SendInfo.SendCount = 0;
                                    mCurrentMsgToSend.SendInfo.FirstSendTime = null;
                                    mCurrentMsgToSend.SendInfo.LastSendTime = null;
                                    mCurrentMsgToSend.SendInfo.Response_Received = false;
                                    mCurrentMsgToSend.SendInfo.Response_Error = MessageErrors.ERR_NONE;
                                }
                            }
                        }
                    }

                    TimeSpan ts_LastConnectionTry = DateTime.Now - lastConnectionTry;
                    TimeSpan ts_LastResponse = DateTime.Now - mLastResponse;
                    if (!Connected && mblnOKToConnect)
                    {
                        if (ts_LastConnectionTry.TotalMilliseconds > miConnect * 1000)
                        {
                            if (StateChanged != null) StateChanged(this, new StateChangeEventArgs(StateChange.TryingToConnect, "Trying to connect..."));
                            base.Connect();
                            lastConnectionTry = DateTime.Now;
                        }
                    }
                    else if (ts_LastResponse.TotalMilliseconds > miSleep * 1000 * 2)
                    {
                        if (StateChanged != null) StateChanged(this, new StateChangeEventArgs(StateChange.Disconnecting, "Disconnecting..."));
                        base.Disconnect();
                        ClearBuffers();
                    }
                    else if (mblnOKToConnect == false)
                    {
                        if (StateChanged != null) StateChanged(this, new StateChangeEventArgs(StateChange.Disconnecting, "Disconnecting..."));
                        base.Disconnect();
                        ClearBuffers();
                    }

                    //Raise connected event if connected state changed.  Need to check before and after the connection section to make sure event gets raised.
                    if (lastConnectState != Connected)
                    {
                        lastConnectState = Connected;
                        DateTime.TryParse("1/1/2000", out mLastMsgSent);
                        DateTime.TryParse("1/1/2000", out mLastResponse);
                        if (lastConnectState == true)
                        {
                            mLastResponse = DateTime.Now;
                            lastConnectionTry = DateTime.Now;
                            if (mCurrentMsgToSend == null)
                            {
                                //Force a keep alive to send next
                                lock (MsgSeqLock)
                                {
                                    SendMsg myMsg = new SendMsg();
                                    myMsg.Initialize(new MsgSendInfo(), KeepAliveMessage());
                                    mCurrentMsgToSend = myMsg;
                                }
                            }

                            if (StateChanged != null) StateChanged(this, new StateChangeEventArgs(StateChange.Connected, "Connected"));
                        }
                        else
                        {
                            if (StateChanged != null) StateChanged(this, new StateChangeEventArgs(StateChange.Disconnected, "Disconnected"));

                            //Clear the send dates and counts for the current message
                            lock (CurrMsgLock)
                            {
                                if (mCurrentMsgToSend != null)
                                {
                                    mCurrentMsgToSend.SendInfo.SendCount = 0;
                                    mCurrentMsgToSend.SendInfo.FirstSendTime = null;
                                    mCurrentMsgToSend.SendInfo.LastSendTime = null;
                                    mCurrentMsgToSend.SendInfo.Response_Received = false;
                                    mCurrentMsgToSend.SendInfo.Response_Error = MessageErrors.ERR_NONE;
                                }
                            }
                        }
                    }

                    Thread.Sleep(1000);
                }
                catch(Exception ex)
                {
                    if (mConnectionThreadActive == true) if (StateChanged != null) StateChanged(this, new StateChangeEventArgs(StateChange.ErrorHappened, ex.ToString()));
                }
            }
        }
        public void Send(Message_Upload msg)
        {
            //add it to the queue to send and let the send message thread take care of it.
            lock (MsgSeqLock)
            {
                //Get rid of any data on the queue that is older than one hour
                while (SendMsgQueue.Count > 0 && SendMsgQueue.Peek().MsgToSend.Age > 60000 * 60)
                {
                    RemoveFromQueue();
                }

                //queue it up.
                SendMsg myMsg = new SendMsg();
                myMsg.Initialize(new MsgSendInfo(), msg);
                SendMsgQueue.Enqueue(myMsg);

                //Save it to a file, in case of power loss or program shuts down.
                SerializeQueueToXML();

            }
        }