From 9fadedc0fc43ea222b09ffdc78c56091387c3221 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Sat, 14 Apr 2018 11:16:20 +0200 Subject: [PATCH] - CS104: fixed timeout T2 problem (S message was sent before timeout elapsed) --- lib60870-C/src/iec60870/cs104/cs104_connection.c | 16 +++++++++++----- lib60870-C/src/iec60870/cs104/cs104_slave.c | 15 ++++++++++----- user_guide.adoc | 2 ++ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/lib60870-C/src/iec60870/cs104/cs104_connection.c b/lib60870-C/src/iec60870/cs104/cs104_connection.c index 5b944d7c..d09b52c5 100644 --- a/lib60870-C/src/iec60870/cs104/cs104_connection.c +++ b/lib60870-C/src/iec60870/cs104/cs104_connection.c @@ -88,9 +88,10 @@ struct sCS104_Connection { int receiveCount; int sendCount; - bool firstIMessageReceived; - int unconfirmedReceivedIMessages; + + /* timeout T2 handling */ + bool timeoutT2Trigger; uint64_t lastConfirmationTime; uint64_t nextT3Timeout; @@ -173,6 +174,9 @@ sendIMessage(CS104_Connection self, Frame frame) self->sendCount = (self->sendCount + 1) % 32768; + self->unconfirmedReceivedIMessages = false; + self->timeoutT2Trigger = false; + return self->sendCount; } @@ -258,7 +262,7 @@ resetConnection(CS104_Connection self) self->unconfirmedReceivedIMessages = 0; self->lastConfirmationTime = 0xffffffffffffffff; - self->firstIMessageReceived = false; + self->timeoutT2Trigger = false; self->oldestSentASDU = -1; self->newestSentASDU = -1; @@ -500,8 +504,8 @@ checkMessage(CS104_Connection self, uint8_t* buffer, int msgSize) { if ((buffer[2] & 1) == 0) { /* I format frame */ - if (self->firstIMessageReceived == false) { - self->firstIMessageReceived = true; + if (self->timeoutT2Trigger == false) { + self->timeoutT2Trigger = true; self->lastConfirmationTime = Hal_getTimeInMs(); /* start timeout T2 */ } @@ -619,6 +623,7 @@ handleTimeouts(CS104_Connection self) self->lastConfirmationTime = currentTime; self->unconfirmedReceivedIMessages = 0; + self->timeoutT2Trigger = false; sendSMessage(self); /* send confirmation message */ } @@ -717,6 +722,7 @@ handleConnection(void* parameter) if (self->unconfirmedReceivedIMessages >= self->parameters.w) { self->lastConfirmationTime = Hal_getTimeInMs(); self->unconfirmedReceivedIMessages = 0; + self->timeoutT2Trigger = false; sendSMessage(self); } } diff --git a/lib60870-C/src/iec60870/cs104/cs104_slave.c b/lib60870-C/src/iec60870/cs104/cs104_slave.c index 1e1a4877..d7cdcb22 100644 --- a/lib60870-C/src/iec60870/cs104/cs104_slave.c +++ b/lib60870-C/src/iec60870/cs104/cs104_slave.c @@ -951,7 +951,10 @@ struct sMasterConnection { int receiveCount; /* received messages - sequence counter */ int unconfirmedReceivedIMessages; /* number of unconfirmed messages received */ + + /* timeout T2 handling */ uint64_t lastConfirmationTime; /* timestamp when the last confirmation message (for I messages) was sent */ + bool timeoutT2Triggered; uint64_t nextT3Timeout; int outstandingTestFRConMessages; @@ -966,8 +969,6 @@ struct sMasterConnection { MessageQueue lowPrioQueue; HighPriorityASDUQueue highPrioQueue; - - bool firstIMessageReceived; }; @@ -1090,6 +1091,7 @@ sendIMessage(MasterConnection self, uint8_t* buffer, int msgSize) DEBUG_PRINT("SEND I (size = %i) N(S) = %i N(R) = %i\n", msgSize, self->sendCount, self->receiveCount); self->sendCount = (self->sendCount + 1) % 32768; self->unconfirmedReceivedIMessages = 0; + self->timeoutT2Triggered = false; } else self->isRunning = false; @@ -1487,8 +1489,8 @@ handleMessage(MasterConnection self, uint8_t* buffer, int msgSize) return false; } - if (self->firstIMessageReceived == false) { - self->firstIMessageReceived = true; + if (self->timeoutT2Triggered == false) { + self->timeoutT2Triggered = true; self->lastConfirmationTime = currentTime; /* start timeout T2 */ } @@ -1739,6 +1741,7 @@ handleTimeouts(MasterConnection self) if ((currentTime - self->lastConfirmationTime) >= (uint64_t) (self->slave->conParameters.t2 * 1000)) { self->lastConfirmationTime = currentTime; self->unconfirmedReceivedIMessages = 0; + self->timeoutT2Triggered = false; sendSMessage(self); } } @@ -1837,6 +1840,8 @@ connectionHandlingThread(void* parameter) self->unconfirmedReceivedIMessages = 0; + self->timeoutT2Triggered = false; + sendSMessage(self); } } @@ -1927,7 +1932,7 @@ MasterConnection_create(CS104_Slave slave, Socket socket, MessageQueue lowPrioQu self->unconfirmedReceivedIMessages = 0; self->lastConfirmationTime = UINT64_MAX; - self->firstIMessageReceived = false; + self->timeoutT2Triggered = false; self->maxSentASDUs = slave->conParameters.k; self->oldestSentASDU = -1; diff --git a/user_guide.adoc b/user_guide.adoc index 52fbd64e..52a58ca4 100644 --- a/user_guide.adoc +++ b/user_guide.adoc @@ -357,6 +357,8 @@ For *select before operate* the command has to be sent with the _selectCommand_ If the command has been successful the outstation will answer with an ACT_CON response message with the _negative flag_ not set. In case the outstation cannot execute the command it will also answer with an ACT_CON response but with the _negative flag_ set. You can check if this flag is set with the _CS101_ASDU_isNegative_ function used with the received _CS101_ASDU_ instance. +For a CS 104 master a command can be sent the same way by using the _CS104_Master_sendProcessCommandEx_ function. + == Slave (server) side programming