diff --git a/src/knx/tpuart_data_link_layer.cpp b/src/knx/tpuart_data_link_layer.cpp index 479b2566..a3780838 100644 --- a/src/knx/tpuart_data_link_layer.cpp +++ b/src/knx/tpuart_data_link_layer.cpp @@ -306,13 +306,7 @@ void TpUartDataLinkLayer::processRxByte() if (_txState == TX_FRAME) { const bool success = ((byte ^ L_DATA_CON_MASK) >> 7); - uint8_t *cemiData = _txFrame->cemiData(); - CemiFrame cemiFrame(cemiData, _txFrame->cemiSize()); - dataConReceived(cemiFrame, success); - free(cemiData); - delete _txFrame; - _txFrame = nullptr; - _txState = TX_IDLE; + processTxFrameComplete(success); } else { @@ -436,7 +430,7 @@ void TpUartDataLinkLayer::processRxFrameByte(uint8_t byte) if (availableInRxQueue() < (_rxFrame->size() + 3)) { // Nur wenn ich nicht selber sende - if (_txState == RX_IDLE) + if (_txState == TX_IDLE) { _platform.writeUart(U_ACK_REQ | U_ACK_REQ_ADRESSED | U_ACK_REQ_BUSY); } @@ -529,6 +523,30 @@ void TpUartDataLinkLayer::processRxFrameComplete() _rxFrame->reset(); } +void TpUartDataLinkLayer::clearTxFrame() +{ + if (_txFrame != nullptr) + { + delete _txFrame; + _txFrame = nullptr; + } +} + +void TpUartDataLinkLayer::clearTxFrameQueue() +{ +} + +void TpUartDataLinkLayer::processTxFrameComplete(bool success) +{ + uint8_t *cemiData = _txFrame->cemiData(); + CemiFrame cemiFrame(cemiData, _txFrame->cemiSize()); + dataConReceived(cemiFrame, success); + free(cemiData); + clearTxFrame(); + _txProcessdFrameCounter++; + _txState = TX_IDLE; +} + /* * Steckt das zu sendende Frame in eine Queue, da der TpUart vielleicht gerade noch nicht sende bereit ist. */ @@ -545,6 +563,14 @@ void TpUartDataLinkLayer::pushTxFrameQueue(TpFrame *tpFrame) _txFrameQueue.back->next = entry; _txFrameQueue.back = entry; } + + if (_txQueueCount > 10) + { + print("_txQueueCount:"); + print(_txQueueCount); + } + _txQueueCount++; + _txFrameCounter++; } void TpUartDataLinkLayer::setRepetitions(uint8_t nack, uint8_t busy) @@ -685,17 +711,15 @@ bool TpUartDataLinkLayer::reset() _rxInvalidFrameCounter = 0; _rxInvalidFrameCounter = 0; _rxUnkownControlCounter = 0; - if (_txFrame != nullptr) - { - _txFrame = nullptr; - delete _txFrame; - } + + clearTxFrame(); + clearTxFrameQueue(); + if (_rxFrame != nullptr) { _rxFrame->reset(); } _rxState = RX_IDLE; - _txState = TX_IDLE; _connected = false; _stopped = false; _monitoring = false; @@ -786,6 +810,17 @@ bool TpUartDataLinkLayer::enabled() const return _initialized && _connected; } +/* + * Wenn ein TxFrame gesendet wurde, wird eine Bestätigung für den Versand erwartet. + * Kam es aber zu einem ungültigen Frame oder Busdisconnect, bleibt die Bestätigung aus und der STack hängt im TX_FRAME fest. + * Daher muss nach einer kurzen Wartezeit das Warten beendet werden. + */ +void TpUartDataLinkLayer::clearOutdatedTxFrame() +{ + if (_txState == TX_FRAME && (millis() - _txLastTime) > 1000) + processTxFrameComplete(false); +} + /* * Hier werden die ausgehenden Frames aus der Warteschlange genomnmen und versendet. * Das passiert immer nur einzelnd, da nach jedem Frame, gewartet werden muss bis das Frame wieder reingekommen ist und das L_DATA_CON rein kommt. @@ -793,10 +828,6 @@ bool TpUartDataLinkLayer::enabled() const */ void TpUartDataLinkLayer::processTxQueue() { - // Diese Abfrage ist vorsorglich. Eigentlich sollte auch schon parallel gestartet werden können. - if (_rxState != RX_IDLE) - return; - if (_txState != TX_IDLE) return; @@ -810,9 +841,9 @@ void TpUartDataLinkLayer::processTxQueue() _txFrameQueue.back = nullptr; } - // free old frame - if (_txFrame != nullptr) - delete _txFrame; + _txQueueCount--; + + clearTxFrame(); // use frame from queue and delete queue entry _txFrame = entry->frame; @@ -892,6 +923,7 @@ void TpUartDataLinkLayer::loop() #endif requestState(); + clearOutdatedTxFrame(); processTxQueue(); checkConnected(); } @@ -1015,6 +1047,21 @@ uint32_t TpUartDataLinkLayer::getRxUnknownControlCounter() return _rxUnkownControlCounter; } +/* + * Liefert die Anzahl der zusendenden Frames + */ +uint32_t TpUartDataLinkLayer::getTxFrameCounter() +{ + return _txFrameCounter; +} +/* + * Liefert die Anzahl der versendeten Frames + */ +uint32_t TpUartDataLinkLayer::getTxProcessedFrameCounter() +{ + return _txProcessdFrameCounter; +} + bool TpUartDataLinkLayer::isConnected() { return _connected; diff --git a/src/knx/tpuart_data_link_layer.h b/src/knx/tpuart_data_link_layer.h index bace5401..24afa1a1 100644 --- a/src/knx/tpuart_data_link_layer.h +++ b/src/knx/tpuart_data_link_layer.h @@ -64,6 +64,8 @@ class TpUartDataLinkLayer : public DataLinkLayer uint32_t getRxProcessdFrameCounter(); uint32_t getRxIgnoredFrameCounter(); uint32_t getRxUnknownControlCounter(); + uint32_t getTxFrameCounter(); + uint32_t getTxProcessedFrameCounter(); uint8_t getMode(); private: @@ -95,19 +97,21 @@ class TpUartDataLinkLayer : public DataLinkLayer volatile bool _busy = false; volatile bool _initialized = false; - volatile uint32_t _stateTime = 0; volatile uint8_t _rxState = 0; volatile uint8_t _txState = 0; volatile uint32_t _rxProcessdFrameCounter = 0; volatile uint32_t _rxInvalidFrameCounter = 0; volatile uint32_t _rxIgnoredFrameCounter = 0; volatile uint32_t _rxUnkownControlCounter = 0; + volatile uint32_t _txFrameCounter = 0; + volatile uint32_t _txProcessdFrameCounter = 0; volatile bool _rxMarker = false; volatile bool _rxOverflow = false; volatile uint8_t _tpState = 0x0; volatile uint32_t _txLastTime = 0; volatile uint32_t _rxLastTime = 0; volatile bool _forceAck = false; + uint8_t _txQueueCount = 0; inline bool markerMode(); @@ -134,6 +138,7 @@ class TpUartDataLinkLayer : public DataLinkLayer void checkConnected(); void processRxByte(); void processTxQueue(); + void clearTxFrameQueue(); void processRxFrameComplete(); inline void processRxFrame(TpFrame* tpFrame); void pushTxFrameQueue(TpFrame* tpFrame); @@ -159,6 +164,9 @@ class TpUartDataLinkLayer : public DataLinkLayer inline void isrUnlock(); inline void clearUartBuffer(); inline void connected(bool state = true); + void clearTxFrame(); + void clearOutdatedTxFrame(); + void processTxFrameComplete(bool success); ITpUartCallBacks& _cb; DataLinkLayerCallbacks* _dllcb;