From 1ee4377e618d40e1edd232a3ed8d100585345011 Mon Sep 17 00:00:00 2001 From: Mike Pieper Date: Sat, 22 Jan 2022 08:56:51 +0100 Subject: [PATCH 1/4] tx throttle. --- src/knx/tpuart_data_link_layer.cpp | 17 +++++++++++++---- src/knx/tpuart_data_link_layer.h | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/knx/tpuart_data_link_layer.cpp b/src/knx/tpuart_data_link_layer.cpp index 96f41f7..7ffb7ec 100644 --- a/src/knx/tpuart_data_link_layer.cpp +++ b/src/knx/tpuart_data_link_layer.cpp @@ -96,6 +96,7 @@ enum { #define EOP_TIMEOUT 2 //milli seconds; end of layer-2 packet gap #define CONFIRM_TIMEOUT 500 //milli seconds #define RESET_TIMEOUT 100 //milli seconds +#define TX_THROTTLE_TIME 1 //milli seconds void TpUartDataLinkLayer::loop() { @@ -295,6 +296,7 @@ void TpUartDataLinkLayer::loop() } // Hint: We can send directly here, this doesn't disturb other transmissions + // We don't have to update _lastByteTxTime because after ACK the timing is not so tight _platform.writeUart(c); } } @@ -377,13 +379,20 @@ void TpUartDataLinkLayer::loop() } break; case TX_FRAME: - if (sendSingleFrameByte() == false) + if (millis() - _lastByteTxTime >= TX_THROTTLE_TIME) { - _waitConfirmStartTime = millis(); - _txState = TX_WAIT_ECHO; + if (sendSingleFrameByte() == false) + { + _waitConfirmStartTime = millis(); + _txState = TX_WAIT_ECHO; #ifdef DBG_TRACE - println("TX_WAIT_ECHO"); + println("TX_WAIT_ECHO"); #endif + } + else + { + _lastByteTxTime = millis(); + } } break; case TX_WAIT_ECHO: diff --git a/src/knx/tpuart_data_link_layer.h b/src/knx/tpuart_data_link_layer.h index 35305f3..fd51c2a 100644 --- a/src/knx/tpuart_data_link_layer.h +++ b/src/knx/tpuart_data_link_layer.h @@ -43,6 +43,7 @@ class TpUartDataLinkLayer : public DataLinkLayer bool _convert = false; uint8_t _xorSum = 0; uint32_t _lastByteRxTime; + uint32_t _lastByteTxTime; uint32_t _waitConfirmStartTime; uint32_t _lastResetChipTime = 0; From 7d7e6eb3b474faa9d691c6aa7859c5390648e926 Mon Sep 17 00:00:00 2001 From: Mike Pieper Date: Sat, 22 Jan 2022 10:19:01 +0100 Subject: [PATCH 2/4] New state RX_L_ADDR; loop load adaption --- src/knx/tpuart_data_link_layer.cpp | 78 +++++++++++++++++++++--------- src/knx/tpuart_data_link_layer.h | 1 + 2 files changed, 57 insertions(+), 22 deletions(-) diff --git a/src/knx/tpuart_data_link_layer.cpp b/src/knx/tpuart_data_link_layer.cpp index 7ffb7ec..968036c 100644 --- a/src/knx/tpuart_data_link_layer.cpp +++ b/src/knx/tpuart_data_link_layer.cpp @@ -89,18 +89,23 @@ enum { //rx states enum { RX_WAIT_START, + RX_L_ADDR, RX_L_DATA, RX_WAIT_EOP }; #define EOP_TIMEOUT 2 //milli seconds; end of layer-2 packet gap +#define EOPR_TIMEOUT 8 //ms; relaxed EOP timeout; usally to trigger after NAK #define CONFIRM_TIMEOUT 500 //milli seconds #define RESET_TIMEOUT 100 //milli seconds -#define TX_THROTTLE_TIME 1 //milli seconds +#define TX_TIMEPAUSE 0 // 0 means 1 milli seconds + +// If this threshold is reached loop() goes into +// "hog mode" where it stays in loop() while L2 address reception +#define HOGMODE_THRESHOLD 3 // milli seconds void TpUartDataLinkLayer::loop() { - if (!_enabled) { if (millis() - _lastResetChipTime > 1000) @@ -117,12 +122,29 @@ void TpUartDataLinkLayer::loop() // Signals to communicate from rx part with the tx part bool isEchoComplete = false; // Flag that a complete echo is received uint8_t dataConnMsg = 0; // The DATA_CONN message just seen or 0 + +#ifdef KNX_WAIT_FOR_ADDR + // After seeing a L2 packet start, stay in loop until address bytes are + // received and the AK/NAK packet is sent + bool stayInRx = true; +#elif defined(KNX_AUTO_ADAPT) + // After seeing a L2 packet start, stay in loop until address bytes are + // received and the AK/NAK packet is sent, when last loop call delayed + // by more than HOGMODE_THRESHOLD + bool stayInRx = millis() - _lastLoopTime > HOGMODE_THRESHOLD; + _lastLoopTime = millis(); +#else + // After seeing a L2 packet start, leave loop and hope the loop + // is called early enough to do further processings + bool stayInRx = false; +#endif + + // Loop as long we are in the receive phase for the L2 address do { _receiveBuffer[0] = 0x29; _receiveBuffer[1] = 0; uint8_t* buffer = _receiveBuffer + 2; uint8_t rxByte; - bool isEOP = (millis() - _lastByteRxTime > EOP_TIMEOUT); // Flag that an EOP gap is seen switch (_rxState) { case RX_WAIT_START: @@ -143,7 +165,7 @@ void TpUartDataLinkLayer::loop() _xorSum ^= rxByte; _RxByteCnt++; //convert to L_DATA_EXTENDED _convert = true; - _rxState = RX_L_DATA; + _rxState = RX_L_ADDR; #ifdef DBG_TRACE println("RLS"); #endif @@ -154,7 +176,7 @@ void TpUartDataLinkLayer::loop() buffer[_RxByteCnt++] = rxByte; _xorSum ^= rxByte; _convert = false; - _rxState = RX_L_DATA; + _rxState = RX_L_ADDR; #ifdef DBG_TRACE println("RLX"); #endif @@ -232,11 +254,11 @@ void TpUartDataLinkLayer::loop() } } break; - case RX_L_DATA: - if (isEOP) + case RX_L_ADDR: + if (millis() - _lastByteRxTime > EOPR_TIMEOUT) { _rxState = RX_WAIT_START; - print("EOP inside RX_L_DATA"); + print("EOPR inside RX_L_ADDR"); printHex(" => ", buffer, _RxByteCnt); break; } @@ -247,20 +269,12 @@ void TpUartDataLinkLayer::loop() #ifdef DBG_TRACE print(rxByte, HEX); #endif - if (_RxByteCnt == MAX_KNX_TELEGRAM_SIZE) - { - _rxState = RX_WAIT_EOP; - println("invalid telegram size"); - } - else - { - buffer[_RxByteCnt++] = rxByte; - } + buffer[_RxByteCnt++] = rxByte; + _xorSum ^= rxByte; if (_RxByteCnt == 7) { //Destination Address + payload available - _xorSum ^= rxByte; //check if echo if (_sendBuffer != nullptr && (!((buffer[0] ^ _sendBuffer[0]) & ~0x20) && !memcmp(buffer + _convert + 1, _sendBuffer + 1, 5))) { //ignore repeated bit of control byte @@ -299,8 +313,28 @@ void TpUartDataLinkLayer::loop() // We don't have to update _lastByteTxTime because after ACK the timing is not so tight _platform.writeUart(c); } + _rxState = RX_L_DATA; } - else if (_RxByteCnt == buffer[6] + 7 + 2) + break; + case RX_L_DATA: + if (!_platform.uartAvailable()) + break; + _lastByteRxTime = millis(); + rxByte = _platform.readUart(); +#ifdef DBG_TRACE + print(rxByte, HEX); +#endif + if (_RxByteCnt == MAX_KNX_TELEGRAM_SIZE) + { + _rxState = RX_WAIT_EOP; + println("invalid telegram size"); + } + else + { + buffer[_RxByteCnt++] = rxByte; + } + + if (_RxByteCnt == buffer[6] + 7 + 2) { //complete Frame received, payloadLength+1 for TCPI +1 for CRC if (rxByte == (uint8_t)(~_xorSum)) @@ -339,7 +373,7 @@ void TpUartDataLinkLayer::loop() } break; case RX_WAIT_EOP: - if (isEOP) + if (millis() - _lastByteRxTime > EOP_TIMEOUT) { _RxByteCnt = 0; _rxState = RX_WAIT_START; @@ -359,7 +393,7 @@ void TpUartDataLinkLayer::loop() default: break; } - } while (_rxState == RX_L_DATA); + } while (_rxState == RX_L_ADDR && (stayInRx || _platform.uartAvailable())); // Check for spurios DATA_CONN message if (dataConnMsg && _txState != TX_WAIT_CONN && _txState != TX_WAIT_ECHO) { @@ -379,7 +413,7 @@ void TpUartDataLinkLayer::loop() } break; case TX_FRAME: - if (millis() - _lastByteTxTime >= TX_THROTTLE_TIME) + if (millis() - _lastByteTxTime > TX_TIMEPAUSE) { if (sendSingleFrameByte() == false) { diff --git a/src/knx/tpuart_data_link_layer.h b/src/knx/tpuart_data_link_layer.h index fd51c2a..5e78662 100644 --- a/src/knx/tpuart_data_link_layer.h +++ b/src/knx/tpuart_data_link_layer.h @@ -44,6 +44,7 @@ class TpUartDataLinkLayer : public DataLinkLayer uint8_t _xorSum = 0; uint32_t _lastByteRxTime; uint32_t _lastByteTxTime; + uint32_t _lastLoopTime; uint32_t _waitConfirmStartTime; uint32_t _lastResetChipTime = 0; From c908d5dc0a816ca77bfa27d402d26c37d5e5b88a Mon Sep 17 00:00:00 2001 From: Mike Pieper Date: Tue, 25 Jan 2022 06:08:58 +0100 Subject: [PATCH 3/4] handle all available bytes --- src/knx/tpuart_data_link_layer.cpp | 631 +++++++++++++++-------------- 1 file changed, 317 insertions(+), 314 deletions(-) diff --git a/src/knx/tpuart_data_link_layer.cpp b/src/knx/tpuart_data_link_layer.cpp index 968036c..cb37311 100644 --- a/src/knx/tpuart_data_link_layer.cpp +++ b/src/knx/tpuart_data_link_layer.cpp @@ -119,355 +119,358 @@ void TpUartDataLinkLayer::loop() if (!_enabled) return; - // Signals to communicate from rx part with the tx part - bool isEchoComplete = false; // Flag that a complete echo is received - uint8_t dataConnMsg = 0; // The DATA_CONN message just seen or 0 + // Loop once and repeat as long we have rx data available + do { + // Signals to communicate from rx part with the tx part + bool isEchoComplete = false; // Flag that a complete echo is received + uint8_t dataConnMsg = 0; // The DATA_CONN message just seen or 0 #ifdef KNX_WAIT_FOR_ADDR - // After seeing a L2 packet start, stay in loop until address bytes are - // received and the AK/NAK packet is sent - bool stayInRx = true; + // After seeing a L2 packet start, stay in loop until address bytes are + // received and the AK/NAK packet is sent + bool stayInRx = true; #elif defined(KNX_AUTO_ADAPT) - // After seeing a L2 packet start, stay in loop until address bytes are - // received and the AK/NAK packet is sent, when last loop call delayed - // by more than HOGMODE_THRESHOLD - bool stayInRx = millis() - _lastLoopTime > HOGMODE_THRESHOLD; - _lastLoopTime = millis(); + // After seeing a L2 packet start, stay in loop until address bytes are + // received and the AK/NAK packet is sent, when last loop call delayed + // by more than HOGMODE_THRESHOLD + bool stayInRx = millis() - _lastLoopTime > HOGMODE_THRESHOLD; + _lastLoopTime = millis(); #else - // After seeing a L2 packet start, leave loop and hope the loop - // is called early enough to do further processings - bool stayInRx = false; + // After seeing a L2 packet start, leave loop and hope the loop + // is called early enough to do further processings + bool stayInRx = false; #endif - // Loop as long we are in the receive phase for the L2 address - do { - _receiveBuffer[0] = 0x29; - _receiveBuffer[1] = 0; - uint8_t* buffer = _receiveBuffer + 2; - uint8_t rxByte; - switch (_rxState) - { - case RX_WAIT_START: - if (_platform.uartAvailable()) - { + // Loop once and repeat as long we are in the receive phase for the L2 address + do { + uint8_t* buffer = _receiveBuffer + 2; + uint8_t rxByte; + switch (_rxState) + { + case RX_WAIT_START: + if (_platform.uartAvailable()) + { + rxByte = _platform.readUart(); +#ifdef DBG_TRACE + print(rxByte, HEX); +#endif + _lastByteRxTime = millis(); + + // Check for layer-2 packets + _RxByteCnt = 0; + _xorSum = 0; + if ((rxByte & L_DATA_MASK) == L_DATA_STANDARD_IND) + { + buffer[_RxByteCnt++] = rxByte; + _xorSum ^= rxByte; + _RxByteCnt++; //convert to L_DATA_EXTENDED + _convert = true; + _rxState = RX_L_ADDR; +#ifdef DBG_TRACE + println("RLS"); +#endif + break; + } + else if ((rxByte & L_DATA_MASK) == L_DATA_EXTENDED_IND) + { + buffer[_RxByteCnt++] = rxByte; + _xorSum ^= rxByte; + _convert = false; + _rxState = RX_L_ADDR; +#ifdef DBG_TRACE + println("RLX"); +#endif + break; + } + + // Handle all single byte packets here + else if ((rxByte & L_DATA_CON_MASK) == L_DATA_CON) + { + dataConnMsg = rxByte; + } + else if (rxByte == L_POLL_DATA_IND) + { + // not sure if this can happen + println("got L_POLL_DATA_IND"); + } + else if ((rxByte & L_ACKN_MASK) == L_ACKN_IND) + { + // this can only happen in bus monitor mode + println("got L_ACKN_IND"); + } + else if (rxByte == U_RESET_IND) + { + println("got U_RESET_IND"); + } + else if ((rxByte & U_STATE_IND) == U_STATE_IND) + { + print("got U_STATE_IND:"); + if (rxByte & 0x80) print (" SC"); + if (rxByte & 0x40) print (" RE"); + if (rxByte & 0x20) print (" TE"); + if (rxByte & 0x10) print (" PE"); + if (rxByte & 0x08) print (" TW"); + println(); + } + else if ((rxByte & U_FRAME_STATE_MASK) == U_FRAME_STATE_IND) + { + print("got U_FRAME_STATE_IND: 0x"); + print(rxByte, HEX); + println(); + } + else if ((rxByte & U_CONFIGURE_MASK) == U_CONFIGURE_IND) + { + print("got U_CONFIGURE_IND: 0x"); + print(rxByte, HEX); + println(); + } + else if (rxByte == U_FRAME_END_IND) + { + println("got U_FRAME_END_IND"); + } + else if (rxByte == U_STOP_MODE_IND) + { + println("got U_STOP_MODE_IND"); + } + else if (rxByte == U_SYSTEM_STAT_IND) + { + print("got U_SYSTEM_STAT_IND: 0x"); + while (true) + { + int tmp = _platform.readUart(); + if (tmp < 0) + continue; + + print(tmp, HEX); + break; + } + println(); + } + else + { + print("got UNEXPECTED: 0x"); + print(rxByte, HEX); + println(); + } + } + break; + case RX_L_ADDR: + if (millis() - _lastByteRxTime > EOPR_TIMEOUT) + { + _rxState = RX_WAIT_START; + print("EOPR inside RX_L_ADDR"); + printHex(" => ", buffer, _RxByteCnt); + break; + } + if (!_platform.uartAvailable()) + break; + _lastByteRxTime = millis(); rxByte = _platform.readUart(); #ifdef DBG_TRACE print(rxByte, HEX); #endif - _lastByteRxTime = millis(); - - // Check for layer-2 packets - _RxByteCnt = 0; - _xorSum = 0; - if ((rxByte & L_DATA_MASK) == L_DATA_STANDARD_IND) - { - buffer[_RxByteCnt++] = rxByte; - _xorSum ^= rxByte; - _RxByteCnt++; //convert to L_DATA_EXTENDED - _convert = true; - _rxState = RX_L_ADDR; -#ifdef DBG_TRACE - println("RLS"); -#endif - break; - } - else if ((rxByte & L_DATA_MASK) == L_DATA_EXTENDED_IND) - { - buffer[_RxByteCnt++] = rxByte; - _xorSum ^= rxByte; - _convert = false; - _rxState = RX_L_ADDR; -#ifdef DBG_TRACE - println("RLX"); -#endif - break; - } - - // Handle all single byte packets here - else if ((rxByte & L_DATA_CON_MASK) == L_DATA_CON) - { - dataConnMsg = rxByte; - } - else if (rxByte == L_POLL_DATA_IND) - { - // not sure if this can happen - println("got L_POLL_DATA_IND"); - } - else if ((rxByte & L_ACKN_MASK) == L_ACKN_IND) - { - // this can only happen in bus monitor mode - println("got L_ACKN_IND"); - } - else if (rxByte == U_RESET_IND) - { - println("got U_RESET_IND"); - } - else if ((rxByte & U_STATE_IND) == U_STATE_IND) - { - print("got U_STATE_IND:"); - if (rxByte & 0x80) print (" SC"); - if (rxByte & 0x40) print (" RE"); - if (rxByte & 0x20) print (" TE"); - if (rxByte & 0x10) print (" PE"); - if (rxByte & 0x08) print (" TW"); - println(); - } - else if ((rxByte & U_FRAME_STATE_MASK) == U_FRAME_STATE_IND) - { - print("got U_FRAME_STATE_IND: 0x"); - print(rxByte, HEX); - println(); - } - else if ((rxByte & U_CONFIGURE_MASK) == U_CONFIGURE_IND) - { - print("got U_CONFIGURE_IND: 0x"); - print(rxByte, HEX); - println(); - } - else if (rxByte == U_FRAME_END_IND) - { - println("got U_FRAME_END_IND"); - } - else if (rxByte == U_STOP_MODE_IND) - { - println("got U_STOP_MODE_IND"); - } - else if (rxByte == U_SYSTEM_STAT_IND) - { - print("got U_SYSTEM_STAT_IND: 0x"); - while (true) - { - int tmp = _platform.readUart(); - if (tmp < 0) - continue; - - print(tmp, HEX); - break; - } - println(); - } - else - { - print("got UNEXPECTED: 0x"); - print(rxByte, HEX); - println(); - } - } - break; - case RX_L_ADDR: - if (millis() - _lastByteRxTime > EOPR_TIMEOUT) - { - _rxState = RX_WAIT_START; - print("EOPR inside RX_L_ADDR"); - printHex(" => ", buffer, _RxByteCnt); - break; - } - if (!_platform.uartAvailable()) - break; - _lastByteRxTime = millis(); - rxByte = _platform.readUart(); -#ifdef DBG_TRACE - print(rxByte, HEX); -#endif - buffer[_RxByteCnt++] = rxByte; - _xorSum ^= rxByte; - - if (_RxByteCnt == 7) - { - //Destination Address + payload available - //check if echo - if (_sendBuffer != nullptr && (!((buffer[0] ^ _sendBuffer[0]) & ~0x20) && !memcmp(buffer + _convert + 1, _sendBuffer + 1, 5))) - { //ignore repeated bit of control byte - _isEcho = true; - } - else - { - _isEcho = false; - } - - //convert into Extended.ind - if (_convert) - { - uint8_t payloadLength = buffer[6] & 0x0F; - buffer[1] = buffer[6] & 0xF0; - buffer[6] = payloadLength; - } - - if (!_isEcho) - { - uint8_t c = 0x10; - - // The bau knows everything and could either check the address table object (normal device) - // or any filter tables (coupler) to see if we are addressed. - - //check if individual or group address - bool isGroupAddress = (buffer[1] & 0x80) != 0; - uint16_t addr = getWord(buffer + 4); - - if (_cb.isAckRequired(addr, isGroupAddress)) - { - c |= 0x01; - } - - // Hint: We can send directly here, this doesn't disturb other transmissions - // We don't have to update _lastByteTxTime because after ACK the timing is not so tight - _platform.writeUart(c); - } - _rxState = RX_L_DATA; - } - break; - case RX_L_DATA: - if (!_platform.uartAvailable()) - break; - _lastByteRxTime = millis(); - rxByte = _platform.readUart(); -#ifdef DBG_TRACE - print(rxByte, HEX); -#endif - if (_RxByteCnt == MAX_KNX_TELEGRAM_SIZE) - { - _rxState = RX_WAIT_EOP; - println("invalid telegram size"); - } - else - { buffer[_RxByteCnt++] = rxByte; - } + _xorSum ^= rxByte; - if (_RxByteCnt == buffer[6] + 7 + 2) - { - //complete Frame received, payloadLength+1 for TCPI +1 for CRC - if (rxByte == (uint8_t)(~_xorSum)) + if (_RxByteCnt == 7) { - //check if crc is correct - if (_isEcho && _sendBuffer != NULL) - { - //check if it is realy an echo, rx_crc = tx_crc - if (rxByte == _sendBuffer[_sendBufferLength - 1]) - _isEcho = true; - else - _isEcho = false; - } - if (_isEcho) - { - isEchoComplete = true; + //Destination Address + payload available + //check if echo + if (_sendBuffer != nullptr && (!((buffer[0] ^ _sendBuffer[0]) & ~0x20) && !memcmp(buffer + _convert + 1, _sendBuffer + 1, 5))) + { //ignore repeated bit of control byte + _isEcho = true; } else { - frameBytesReceived(_receiveBuffer, _RxByteCnt + 2); + _isEcho = false; } + + //convert into Extended.ind + if (_convert) + { + uint8_t payloadLength = buffer[6] & 0x0F; + buffer[1] = buffer[6] & 0xF0; + buffer[6] = payloadLength; + } + + if (!_isEcho) + { + uint8_t c = 0x10; + + // The bau knows everything and could either check the address table object (normal device) + // or any filter tables (coupler) to see if we are addressed. + + //check if individual or group address + bool isGroupAddress = (buffer[1] & 0x80) != 0; + uint16_t addr = getWord(buffer + 4); + + if (_cb.isAckRequired(addr, isGroupAddress)) + { + c |= 0x01; + } + + // Hint: We can send directly here, this doesn't disturb other transmissions + // We don't have to update _lastByteTxTime because after ACK the timing is not so tight + _platform.writeUart(c); + } + _rxState = RX_L_DATA; + } + break; + case RX_L_DATA: + if (!_platform.uartAvailable()) + break; + _lastByteRxTime = millis(); + rxByte = _platform.readUart(); +#ifdef DBG_TRACE + print(rxByte, HEX); +#endif + if (_RxByteCnt == MAX_KNX_TELEGRAM_SIZE) + { + _rxState = RX_WAIT_EOP; + println("invalid telegram size"); + } + else + { + buffer[_RxByteCnt++] = rxByte; + } + + if (_RxByteCnt == buffer[6] + 7 + 2) + { + //complete Frame received, payloadLength+1 for TCPI +1 for CRC + if (rxByte == (uint8_t)(~_xorSum)) + { + //check if crc is correct + if (_isEcho && _sendBuffer != NULL) + { + //check if it is realy an echo, rx_crc = tx_crc + if (rxByte == _sendBuffer[_sendBufferLength - 1]) + _isEcho = true; + else + _isEcho = false; + } + if (_isEcho) + { + isEchoComplete = true; + } + else + { + _receiveBuffer[0] = 0x29; + _receiveBuffer[1] = 0; + frameBytesReceived(_receiveBuffer, _RxByteCnt + 2); + } + _rxState = RX_WAIT_START; +#ifdef DBG_TRACE + println("RX_WAIT_START"); +#endif + } + else + { + println("frame with invalid crc ignored"); + _rxState = RX_WAIT_EOP; + } + } + else + { + _xorSum ^= rxByte; + } + break; + case RX_WAIT_EOP: + if (millis() - _lastByteRxTime > EOP_TIMEOUT) + { + _RxByteCnt = 0; _rxState = RX_WAIT_START; #ifdef DBG_TRACE println("RX_WAIT_START"); +#endif + break; + } + if (!_platform.uartAvailable()) + break; + _lastByteRxTime = millis(); + rxByte = _platform.readUart(); +#ifdef DBG_TRACE + print(rxByte, HEX); +#endif + break; + default: + break; + } + } while (_rxState == RX_L_ADDR && (stayInRx || _platform.uartAvailable())); + + // Check for spurios DATA_CONN message + if (dataConnMsg && _txState != TX_WAIT_CONN && _txState != TX_WAIT_ECHO) { + println("got unexpected L_DATA_CON"); + } + + switch (_txState) + { + case TX_IDLE: + if (!isTxQueueEmpty()) + { + loadNextTxFrame(); + _txState = TX_FRAME; +#ifdef DBG_TRACE + println("TX_FRAME"); +#endif + } + break; + case TX_FRAME: + if (millis() - _lastByteTxTime > TX_TIMEPAUSE) + { + if (sendSingleFrameByte() == false) + { + _waitConfirmStartTime = millis(); + _txState = TX_WAIT_ECHO; +#ifdef DBG_TRACE + println("TX_WAIT_ECHO"); #endif } else { - println("frame with invalid crc ignored"); - _rxState = RX_WAIT_EOP; + _lastByteTxTime = millis(); } } - else - { - _xorSum ^= rxByte; - } break; - case RX_WAIT_EOP: - if (millis() - _lastByteRxTime > EOP_TIMEOUT) + case TX_WAIT_ECHO: + case TX_WAIT_CONN: + if (isEchoComplete) { - _RxByteCnt = 0; - _rxState = RX_WAIT_START; + _txState = TX_WAIT_CONN; #ifdef DBG_TRACE - println("RX_WAIT_START"); + println("TX_WAIT_CONN"); #endif - break; } - if (!_platform.uartAvailable()) - break; - _lastByteRxTime = millis(); - rxByte = _platform.readUart(); + else if (dataConnMsg) + { + bool waitEcho = (_txState == TX_WAIT_ECHO); + if (waitEcho) { + println("L_DATA_CON without echo"); + } + dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, !waitEcho && ((dataConnMsg & SUCCESS) > 0)); + delete[] _sendBuffer; + _sendBuffer = 0; + _sendBufferLength = 0; + _txState = TX_IDLE; + } + else if (millis() - _waitConfirmStartTime > CONFIRM_TIMEOUT) + { + println("L_DATA_CON not received within expected time"); + uint8_t cemiBuffer[MAX_KNX_TELEGRAM_SIZE]; + cemiBuffer[0] = 0x29; + cemiBuffer[1] = 0; + memcpy((cemiBuffer + 2), _sendBuffer, _sendBufferLength); + dataConBytesReceived(cemiBuffer, _sendBufferLength + 2, false); + delete[] _sendBuffer; + _sendBuffer = 0; + _sendBufferLength = 0; + _txState = TX_IDLE; #ifdef DBG_TRACE - print(rxByte, HEX); + println("TX_IDLE"); #endif - break; - default: + } break; } - } while (_rxState == RX_L_ADDR && (stayInRx || _platform.uartAvailable())); - - // Check for spurios DATA_CONN message - if (dataConnMsg && _txState != TX_WAIT_CONN && _txState != TX_WAIT_ECHO) { - println("got unexpected L_DATA_CON"); - } - - switch (_txState) - { - case TX_IDLE: - if (!isTxQueueEmpty()) - { - loadNextTxFrame(); - _txState = TX_FRAME; -#ifdef DBG_TRACE - println("TX_FRAME"); -#endif - } - break; - case TX_FRAME: - if (millis() - _lastByteTxTime > TX_TIMEPAUSE) - { - if (sendSingleFrameByte() == false) - { - _waitConfirmStartTime = millis(); - _txState = TX_WAIT_ECHO; -#ifdef DBG_TRACE - println("TX_WAIT_ECHO"); -#endif - } - else - { - _lastByteTxTime = millis(); - } - } - break; - case TX_WAIT_ECHO: - case TX_WAIT_CONN: - if (isEchoComplete) - { - _txState = TX_WAIT_CONN; -#ifdef DBG_TRACE - println("TX_WAIT_CONN"); -#endif - } - else if (dataConnMsg) - { - bool waitEcho = (_txState == TX_WAIT_ECHO); - if (waitEcho) { - println("L_DATA_CON without echo"); - } - dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, !waitEcho && ((dataConnMsg & SUCCESS) > 0)); - delete[] _sendBuffer; - _sendBuffer = 0; - _sendBufferLength = 0; - _txState = TX_IDLE; - } - else if (millis() - _waitConfirmStartTime > CONFIRM_TIMEOUT) - { - println("L_DATA_CON not received within expected time"); - uint8_t cemiBuffer[MAX_KNX_TELEGRAM_SIZE]; - cemiBuffer[0] = 0x29; - cemiBuffer[1] = 0; - memcpy((cemiBuffer + 2), _sendBuffer, _sendBufferLength); - dataConBytesReceived(cemiBuffer, _sendBufferLength + 2, false); - delete[] _sendBuffer; - _sendBuffer = 0; - _sendBufferLength = 0; - _txState = TX_IDLE; -#ifdef DBG_TRACE - println("TX_IDLE"); -#endif - } - break; - } + } while (_platform.uartAvailable()); } bool TpUartDataLinkLayer::sendFrame(CemiFrame& frame) From 408cd2bbebaf85d4a486fb92f719fefba73ab7d6 Mon Sep 17 00:00:00 2001 From: Mike Pieper Date: Sun, 13 Feb 2022 11:22:02 +0100 Subject: [PATCH 4/4] printHex takes to long --- src/knx/tpuart_data_link_layer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/knx/tpuart_data_link_layer.cpp b/src/knx/tpuart_data_link_layer.cpp index cb37311..ce6d5d7 100644 --- a/src/knx/tpuart_data_link_layer.cpp +++ b/src/knx/tpuart_data_link_layer.cpp @@ -259,7 +259,6 @@ void TpUartDataLinkLayer::loop() { _rxState = RX_WAIT_START; print("EOPR inside RX_L_ADDR"); - printHex(" => ", buffer, _RxByteCnt); break; } if (!_platform.uartAvailable())