diff --git a/src/knx/application_layer.cpp b/src/knx/application_layer.cpp index 421a8f2..297eb65 100644 --- a/src/knx/application_layer.cpp +++ b/src/knx/application_layer.cpp @@ -487,7 +487,7 @@ void ApplicationLayer::systemNetworkParameterReadResponse(Priority priority, Hop //TODO: ApplicationLayer::domainAddressSerialNumberWriteRequest() //TODO: ApplicationLayer::domainAddressSerialNumberReadRequest() -void ApplicationLayer::domainAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, uint8_t* rfDoA, +void ApplicationLayer::domainAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const uint8_t* rfDoA, const uint8_t* knxSerialNumber) { CemiFrame frame(13); @@ -506,8 +506,8 @@ void ApplicationLayer::domainAddressSerialNumberReadResponse(Priority priority, //TODO: ApplicationLayer::IndividualAddressSerialNumberWriteRequest() //TODO: ApplicationLayer::IndividualAddressSerialNumberReadRequest() -void ApplicationLayer::IndividualAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, uint8_t* rfDoA, - uint8_t* knxSerialNumber) +void ApplicationLayer::IndividualAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const uint8_t* rfDoA, + const uint8_t* knxSerialNumber) { CemiFrame frame(13); APDU& apdu = frame.apdu(); diff --git a/src/knx/application_layer.h b/src/knx/application_layer.h index c2de79c..e05e3c9 100644 --- a/src/knx/application_layer.h +++ b/src/knx/application_layer.h @@ -135,10 +135,10 @@ class ApplicationLayer void systemNetworkParameterReadResponse(Priority priority, HopCountType hopType, uint16_t objectType, uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength, uint8_t* testResult, uint16_t testResultLength); - void domainAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, uint8_t* rfDoA, + void domainAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const uint8_t* rfDoA, + const uint8_t* knxSerialNumber); + void IndividualAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const uint8_t* rfDoA, const uint8_t* knxSerialNumber); - void IndividualAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, uint8_t* rfDoA, - uint8_t* knxSerialNumber); #pragma endregion private: diff --git a/src/knx/cemi_frame.cpp b/src/knx/cemi_frame.cpp index c4d6ff1..13e7c79 100644 --- a/src/knx/cemi_frame.cpp +++ b/src/knx/cemi_frame.cpp @@ -323,9 +323,9 @@ uint8_t* CemiFrame::rfSerialOrDoA() const return _rfSerialOrDoA; } -void CemiFrame::rfSerialOrDoA(uint8_t* rfSerialOrDoA) +void CemiFrame::rfSerialOrDoA(const uint8_t* rfSerialOrDoA) { - _rfSerialOrDoA = rfSerialOrDoA; + _rfSerialOrDoA = (uint8_t*)rfSerialOrDoA; } uint8_t CemiFrame::rfInfo() const diff --git a/src/knx/cemi_frame.h b/src/knx/cemi_frame.h index ef30165..fc21501 100644 --- a/src/knx/cemi_frame.h +++ b/src/knx/cemi_frame.h @@ -60,7 +60,7 @@ class CemiFrame #ifdef USE_RF // only for RF medium uint8_t* rfSerialOrDoA() const; - void rfSerialOrDoA(uint8_t* rfSerialOrDoA); + void rfSerialOrDoA(const uint8_t* rfSerialOrDoA); uint8_t rfInfo() const; void rfInfo(uint8_t rfInfo); uint8_t rfLfn() const; diff --git a/src/knx/dptconvert.cpp b/src/knx/dptconvert.cpp index 9ed1154..84c4f94 100644 --- a/src/knx/dptconvert.cpp +++ b/src/knx/dptconvert.cpp @@ -1043,7 +1043,7 @@ int valueToBusValueSigned8(const KNXValue& value, uint8_t* payload, size_t paylo if ((int64_t)value < INT64_C(-128) || (int64_t)value > INT64_C(127)) return false; - signed8ToPayload(payload, 0, payload_length, (uint64_t)value, 0xFF); + signed8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF); return true; } diff --git a/src/knx/tpuart_data_link_layer.cpp b/src/knx/tpuart_data_link_layer.cpp index 595800e..c68db25 100644 --- a/src/knx/tpuart_data_link_layer.cpp +++ b/src/knx/tpuart_data_link_layer.cpp @@ -1,539 +1,551 @@ -#include "tpuart_data_link_layer.h" -#ifdef USE_TP -#include "bits.h" -#include "platform.h" -#include "device_object.h" -#include "address_table_object.h" -#include "cemi_frame.h" - -#include -#include - -// NCN5120 -//#define NCN5120 - -// services Host -> Controller : -// internal commands, device specific -#define U_RESET_REQ 0x01 -#define U_STATE_REQ 0x02 -#define U_SET_BUSY_REQ 0x03 -#define U_QUIT_BUSY_REQ 0x04 -#define U_BUSMON_REQ 0x05 -#define U_SET_ADDRESS_REQ 0xF1 // different on TP-UART -#define U_SET_REPETITION_REQ 0xF2 -#define U_L_DATA_OFFSET_REQ 0x08 //-0x0C -#define U_SYSTEM_STATE 0x0D -#define U_STOP_MODE_REQ 0x0E -#define U_EXIT_STOP_MODE_REQ 0x0F -#define U_ACK_REQ 0x10 //-0x17 -#define U_CONFIGURE_REQ 0x18 -#define U_INT_REG_WR_REQ 0x28 -#define U_INT_REG_RD_REQ 0x38 -#define U_POLLING_STATE_REQ 0xE0 - -//knx transmit data commands -#define U_L_DATA_START_CONT_REQ 0x80 //-0xBF -#define U_L_DATA_END_REQ 0x40 //-0x7F - -//serices to host controller - -// DLL services (device is transparent) -#define L_DATA_STANDARD_IND 0x90 -#define L_DATA_EXTENDED_IND 0x10 -#define L_DATA_MASK 0xD3 -#define L_POLL_DATA_IND 0xF0 - -// acknowledge services (device is transparent in bus monitor mode) -#define L_ACKN_IND 0x00 -#define L_ACKN_MASK 0x33 -#define L_DATA_CON 0x0B -#define L_DATA_CON_MASK 0x7F -#define SUCCESS 0x80 - -// control services, device specific -#define U_RESET_IND 0x03 -#define U_STATE_IND 0x07 -#define SLAVE_COLLISION 0x80 -#define RECEIVE_ERROR 0x40 -#define TRANSMIT_ERROR 0x20 -#define PROTOCOL_ERROR 0x10 -#define TEMPERATURE_WARNING 0x08 -#define U_FRAME_STATE_IND 0x13 -#define U_FRAME_STATE_MASK 0x17 -#define PARITY_BIT_ERROR 0x80 -#define CHECKSUM_LENGTH_ERROR 0x40 -#define TIMING_ERROR 0x20 -#define U_CONFIGURE_IND 0x01 -#define U_CONFIGURE_MASK 0x83 -#define AUTO_ACKNOWLEDGE 0x20 -#define AUTO_POLLING 0x10 -#define CRC_CCITT 0x80 -#define FRAME_END_WITH_MARKER 0x40 -#define U_FRAME_END_IND 0xCB -#define U_STOP_MODE_IND 0x2B -#define U_SYSTEM_STAT_IND 0x4B - -//loop states -#define IDLE 0 -#define RX_FIRST_BYTE 1 -#define RX_L_DATA 2 -#define RX_WAIT_DATA_CON 3 -#define TX_FRAME 4 - -#define BYTE_TIMEOUT 10 //milli seconds -#define CONFIRM_TIMEOUT 500 //milli seconds -#define RESET_TIMEOUT 100 //milli seconds - -void TpUartDataLinkLayer::loop() -{ - - _receiveBuffer[0] = 0x29; - _receiveBuffer[1] = 0; - uint8_t* buffer = _receiveBuffer + 2; - uint8_t rxByte; - - if (!_enabled) - return; - - switch (_loopState) - { - case IDLE: - if (_platform.uartAvailable()) - { - _loopState = RX_FIRST_BYTE; - } - else - { - if (!_waitConfirm && !isTxQueueEmpty()) - { - loadNextTxFrame(); - _loopState = TX_FRAME; - } - } - break; - case TX_FRAME: - if (sendSingleFrameByte() == false) - { - _waitConfirm = true; - _waitConfirmStartTime = millis(); - _loopState = IDLE; - } - break; - case RX_FIRST_BYTE: - rxByte = _platform.readUart(); - _lastByteRxTime = millis(); - _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; - _loopState = RX_L_DATA; - break; - } - else if ((rxByte & L_DATA_MASK) == L_DATA_EXTENDED_IND) - { - buffer[_RxByteCnt++] = rxByte; - _xorSum ^= rxByte; - _convert = false; - _loopState = RX_L_DATA; - break; - } - else if ((rxByte & L_DATA_CON_MASK) == L_DATA_CON) - { - println("got unexpected L_DATA_CON"); - } - 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: 0x"); - print(rxByte, HEX); - 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(); - } - _loopState = IDLE; - break; - case RX_L_DATA: - if (millis() - _lastByteRxTime > BYTE_TIMEOUT) - { - _RxByteCnt = 0; - _loopState = IDLE; - println("Timeout during RX_L_DATA"); - break; - } - if (!_platform.uartAvailable()) - break; - _lastByteRxTime = millis(); - rxByte = _platform.readUart(); - - if (_RxByteCnt == MAX_KNX_TELEGRAM_SIZE) - { - _loopState = IDLE; - println("invalid telegram size"); - } - else - { - buffer[_RxByteCnt++] = rxByte; - } - - if (_RxByteCnt == 7) - { - //Destination Address + payload available - _xorSum ^= rxByte; - //check if echo - if (!((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; - //ceck if individual or group address - if ((buffer[6] & 0x80) == 0) - { - //individual - if (_deviceObject.induvidualAddress() == getWord(buffer + 4)) - { - c |= 0x01; - } - } - else - { - //group - if (_groupAddressTable.contains(getWord(buffer + 4)) || getWord(buffer + 4) == 0) - { - c |= 0x01; - } - } - _platform.writeUart(c); - } - } - else 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) - { - _loopState = RX_WAIT_DATA_CON; - } - else - { - frameBytesReceived(_receiveBuffer, _RxByteCnt + 2); - _loopState = IDLE; - } - } - else - { - println("frame with invalid crc ignored"); - _loopState = IDLE; - } - } - else - { - _xorSum ^= rxByte; - } - break; - case RX_WAIT_DATA_CON: - if (!_platform.uartAvailable()) - break; - rxByte = _platform.readUart(); - _lastByteRxTime = millis(); - if ((rxByte & L_DATA_CON_MASK) == L_DATA_CON) - { - //println("L_DATA_CON received"); - dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, ((rxByte & SUCCESS) > 0)); - _waitConfirm = false; - delete[] _sendBuffer; - _sendBuffer = 0; - _sendBufferLength = 0; - _loopState = IDLE; - } - else - { - //should not happen - println("expected L_DATA_CON not received"); - dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, false); - _waitConfirm = false; - delete[] _sendBuffer; - _sendBuffer = 0; - _sendBufferLength = 0; - _loopState = IDLE; - } - break; - default: - break; - } - - if (_waitConfirm) - { - 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); - _waitConfirm = false; - delete[] _sendBuffer; - _sendBuffer = 0; - _sendBufferLength = 0; - if (_loopState == RX_WAIT_DATA_CON) - _loopState = IDLE; - } - } -} - -bool TpUartDataLinkLayer::sendFrame(CemiFrame& frame) -{ - if (!_enabled) - { - dataConReceived(frame, false); - return false; - } - - addFrameTxQueue(frame); - return true; -} - -bool TpUartDataLinkLayer::resetChip() -{ - uint8_t cmd = U_RESET_REQ; - _platform.writeUart(cmd); - _waitConfirmStartTime = millis(); - while (true) - { - int resp = _platform.readUart(); - if (resp == U_RESET_IND) - return true; - else if (millis() - _waitConfirmStartTime > RESET_TIMEOUT) - return false; - } -} - -void TpUartDataLinkLayer::stopChip() -{ -#ifdef NCN5120 - uint8_t cmd = U_STOP_MODE_REQ; - _platform.writeUart(cmd); - while (true) - { - int resp = _platform.readUart(); - if (resp == U_STOP_MODE_IND) - break; - } -#endif -} - -TpUartDataLinkLayer::TpUartDataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, - NetworkLayer& layer, Platform& platform) - : DataLinkLayer(devObj, addrTab, layer, platform) -{ -} - -void TpUartDataLinkLayer::frameBytesReceived(uint8_t* buffer, uint16_t length) -{ - //printHex("=>", buffer, length); - CemiFrame frame(buffer, length); - - frameRecieved(frame); -} - -void TpUartDataLinkLayer::dataConBytesReceived(uint8_t* buffer, uint16_t length, bool success) -{ - //printHex("=>", buffer, length); - CemiFrame frame(buffer, length); - dataConReceived(frame, success); -} - -void TpUartDataLinkLayer::enabled(bool value) -{ - if (value && !_enabled) - { - _platform.setupUart(); - - if (resetChip()){ - _enabled = true; - print("ownaddr "); - println(_deviceObject.induvidualAddress(), HEX); - } - else{ - _enabled = false; - println("ERROR, TPUART not responding"); - } - return; - } - - if (!value && _enabled) - { - _enabled = false; - stopChip(); - _platform.closeUart(); - return; - } -} - -bool TpUartDataLinkLayer::enabled() const -{ - return _enabled; -} - -bool TpUartDataLinkLayer::sendSingleFrameByte() -{ - uint8_t cmd[2]; - uint8_t idx = _TxByteCnt / 64; - - if (_sendBuffer == NULL) - return false; - - if (_TxByteCnt < _sendBufferLength) - { - if (idx != _oldIdx) - { - _oldIdx = idx; - cmd[0] = U_L_DATA_OFFSET_REQ | idx; - _platform.writeUart(cmd, 1); - } - - if (_TxByteCnt != _sendBufferLength - 1) - cmd[0] = U_L_DATA_START_CONT_REQ | _TxByteCnt; - else - cmd[0] = U_L_DATA_END_REQ | _TxByteCnt; - - cmd[1] = _sendBuffer[_TxByteCnt]; - - _platform.writeUart(cmd, 2); - _TxByteCnt++; - return true; - } - else - { - _TxByteCnt = 0; - return false; - } -} - -void TpUartDataLinkLayer::addFrameTxQueue(CemiFrame& frame) -{ - - _tx_queue_frame_t* tx_frame = new _tx_queue_frame_t; - tx_frame->length = frame.telegramLengthtTP(); - tx_frame->data = new uint8_t[tx_frame->length]; - tx_frame->next = NULL; - frame.fillTelegramTP(tx_frame->data); - - if (_tx_queue.back == NULL) - { - _tx_queue.front = _tx_queue.back = tx_frame; - } - else - { - _tx_queue.back->next = tx_frame; - _tx_queue.back = tx_frame; - } -} - -bool TpUartDataLinkLayer::isTxQueueEmpty() -{ - if (_tx_queue.front == NULL) - { - return true; - } - return false; -} - -void TpUartDataLinkLayer::loadNextTxFrame() -{ - if (_tx_queue.front == NULL) - { - return; - } - _tx_queue_frame_t* tx_frame = _tx_queue.front; - _sendBuffer = tx_frame->data; - _sendBufferLength = tx_frame->length; - _tx_queue.front = tx_frame->next; - - if (_tx_queue.front == NULL) - { - _tx_queue.back = NULL; - } - delete tx_frame; -} -#endif \ No newline at end of file +#include "tpuart_data_link_layer.h" +#ifdef USE_TP +#include "bits.h" +#include "platform.h" +#include "device_object.h" +#include "address_table_object.h" +#include "cemi_frame.h" + +#include +#include + +// NCN5120 +//#define NCN5120 + +// services Host -> Controller : +// internal commands, device specific +#define U_RESET_REQ 0x01 +#define U_STATE_REQ 0x02 +#define U_SET_BUSY_REQ 0x03 +#define U_QUIT_BUSY_REQ 0x04 +#define U_BUSMON_REQ 0x05 +#define U_SET_ADDRESS_REQ 0xF1 // different on TP-UART +#define U_SET_REPETITION_REQ 0xF2 +#define U_L_DATA_OFFSET_REQ 0x08 //-0x0C +#define U_SYSTEM_STATE 0x0D +#define U_STOP_MODE_REQ 0x0E +#define U_EXIT_STOP_MODE_REQ 0x0F +#define U_ACK_REQ 0x10 //-0x17 +#define U_CONFIGURE_REQ 0x18 +#define U_INT_REG_WR_REQ 0x28 +#define U_INT_REG_RD_REQ 0x38 +#define U_POLLING_STATE_REQ 0xE0 + +//knx transmit data commands +#define U_L_DATA_START_CONT_REQ 0x80 //-0xBF +#define U_L_DATA_END_REQ 0x40 //-0x7F + +//serices to host controller + +// DLL services (device is transparent) +#define L_DATA_STANDARD_IND 0x90 +#define L_DATA_EXTENDED_IND 0x10 +#define L_DATA_MASK 0xD3 +#define L_POLL_DATA_IND 0xF0 + +// acknowledge services (device is transparent in bus monitor mode) +#define L_ACKN_IND 0x00 +#define L_ACKN_MASK 0x33 +#define L_DATA_CON 0x0B +#define L_DATA_CON_MASK 0x7F +#define SUCCESS 0x80 + +// control services, device specific +#define U_RESET_IND 0x03 +#define U_STATE_IND 0x07 +#define SLAVE_COLLISION 0x80 +#define RECEIVE_ERROR 0x40 +#define TRANSMIT_ERROR 0x20 +#define PROTOCOL_ERROR 0x10 +#define TEMPERATURE_WARNING 0x08 +#define U_FRAME_STATE_IND 0x13 +#define U_FRAME_STATE_MASK 0x17 +#define PARITY_BIT_ERROR 0x80 +#define CHECKSUM_LENGTH_ERROR 0x40 +#define TIMING_ERROR 0x20 +#define U_CONFIGURE_IND 0x01 +#define U_CONFIGURE_MASK 0x83 +#define AUTO_ACKNOWLEDGE 0x20 +#define AUTO_POLLING 0x10 +#define CRC_CCITT 0x80 +#define FRAME_END_WITH_MARKER 0x40 +#define U_FRAME_END_IND 0xCB +#define U_STOP_MODE_IND 0x2B +#define U_SYSTEM_STAT_IND 0x4B + +//loop states +#define IDLE 0 +#define RX_FIRST_BYTE 1 +#define RX_L_DATA 2 +#define RX_WAIT_DATA_CON 3 +#define TX_FRAME 4 + +#define BYTE_TIMEOUT 10 //milli seconds +#define CONFIRM_TIMEOUT 500 //milli seconds +#define RESET_TIMEOUT 100 //milli seconds + +void TpUartDataLinkLayer::loop() +{ + + _receiveBuffer[0] = 0x29; + _receiveBuffer[1] = 0; + uint8_t* buffer = _receiveBuffer + 2; + uint8_t rxByte; + + if (!_enabled) + { + if (millis() - _lastResetChipTime > 1000) + { + //reset chip every 1 seconds + _lastResetChipTime = millis(); + _enabled = resetChip(); + } + } + + if (!_enabled) + return; + + switch (_loopState) + { + case IDLE: + if (_platform.uartAvailable()) + { + _loopState = RX_FIRST_BYTE; + } + else + { + if (!_waitConfirm && !isTxQueueEmpty()) + { + loadNextTxFrame(); + _loopState = TX_FRAME; + } + } + break; + case TX_FRAME: + if (sendSingleFrameByte() == false) + { + _waitConfirm = true; + _waitConfirmStartTime = millis(); + _loopState = IDLE; + } + break; + case RX_FIRST_BYTE: + rxByte = _platform.readUart(); + _lastByteRxTime = millis(); + _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; + _loopState = RX_L_DATA; + break; + } + else if ((rxByte & L_DATA_MASK) == L_DATA_EXTENDED_IND) + { + buffer[_RxByteCnt++] = rxByte; + _xorSum ^= rxByte; + _convert = false; + _loopState = RX_L_DATA; + break; + } + else if ((rxByte & L_DATA_CON_MASK) == L_DATA_CON) + { + println("got unexpected L_DATA_CON"); + } + 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: 0x"); + print(rxByte, HEX); + 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(); + } + _loopState = IDLE; + break; + case RX_L_DATA: + if (millis() - _lastByteRxTime > BYTE_TIMEOUT) + { + _RxByteCnt = 0; + _loopState = IDLE; + println("Timeout during RX_L_DATA"); + break; + } + if (!_platform.uartAvailable()) + break; + _lastByteRxTime = millis(); + rxByte = _platform.readUart(); + + if (_RxByteCnt == MAX_KNX_TELEGRAM_SIZE) + { + _loopState = IDLE; + println("invalid telegram size"); + } + else + { + buffer[_RxByteCnt++] = rxByte; + } + + if (_RxByteCnt == 7) + { + //Destination Address + payload available + _xorSum ^= rxByte; + //check if echo + if (!((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; + //ceck if individual or group address + if ((buffer[6] & 0x80) == 0) + { + //individual + if (_deviceObject.induvidualAddress() == getWord(buffer + 4)) + { + c |= 0x01; + } + } + else + { + //group + if (_groupAddressTable.contains(getWord(buffer + 4)) || getWord(buffer + 4) == 0) + { + c |= 0x01; + } + } + _platform.writeUart(c); + } + } + else 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) + { + _loopState = RX_WAIT_DATA_CON; + } + else + { + frameBytesReceived(_receiveBuffer, _RxByteCnt + 2); + _loopState = IDLE; + } + } + else + { + println("frame with invalid crc ignored"); + _loopState = IDLE; + } + } + else + { + _xorSum ^= rxByte; + } + break; + case RX_WAIT_DATA_CON: + if (!_platform.uartAvailable()) + break; + rxByte = _platform.readUart(); + _lastByteRxTime = millis(); + if ((rxByte & L_DATA_CON_MASK) == L_DATA_CON) + { + //println("L_DATA_CON received"); + dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, ((rxByte & SUCCESS) > 0)); + _waitConfirm = false; + delete[] _sendBuffer; + _sendBuffer = 0; + _sendBufferLength = 0; + _loopState = IDLE; + } + else + { + //should not happen + println("expected L_DATA_CON not received"); + dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, false); + _waitConfirm = false; + delete[] _sendBuffer; + _sendBuffer = 0; + _sendBufferLength = 0; + _loopState = IDLE; + } + break; + default: + break; + } + + if (_waitConfirm) + { + 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); + _waitConfirm = false; + delete[] _sendBuffer; + _sendBuffer = 0; + _sendBufferLength = 0; + if (_loopState == RX_WAIT_DATA_CON) + _loopState = IDLE; + } + } +} + +bool TpUartDataLinkLayer::sendFrame(CemiFrame& frame) +{ + if (!_enabled) + { + dataConReceived(frame, false); + return false; + } + + addFrameTxQueue(frame); + return true; +} + +bool TpUartDataLinkLayer::resetChip() +{ + uint8_t cmd = U_RESET_REQ; + _platform.writeUart(cmd); + _waitConfirmStartTime = millis(); + while (true) + { + int resp = _platform.readUart(); + if (resp == U_RESET_IND) + return true; + else if (millis() - _waitConfirmStartTime > RESET_TIMEOUT) + return false; + } +} + +void TpUartDataLinkLayer::stopChip() +{ +#ifdef NCN5120 + uint8_t cmd = U_STOP_MODE_REQ; + _platform.writeUart(cmd); + while (true) + { + int resp = _platform.readUart(); + if (resp == U_STOP_MODE_IND) + break; + } +#endif +} + +TpUartDataLinkLayer::TpUartDataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, + NetworkLayer& layer, Platform& platform) + : DataLinkLayer(devObj, addrTab, layer, platform) +{ +} + +void TpUartDataLinkLayer::frameBytesReceived(uint8_t* buffer, uint16_t length) +{ + //printHex("=>", buffer, length); + CemiFrame frame(buffer, length); + + frameRecieved(frame); +} + +void TpUartDataLinkLayer::dataConBytesReceived(uint8_t* buffer, uint16_t length, bool success) +{ + //printHex("=>", buffer, length); + CemiFrame frame(buffer, length); + dataConReceived(frame, success); +} + +void TpUartDataLinkLayer::enabled(bool value) +{ + if (value && !_enabled) + { + _platform.setupUart(); + + if (resetChip()) + { + _enabled = true; + print("ownaddr "); + println(_deviceObject.induvidualAddress(), HEX); + } + else + { + _enabled = false; + println("ERROR, TPUART not responding"); + } + return; + } + + if (!value && _enabled) + { + _enabled = false; + stopChip(); + _platform.closeUart(); + return; + } +} + +bool TpUartDataLinkLayer::enabled() const +{ + return _enabled; +} + +bool TpUartDataLinkLayer::sendSingleFrameByte() +{ + uint8_t cmd[2]; + uint8_t idx = _TxByteCnt / 64; + + if (_sendBuffer == NULL) + return false; + + if (_TxByteCnt < _sendBufferLength) + { + if (idx != _oldIdx) + { + _oldIdx = idx; + cmd[0] = U_L_DATA_OFFSET_REQ | idx; + _platform.writeUart(cmd, 1); + } + + if (_TxByteCnt != _sendBufferLength - 1) + cmd[0] = U_L_DATA_START_CONT_REQ | _TxByteCnt; + else + cmd[0] = U_L_DATA_END_REQ | _TxByteCnt; + + cmd[1] = _sendBuffer[_TxByteCnt]; + + _platform.writeUart(cmd, 2); + _TxByteCnt++; + return true; + } + else + { + _TxByteCnt = 0; + return false; + } +} + +void TpUartDataLinkLayer::addFrameTxQueue(CemiFrame& frame) +{ + + _tx_queue_frame_t* tx_frame = new _tx_queue_frame_t; + tx_frame->length = frame.telegramLengthtTP(); + tx_frame->data = new uint8_t[tx_frame->length]; + tx_frame->next = NULL; + frame.fillTelegramTP(tx_frame->data); + + if (_tx_queue.back == NULL) + { + _tx_queue.front = _tx_queue.back = tx_frame; + } + else + { + _tx_queue.back->next = tx_frame; + _tx_queue.back = tx_frame; + } +} + +bool TpUartDataLinkLayer::isTxQueueEmpty() +{ + if (_tx_queue.front == NULL) + { + return true; + } + return false; +} + +void TpUartDataLinkLayer::loadNextTxFrame() +{ + if (_tx_queue.front == NULL) + { + return; + } + _tx_queue_frame_t* tx_frame = _tx_queue.front; + _sendBuffer = tx_frame->data; + _sendBufferLength = tx_frame->length; + _tx_queue.front = tx_frame->next; + + if (_tx_queue.front == NULL) + { + _tx_queue.back = NULL; + } + delete tx_frame; +} +#endif \ No newline at end of file diff --git a/src/knx/tpuart_data_link_layer.h b/src/knx/tpuart_data_link_layer.h index e60c45c..e84bc3e 100644 --- a/src/knx/tpuart_data_link_layer.h +++ b/src/knx/tpuart_data_link_layer.h @@ -38,6 +38,7 @@ class TpUartDataLinkLayer : public DataLinkLayer uint8_t _xorSum = 0; uint32_t _lastByteRxTime; uint32_t _waitConfirmStartTime; + uint32_t _lastResetChipTime = 0; struct _tx_queue_frame_t {