mirror of
				https://github.com/thelsing/knx.git
				synced 2025-10-26 10:26:25 +01:00 
			
		
		
		
	Merge pull request #1 from thelsing/master
async tpuart_data_link_layer version (#21)
This commit is contained in:
		
						commit
						61a3d1ef2a
					
				| @ -14,16 +14,31 @@ DataLinkLayer::DataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, | ||||
| 
 | ||||
| void DataLinkLayer::dataRequest(AckType ack, AddressType addrType, uint16_t destinationAddr, FrameFormat format, Priority priority, NPDU& npdu) | ||||
| { | ||||
|     bool success = sendTelegram(npdu, ack, destinationAddr, addrType, format, priority); | ||||
|     _networkLayer.dataConfirm(ack, addrType, destinationAddr, format, priority, npdu.frame().sourceAddress(), npdu, success); | ||||
|     sendTelegram(npdu, ack, destinationAddr, addrType, format, priority); | ||||
| } | ||||
| 
 | ||||
| void DataLinkLayer::systemBroadcastRequest(AckType ack, FrameFormat format, Priority priority, NPDU& npdu) | ||||
| { | ||||
|     bool success = sendTelegram(npdu, ack, 0, GroupAddress, format, priority); | ||||
|     _networkLayer.systemBroadcastConfirm(ack, format, priority, npdu.frame().sourceAddress(), npdu, success); | ||||
|     sendTelegram(npdu, ack, 0, GroupAddress, format, priority); | ||||
| } | ||||
| 
 | ||||
| void DataLinkLayer::dataConReceived(CemiFrame& frame,bool success) | ||||
| { | ||||
|     AckType ack = frame.ack(); | ||||
|     AddressType addrType = frame.addressType(); | ||||
|     uint16_t destination = frame.destinationAddress(); | ||||
|     uint16_t source = frame.sourceAddress(); | ||||
|     FrameFormat type = frame.frameType(); | ||||
|     Priority priority = frame.priority(); | ||||
|     NPDU& npdu = frame.npdu(); | ||||
| 
 | ||||
|     if (addrType == GroupAddress && destination == 0) | ||||
|         _networkLayer.systemBroadcastConfirm(ack, type, priority, source, npdu, success); | ||||
|     else | ||||
|         _networkLayer.dataConfirm(ack, addrType, destination, type, priority, source, npdu, success); | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| void DataLinkLayer::frameRecieved(CemiFrame& frame) | ||||
| { | ||||
|     AckType ack = frame.ack(); | ||||
| @ -93,3 +108,5 @@ uint8_t* DataLinkLayer::frameData(CemiFrame& frame) | ||||
| { | ||||
|     return frame._data; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -21,6 +21,7 @@ public: | ||||
|     virtual bool enabled() const = 0; | ||||
| protected: | ||||
|     void frameRecieved(CemiFrame& frame); | ||||
|     void dataConReceived(CemiFrame& frame, bool success); | ||||
|     bool sendTelegram(NPDU &npdu, AckType ack, uint16_t destinationAddr, AddressType addrType, FrameFormat format, Priority priority); | ||||
|     virtual bool sendFrame(CemiFrame& frame) = 0; | ||||
|     uint8_t* frameData(CemiFrame& frame); | ||||
| @ -28,4 +29,4 @@ protected: | ||||
|     AddressTableObject& _groupAddressTable; | ||||
|     NetworkLayer& _networkLayer; | ||||
|     Platform& _platform; | ||||
| }; | ||||
| }; | ||||
|  | ||||
| @ -36,6 +36,7 @@ bool IpDataLinkLayer::sendFrame(CemiFrame& frame) | ||||
|     bool success = sendBytes(buffer, length); | ||||
|     // only send 50 packet per second: see KNX 3.2.6 p.6
 | ||||
|     _platform.mdelay(20); | ||||
|     dataConReceived(frame, success); | ||||
|     delete[] buffer; | ||||
|     return success; | ||||
| } | ||||
| @ -101,4 +102,4 @@ bool IpDataLinkLayer::sendBytes(uint8_t* bytes, uint16_t length) | ||||
|         return false; | ||||
| 
 | ||||
|     return _platform.sendBytes(bytes, length); | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -73,6 +73,252 @@ | ||||
| #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 | ||||
| 
 | ||||
| 
 | ||||
| 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(); | ||||
|                 _waitConfirm = true; | ||||
|                 _waitConfirmStartTime = _platform.millis(); | ||||
|                 _loopState = TX_FRAME; | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
|     case TX_FRAME: | ||||
|         if(sendSingleFrameByte() == false){ | ||||
|             _loopState = IDLE; | ||||
|         } | ||||
|         break; | ||||
|     case RX_FIRST_BYTE: | ||||
|         rxByte =_platform.readUart(); | ||||
|         _lastByteRxTime = _platform.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 (_platform.millis() - _lastByteRxTime > BYTE_TIMEOUT){ | ||||
|             _RxByteCnt = 0; | ||||
|             _loopState = IDLE; | ||||
|             println("Timeout during RX_L_DATA"); | ||||
|             break; | ||||
|         } | ||||
|         if(!_platform.uartAvailable()) break; | ||||
|         _lastByteRxTime = _platform.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+2,_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 = _platform.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 (_platform.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) | ||||
|         return false; | ||||
| 
 | ||||
|     addFrameTxQueue(frame); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void TpUartDataLinkLayer::resetChip() | ||||
| { | ||||
|     uint8_t cmd = U_RESET_REQ; | ||||
| @ -106,160 +352,6 @@ TpUartDataLinkLayer::TpUartDataLinkLayer(DeviceObject& devObj, AddressTableObjec | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool TpUartDataLinkLayer::sendFrame(CemiFrame& frame) | ||||
| { | ||||
|     if (!_enabled) | ||||
|         return false; | ||||
| 
 | ||||
|     uint16_t length = frame.telegramLengthtTP(); | ||||
|     uint8_t* buffer = new uint8_t[length]; | ||||
|     frame.fillTelegramTP(buffer); | ||||
| 
 | ||||
|     _sendBuffer = buffer; | ||||
|     _sendResult = false; | ||||
|     _sendBufferLength = length; | ||||
|     sendBytes(buffer, length); | ||||
| 
 | ||||
|     while (_sendBuffer != 0) | ||||
|         loop(); | ||||
| 
 | ||||
|     delete[] buffer; | ||||
|     return _sendResult; | ||||
| } | ||||
| 
 | ||||
| void TpUartDataLinkLayer::loop() | ||||
| { | ||||
|     if (!_enabled) | ||||
|         return; | ||||
| 
 | ||||
|     if (_platform.uartAvailable() == 0) | ||||
|         return; | ||||
| 
 | ||||
|     uint8_t firstByte = _platform.readUart(); | ||||
| 
 | ||||
|     if (checkDataInd(firstByte)) | ||||
|         return; | ||||
| 
 | ||||
|     if (checkDataCon(firstByte)) | ||||
|         return; | ||||
| 
 | ||||
|     if (checkPollDataInd(firstByte)) | ||||
|         return; | ||||
| 
 | ||||
|     if (checkAckNackInd(firstByte)) | ||||
|         return; | ||||
| 
 | ||||
|     if (checkResetInd(firstByte)) | ||||
|         return; | ||||
| 
 | ||||
|     if (checkStateInd(firstByte)) | ||||
|         return; | ||||
| 
 | ||||
|     if (checkFrameStateInd(firstByte)) | ||||
|         return; | ||||
| 
 | ||||
|     if (checkConfigureInd(firstByte)) | ||||
|         return; | ||||
| 
 | ||||
|     if (checkFrameEndInd(firstByte)) | ||||
|         return; | ||||
| 
 | ||||
|     if (checkStopModeInd(firstByte)) | ||||
|         return; | ||||
| 
 | ||||
|     if (checkSystemStatInd(firstByte)) | ||||
|         return; | ||||
| 
 | ||||
|     handleUnexpected(firstByte); | ||||
| } | ||||
| 
 | ||||
| bool TpUartDataLinkLayer::checkDataInd(uint8_t firstByte) | ||||
| { | ||||
|     const size_t bufferSize = 512; | ||||
| 
 | ||||
|     uint8_t tmp = firstByte & L_DATA_MASK; | ||||
|     if (tmp != L_DATA_STANDARD_IND && tmp != L_DATA_EXTENDED_IND) | ||||
|         return false; | ||||
| 
 | ||||
|     int len = 0; | ||||
|     uint8_t cemiBuffer[bufferSize + 2]; | ||||
|     cemiBuffer[0] = 0x29; | ||||
|     cemiBuffer[1] = 0; | ||||
|     uint8_t* buffer = cemiBuffer + 2; | ||||
|     buffer[0] = firstByte; | ||||
| 
 | ||||
|     uint8_t payloadLength = 0; | ||||
|     if (tmp == L_DATA_STANDARD_IND) | ||||
|     { | ||||
|         //convert to extended frame format
 | ||||
|         _platform.readBytesUart(buffer + 2, 5); | ||||
|         sendAck((AddressType)(buffer[6] & GroupAddress), getWord(buffer + 4)); | ||||
|         payloadLength = buffer[6] & 0xF; | ||||
|         _platform.readBytesUart(buffer + 7, payloadLength + 2); //+1 for TCPI +1 for CRC
 | ||||
|         buffer[1] = buffer[6] & 0xF0; | ||||
|         buffer[6] = payloadLength; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         //extended frame
 | ||||
|         _platform.readBytesUart(buffer + 1, 6); | ||||
|         sendAck((AddressType)(buffer[1] & GroupAddress), getWord(buffer + 4)); | ||||
|         payloadLength = buffer[6]; | ||||
|         _platform.readBytesUart(buffer + 7, payloadLength + 2); //+1 for TCPI +1 for CRC
 | ||||
|     } | ||||
|     len = payloadLength + 9; | ||||
|      | ||||
|      | ||||
|     const uint8_t queueLength = 5; | ||||
|     static uint8_t buffers[queueLength][bufferSize + 2]; | ||||
|     static uint16_t bufferLengths[queueLength]; | ||||
| 
 | ||||
|     if (_sendBuffer != 0) | ||||
|     { | ||||
|         // we are trying to send a telegram queue received telegrams until we get our sent telegram
 | ||||
| 
 | ||||
|         if (len == _sendBufferLength && memcmp(_sendBuffer, buffer, len) == 0) | ||||
|         { | ||||
|             //we got the send telegramm back next byte is L_Data.con byte
 | ||||
|             uint8_t confirm = _platform.readUart(); | ||||
|             confirm &= L_DATA_CON_MASK; | ||||
|             _sendResult = (confirm > 0); | ||||
|             _sendBuffer = 0; | ||||
|             _sendBufferLength = 0; | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         // queue telegram, if we get more the queueLength before send succeeds 
 | ||||
|         // ignore the telegram
 | ||||
|         for (int i = 0; i < queueLength; i++) | ||||
|         { | ||||
|             if (bufferLengths[i] != 0) | ||||
|                 continue; | ||||
| 
 | ||||
|             bufferLengths[i] = len; | ||||
|             memcpy(&buffers[i][0], cemiBuffer, len + 2); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // process all previously queued telegramms first
 | ||||
|         for (int i = 0; i < queueLength; i++) | ||||
|         { | ||||
|             if (bufferLengths[i] == 0) | ||||
|                 break; | ||||
| 
 | ||||
|             frameBytesReceived(&buffers[i][0], bufferLengths[i]+2); | ||||
|             bufferLengths[i] = 0; | ||||
|         } | ||||
| 
 | ||||
|         frameBytesReceived(cemiBuffer, len+2); | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void TpUartDataLinkLayer::frameBytesReceived(uint8_t* buffer, uint16_t length) | ||||
| { | ||||
|     //printHex("=>", buffer, length);
 | ||||
| @ -268,133 +360,12 @@ void TpUartDataLinkLayer::frameBytesReceived(uint8_t* buffer, uint16_t length) | ||||
|     frameRecieved(frame); | ||||
| } | ||||
| 
 | ||||
| bool TpUartDataLinkLayer::checkDataCon(uint8_t firstByte) | ||||
| void TpUartDataLinkLayer::dataConBytesReceived(uint8_t* buffer, uint16_t length, bool success) | ||||
| { | ||||
|     uint8_t tmp = firstByte & L_DATA_CON_MASK; | ||||
|     if (tmp != L_DATA_CON) | ||||
|         return false; | ||||
|     //printHex("=>", buffer, length);
 | ||||
|     CemiFrame frame(buffer, length); | ||||
|     dataConReceived(frame,success); | ||||
| 
 | ||||
|     if (_sendBuffer == 0) | ||||
|     { | ||||
|         println("got unexpected L_DATA_CON"); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     _sendResult = (firstByte & SUCCESS) > 0; | ||||
|     _sendBuffer = 0; | ||||
|     _sendBufferLength = 0; | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool TpUartDataLinkLayer::checkPollDataInd(uint8_t firstByte) | ||||
| { | ||||
|     if (firstByte != L_POLL_DATA_IND) | ||||
|         return false; | ||||
| 
 | ||||
|     // not sure if this can happen
 | ||||
|     println("got L_POLL_DATA_IND"); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool TpUartDataLinkLayer::checkAckNackInd(uint8_t firstByte) | ||||
| { | ||||
|     uint8_t tmp = firstByte & L_ACKN_MASK; | ||||
|     if (tmp != L_ACKN_IND) | ||||
|         return false; | ||||
| 
 | ||||
|     // this can only happen in bus monitor mode
 | ||||
|     println("got L_ACKN_IND"); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool TpUartDataLinkLayer::checkResetInd(uint8_t firstByte) | ||||
| { | ||||
|     if (firstByte != U_RESET_IND) | ||||
|         return false; | ||||
| 
 | ||||
|     println("got U_RESET_IND"); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool TpUartDataLinkLayer::checkStateInd(uint8_t firstByte) | ||||
| { | ||||
|     uint8_t tmp = firstByte & U_STATE_IND; | ||||
|     if (tmp != U_STATE_IND) | ||||
|         return false; | ||||
| 
 | ||||
|     print("got U_STATE_IND: 0x"); | ||||
|     print(firstByte, HEX); | ||||
|     println(); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool TpUartDataLinkLayer::checkFrameStateInd(uint8_t firstByte) | ||||
| { | ||||
|     uint8_t tmp = firstByte & U_FRAME_STATE_MASK; | ||||
|     if (tmp != U_FRAME_STATE_IND) | ||||
|         return false; | ||||
| 
 | ||||
|     print("got U_FRAME_STATE_IND: 0x"); | ||||
|     print(firstByte, HEX); | ||||
|     println(); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool TpUartDataLinkLayer::checkConfigureInd(uint8_t firstByte) | ||||
| { | ||||
|     uint8_t tmp = firstByte & U_CONFIGURE_MASK; | ||||
|     if (tmp != U_CONFIGURE_IND) | ||||
|         return false; | ||||
| 
 | ||||
|     print("got U_CONFIGURE_IND: 0x"); | ||||
|     print(firstByte, HEX); | ||||
|     println(); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool TpUartDataLinkLayer::checkFrameEndInd(uint8_t firstByte) | ||||
| { | ||||
|     if (firstByte != U_FRAME_END_IND) | ||||
|         return false; | ||||
| 
 | ||||
|     println("got U_FRAME_END_IND"); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool TpUartDataLinkLayer::checkStopModeInd(uint8_t firstByte) | ||||
| { | ||||
|     if (firstByte != U_STOP_MODE_IND) | ||||
|         return false; | ||||
| 
 | ||||
|     println("got U_STOP_MODE_IND"); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool TpUartDataLinkLayer::checkSystemStatInd(uint8_t firstByte) | ||||
| { | ||||
|     if (firstByte != U_SYSTEM_STAT_IND) | ||||
|         return false; | ||||
| 
 | ||||
|     print("got U_SYSTEM_STAT_IND: 0x"); | ||||
|     while (true) | ||||
|     { | ||||
|         int tmp = _platform.readUart(); | ||||
|         if (tmp < 0) | ||||
|             continue; | ||||
| 
 | ||||
|         print(tmp, HEX); | ||||
|         break; | ||||
|     } | ||||
|     println(); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void TpUartDataLinkLayer::handleUnexpected(uint8_t firstByte) | ||||
| { | ||||
|     print("got UNEXPECTED: 0x"); | ||||
|     print(firstByte, HEX); | ||||
|     println(); | ||||
| } | ||||
| 
 | ||||
| void TpUartDataLinkLayer::enabled(bool value) | ||||
| @ -424,45 +395,74 @@ bool TpUartDataLinkLayer::enabled() const | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void TpUartDataLinkLayer::sendBytes(uint8_t* bytes, uint16_t length) | ||||
| { | ||||
|     //printHex("<=", bytes, length);
 | ||||
| bool TpUartDataLinkLayer::sendSingleFrameByte(){ | ||||
|     uint8_t cmd[2]; | ||||
|     uint8_t idx = _TxByteCnt / 64; | ||||
| 
 | ||||
|     uint8_t oldIdx = 0; | ||||
|          | ||||
|     for (int i = 0; i < length; i++) | ||||
|     { | ||||
|         uint8_t idx = length / 64; | ||||
|         if (idx != oldIdx) | ||||
|     if(_sendBuffer == NULL) return false; | ||||
| 
 | ||||
|     if(_TxByteCnt < _sendBufferLength){ | ||||
|         if (idx != _oldIdx) | ||||
|         { | ||||
|             oldIdx = idx; | ||||
|             _oldIdx = idx; | ||||
|             cmd[0] = U_L_DATA_OFFSET_REQ | idx; | ||||
|             _platform.writeUart(cmd, 1); | ||||
|         } | ||||
| 
 | ||||
|         if (i != length - 1) | ||||
|             cmd[0] = U_L_DATA_START_CONT_REQ | i; | ||||
|         if (_TxByteCnt != _sendBufferLength - 1) | ||||
|             cmd[0] = U_L_DATA_START_CONT_REQ | _TxByteCnt; | ||||
|         else | ||||
|             cmd[0] = U_L_DATA_END_REQ | i; | ||||
|             cmd[0] = U_L_DATA_END_REQ | _TxByteCnt; | ||||
| 
 | ||||
|         cmd[1] = bytes[i]; | ||||
|         cmd[1] = _sendBuffer[_TxByteCnt]; | ||||
| 
 | ||||
|         _platform.writeUart(cmd, 2); | ||||
|         _TxByteCnt++; | ||||
|         return true; | ||||
|     } | ||||
|     else{ | ||||
|         _TxByteCnt=0; | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void TpUartDataLinkLayer::sendAck(AddressType type, uint16_t address) | ||||
| { | ||||
|     if ( (type == InduvidualAddress &&  _deviceObject.induvidualAddress() == address)  | ||||
|       || (type == GroupAddress &&  (_groupAddressTable.contains(address) || address == 0))) | ||||
|     { | ||||
|         //send ack. 
 | ||||
|         _platform.writeUart(U_ACK_REQ + 1); | ||||
| 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 | ||||
|     { | ||||
|         // send not addressed
 | ||||
|         _platform.writeUart(U_ACK_REQ); | ||||
|     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; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -3,6 +3,11 @@ | ||||
| #include <stdint.h> | ||||
| #include "data_link_layer.h" | ||||
| 
 | ||||
| #define MAX_KNX_TELEGRAM_SIZE            263 | ||||
| #define BYTE_TIMEOUT                     3           //milli seconds
 | ||||
| #define CONFIRM_TIMEOUT                  500         //milli seconds
 | ||||
| 
 | ||||
| 
 | ||||
| class TpUartDataLinkLayer: public DataLinkLayer | ||||
| { | ||||
|     using DataLinkLayer::_deviceObject; | ||||
| @ -17,25 +22,40 @@ public: | ||||
|     bool enabled() const; | ||||
| private: | ||||
|     bool _enabled = false; | ||||
|     bool _waitConfirm = false; | ||||
|     uint8_t* _sendBuffer = 0; | ||||
|     bool _sendResult = false; | ||||
|     uint16_t _sendBufferLength = 0; | ||||
|     uint8_t _receiveBuffer[MAX_KNX_TELEGRAM_SIZE]; | ||||
|     uint8_t _loopState = 0; | ||||
|     uint16_t _RxByteCnt = 0; | ||||
|     uint16_t _TxByteCnt = 0; | ||||
|     uint8_t _oldIdx = 0; | ||||
|     bool _isEcho = false; | ||||
|     bool _isAddressed = false; | ||||
|     bool _convert = false; | ||||
|     uint8_t _xorSum=0; | ||||
|     uint32_t _lastByteRxTime; | ||||
|     uint32_t _waitConfirmStartTime; | ||||
| 
 | ||||
|     struct _tx_queue_frame_t{ | ||||
|         uint8_t *data; | ||||
|         uint16_t length; | ||||
|         _tx_queue_frame_t *next; | ||||
|     }; | ||||
| 
 | ||||
|     struct _tx_queue_t { | ||||
|       _tx_queue_frame_t *front=NULL; | ||||
|       _tx_queue_frame_t *back=NULL; | ||||
|     }_tx_queue; | ||||
| 
 | ||||
|     void addFrameTxQueue(CemiFrame& frame); | ||||
|     bool isTxQueueEmpty(); | ||||
|     void loadNextTxFrame(); | ||||
|     bool sendSingleFrameByte(); | ||||
|     bool sendFrame(CemiFrame& frame); | ||||
|     bool checkDataInd(uint8_t firstByte); | ||||
|     bool checkDataCon(uint8_t firstByte); | ||||
|     bool checkPollDataInd(uint8_t firstByte); | ||||
|     bool checkAckNackInd(uint8_t firstByte); | ||||
|     bool checkResetInd(uint8_t firstByte); | ||||
|     bool checkStateInd(uint8_t firstByte); | ||||
|     bool checkFrameStateInd(uint8_t firstByte); | ||||
|     bool checkConfigureInd(uint8_t firstByte); | ||||
|     bool checkFrameEndInd(uint8_t firstByte); | ||||
|     bool checkStopModeInd(uint8_t firstByte); | ||||
|     bool checkSystemStatInd(uint8_t firstByte); | ||||
|     void handleUnexpected(uint8_t firstByte); | ||||
|     void sendBytes(uint8_t* buffer, uint16_t length); | ||||
|     void frameBytesReceived(uint8_t* buffer, uint16_t length); | ||||
|     void dataConBytesReceived(uint8_t* buffer, uint16_t length, bool success); | ||||
|     void resetChip(); | ||||
|     void stopChip(); | ||||
|     void sendAck(AddressType type, uint16_t address); | ||||
| }; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user