Merge pull request #171 from mptei/tx_throttle_rx_wait_addr

More tpuart fixes
This commit is contained in:
thelsing 2022-02-13 21:56:03 +01:00 committed by GitHub
commit d26771c432
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 330 additions and 283 deletions

View File

@ -89,17 +89,23 @@ enum {
//rx states //rx states
enum { enum {
RX_WAIT_START, RX_WAIT_START,
RX_L_ADDR,
RX_L_DATA, RX_L_DATA,
RX_WAIT_EOP RX_WAIT_EOP
}; };
#define EOP_TIMEOUT 2 //milli seconds; end of layer-2 packet gap #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 CONFIRM_TIMEOUT 500 //milli seconds
#define RESET_TIMEOUT 100 //milli seconds #define RESET_TIMEOUT 100 //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() void TpUartDataLinkLayer::loop()
{ {
if (!_enabled) if (!_enabled)
{ {
if (millis() - _lastResetChipTime > 1000) if (millis() - _lastResetChipTime > 1000)
@ -113,15 +119,32 @@ void TpUartDataLinkLayer::loop()
if (!_enabled) if (!_enabled)
return; return;
// Loop once and repeat as long we have rx data available
do {
// Signals to communicate from rx part with the tx part // Signals to communicate from rx part with the tx part
bool isEchoComplete = false; // Flag that a complete echo is received bool isEchoComplete = false; // Flag that a complete echo is received
uint8_t dataConnMsg = 0; // The DATA_CONN message just seen or 0 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 once and repeat as long we are in the receive phase for the L2 address
do { do {
_receiveBuffer[0] = 0x29;
_receiveBuffer[1] = 0;
uint8_t* buffer = _receiveBuffer + 2; uint8_t* buffer = _receiveBuffer + 2;
uint8_t rxByte; uint8_t rxByte;
bool isEOP = (millis() - _lastByteRxTime > EOP_TIMEOUT); // Flag that an EOP gap is seen
switch (_rxState) switch (_rxState)
{ {
case RX_WAIT_START: case RX_WAIT_START:
@ -142,7 +165,7 @@ void TpUartDataLinkLayer::loop()
_xorSum ^= rxByte; _xorSum ^= rxByte;
_RxByteCnt++; //convert to L_DATA_EXTENDED _RxByteCnt++; //convert to L_DATA_EXTENDED
_convert = true; _convert = true;
_rxState = RX_L_DATA; _rxState = RX_L_ADDR;
#ifdef DBG_TRACE #ifdef DBG_TRACE
println("RLS"); println("RLS");
#endif #endif
@ -153,7 +176,7 @@ void TpUartDataLinkLayer::loop()
buffer[_RxByteCnt++] = rxByte; buffer[_RxByteCnt++] = rxByte;
_xorSum ^= rxByte; _xorSum ^= rxByte;
_convert = false; _convert = false;
_rxState = RX_L_DATA; _rxState = RX_L_ADDR;
#ifdef DBG_TRACE #ifdef DBG_TRACE
println("RLX"); println("RLX");
#endif #endif
@ -231,12 +254,11 @@ void TpUartDataLinkLayer::loop()
} }
} }
break; break;
case RX_L_DATA: case RX_L_ADDR:
if (isEOP) if (millis() - _lastByteRxTime > EOPR_TIMEOUT)
{ {
_rxState = RX_WAIT_START; _rxState = RX_WAIT_START;
print("EOP inside RX_L_DATA"); print("EOPR inside RX_L_ADDR");
printHex(" => ", buffer, _RxByteCnt);
break; break;
} }
if (!_platform.uartAvailable()) if (!_platform.uartAvailable())
@ -246,20 +268,12 @@ void TpUartDataLinkLayer::loop()
#ifdef DBG_TRACE #ifdef DBG_TRACE
print(rxByte, HEX); print(rxByte, HEX);
#endif #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) if (_RxByteCnt == 7)
{ {
//Destination Address + payload available //Destination Address + payload available
_xorSum ^= rxByte;
//check if echo //check if echo
if (_sendBuffer != nullptr && (!((buffer[0] ^ _sendBuffer[0]) & ~0x20) && !memcmp(buffer + _convert + 1, _sendBuffer + 1, 5))) if (_sendBuffer != nullptr && (!((buffer[0] ^ _sendBuffer[0]) & ~0x20) && !memcmp(buffer + _convert + 1, _sendBuffer + 1, 5)))
{ //ignore repeated bit of control byte { //ignore repeated bit of control byte
@ -295,10 +309,31 @@ void TpUartDataLinkLayer::loop()
} }
// Hint: We can send directly here, this doesn't disturb other transmissions // 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); _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 //complete Frame received, payloadLength+1 for TCPI +1 for CRC
if (rxByte == (uint8_t)(~_xorSum)) if (rxByte == (uint8_t)(~_xorSum))
@ -318,6 +353,8 @@ void TpUartDataLinkLayer::loop()
} }
else else
{ {
_receiveBuffer[0] = 0x29;
_receiveBuffer[1] = 0;
frameBytesReceived(_receiveBuffer, _RxByteCnt + 2); frameBytesReceived(_receiveBuffer, _RxByteCnt + 2);
} }
_rxState = RX_WAIT_START; _rxState = RX_WAIT_START;
@ -337,7 +374,7 @@ void TpUartDataLinkLayer::loop()
} }
break; break;
case RX_WAIT_EOP: case RX_WAIT_EOP:
if (isEOP) if (millis() - _lastByteRxTime > EOP_TIMEOUT)
{ {
_RxByteCnt = 0; _RxByteCnt = 0;
_rxState = RX_WAIT_START; _rxState = RX_WAIT_START;
@ -357,7 +394,7 @@ void TpUartDataLinkLayer::loop()
default: default:
break; break;
} }
} while (_rxState == RX_L_DATA); } while (_rxState == RX_L_ADDR && (stayInRx || _platform.uartAvailable()));
// Check for spurios DATA_CONN message // Check for spurios DATA_CONN message
if (dataConnMsg && _txState != TX_WAIT_CONN && _txState != TX_WAIT_ECHO) { if (dataConnMsg && _txState != TX_WAIT_CONN && _txState != TX_WAIT_ECHO) {
@ -377,6 +414,8 @@ void TpUartDataLinkLayer::loop()
} }
break; break;
case TX_FRAME: case TX_FRAME:
if (millis() - _lastByteTxTime > TX_TIMEPAUSE)
{
if (sendSingleFrameByte() == false) if (sendSingleFrameByte() == false)
{ {
_waitConfirmStartTime = millis(); _waitConfirmStartTime = millis();
@ -385,6 +424,11 @@ void TpUartDataLinkLayer::loop()
println("TX_WAIT_ECHO"); println("TX_WAIT_ECHO");
#endif #endif
} }
else
{
_lastByteTxTime = millis();
}
}
break; break;
case TX_WAIT_ECHO: case TX_WAIT_ECHO:
case TX_WAIT_CONN: case TX_WAIT_CONN:
@ -425,6 +469,7 @@ void TpUartDataLinkLayer::loop()
} }
break; break;
} }
} while (_platform.uartAvailable());
} }
bool TpUartDataLinkLayer::sendFrame(CemiFrame& frame) bool TpUartDataLinkLayer::sendFrame(CemiFrame& frame)

View File

@ -43,6 +43,8 @@ class TpUartDataLinkLayer : public DataLinkLayer
bool _convert = false; bool _convert = false;
uint8_t _xorSum = 0; uint8_t _xorSum = 0;
uint32_t _lastByteRxTime; uint32_t _lastByteRxTime;
uint32_t _lastByteTxTime;
uint32_t _lastLoopTime;
uint32_t _waitConfirmStartTime; uint32_t _waitConfirmStartTime;
uint32_t _lastResetChipTime = 0; uint32_t _lastResetChipTime = 0;