/// <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(); } }