From 59a76b7c3f8adcbef66287079395a0bee8bbe748 Mon Sep 17 00:00:00 2001 From: Thomas Kunze Date: Sat, 17 Aug 2024 21:30:44 +0200 Subject: [PATCH] frame logging data link layer --- src/knx/apdu.cpp | 6 +- src/knx/apdu.h | 2 +- src/knx/application_layer.cpp | 2 +- src/knx/bits.cpp | 10 ++- src/knx/bits.h | 4 +- src/knx/cemi_frame.cpp | 18 ++++++ src/knx/cemi_frame.h | 2 + src/knx/data_link_layer.cpp | 17 ++--- src/knx/ip/ip_data_link_layer.cpp | 95 +++++++++++++++++----------- src/knx/ip/ip_data_link_layer.h | 8 +-- src/knx/ip/knx_ip_frame.cpp | 86 +++++++++++++++++++++++-- src/knx/ip/knx_ip_frame.h | 8 ++- src/knx/knx_types.cpp | 30 ++++----- src/knx/knx_types.h | 9 ++- src/knx/secure_application_layer.cpp | 12 ++-- 15 files changed, 215 insertions(+), 94 deletions(-) diff --git a/src/knx/apdu.cpp b/src/knx/apdu.cpp index 1800335..e19d8ad 100644 --- a/src/knx/apdu.cpp +++ b/src/knx/apdu.cpp @@ -40,17 +40,17 @@ uint8_t APDU::length() const return _frame.npdu().octetCount(); } -APDU::operator std::string() const +string APDU::to_string() const { string value = "APDU: " + enum_name(type()) + " "; - value += hex(_data[0] & 0x3); + value += byte2hex(_data[0] & 0x3); for (uint8_t i = 1; i < length() + 1; ++i) { if (i) value += " "; - value += hex(_data[i]); + value += byte2hex(_data[i]); } return value; diff --git a/src/knx/apdu.h b/src/knx/apdu.h index 13723b8..2de954a 100644 --- a/src/knx/apdu.h +++ b/src/knx/apdu.h @@ -37,7 +37,7 @@ class APDU /** * Convert APDU to string. */ - operator std::string() const; + std::string to_string() const; protected: /** diff --git a/src/knx/application_layer.cpp b/src/knx/application_layer.cpp index 980486a..06e9e83 100644 --- a/src/knx/application_layer.cpp +++ b/src/knx/application_layer.cpp @@ -1362,7 +1362,7 @@ void ApplicationLayer::individualIndication(HopCountType hopType, Priority prior } default: - LOGGER.warning("Individual-indication: unhandled APDU-Type: %s", ((std::string)apdu).c_str()); + LOGGER.warning("Individual-indication: unhandled APDU-Type: %s", apdu.to_string().c_str()); } } diff --git a/src/knx/bits.cpp b/src/knx/bits.cpp index 3800141..f291f81 100644 --- a/src/knx/bits.cpp +++ b/src/knx/bits.cpp @@ -8,8 +8,8 @@ const uint8_t* popByte(uint8_t& b, const uint8_t* data) return data; } -#ifndef KNX_NO_PRINT -std::string hex(uint8_t byte) + +std::string byte2hex(uint8_t byte) { const char* hex = "0123456789ABCDEF"; char out[3] = {0}; @@ -18,6 +18,12 @@ std::string hex(uint8_t byte) return std::string(out); } +std::string word2hex(uint16_t value) +{ + return byte2hex((uint8_t) (value & 0xFF00) >> 8) + byte2hex((uint8_t) (value & 0xFF)); +} + +#ifndef KNX_NO_PRINT void printHex(const char* suffix, const uint8_t* data, size_t length, bool newline) { print(suffix); diff --git a/src/knx/bits.h b/src/knx/bits.h index d9ee59f..772bf0a 100644 --- a/src/knx/bits.h +++ b/src/knx/bits.h @@ -70,8 +70,10 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode); #endif + std::string byte2hex(uint8_t byte); + std::string word2hex(uint16_t value); + #ifndef KNX_NO_PRINT - std::string hex(uint8_t byte); void print(const char[]); void print(char); void print(unsigned char, int = DEC); diff --git a/src/knx/cemi_frame.cpp b/src/knx/cemi_frame.cpp index 5ac73ea..550f618 100644 --- a/src/knx/cemi_frame.cpp +++ b/src/knx/cemi_frame.cpp @@ -399,3 +399,21 @@ bool CemiFrame::valid() const return true; } + +std::string CemiFrame::to_string() const +{ + std::string value = enum_name(frameType()) + " "; + value += enum_name(systemBroadcast()) + " "; + value += enum_name(ack()) + " "; + value += enum_name(repetition()) + " "; + value += enum_name(priority()) + " from "; + value += format_ia(sourceAddress()) + " to "; + value += enum_name(addressType()) + " "; + + if (addressType() == AddressType::IndividualAddress) + value += format_ia(destinationAddress()); + else + value += format_ga(destinationAddress()); + + return value; +} diff --git a/src/knx/cemi_frame.h b/src/knx/cemi_frame.h index 8ed60de..71fa364 100644 --- a/src/knx/cemi_frame.h +++ b/src/knx/cemi_frame.h @@ -72,6 +72,8 @@ class CemiFrame uint8_t calcCrcTP(uint8_t* buffer, uint16_t len); bool valid() const; + std::string to_string() const; + private: uint8_t buffer[0xff + NPDU_LPDU_DIFF] = {0}; //only valid of add info is zero uint8_t* _data = 0; diff --git a/src/knx/data_link_layer.cpp b/src/knx/data_link_layer.cpp index 41c6658..d64faa1 100644 --- a/src/knx/data_link_layer.cpp +++ b/src/knx/data_link_layer.cpp @@ -160,10 +160,9 @@ void DataLinkLayer::frameReceived(CemiFrame& frame) uint16_t ownAddr = _deviceObject.individualAddress(); SystemBroadcast systemBroadcast = frame.systemBroadcast(); - if (frame.npdu().octetCount() > 0) - { - LOGGER.info("-> %s", ((string)frame.apdu()).c_str()); - } + + LOGGER.info("frameReceived %s", frame.to_string().c_str()); + #ifdef USE_CEMI_SERVER // Do not send our own message back to the tunnel @@ -189,7 +188,7 @@ void DataLinkLayer::frameReceived(CemiFrame& frame) // println(); // print("frameReceived: frame valid? :"); // println(npdu.frame().valid() ? "true" : "false"); - if (source == ownAddr) + if (source == ownAddr) _deviceObject.individualAddressDuplication(true); if (addrType == GroupAddress && destination == 0) @@ -223,6 +222,7 @@ bool DataLinkLayer::sendTelegram(NPDU& npdu, AckType ack, uint16_t destinationAd else frame.frameType(format); + LOGGER.info("sendTelegram %s", frame.to_string().c_str()); if (!frame.valid()) { @@ -230,14 +230,10 @@ bool DataLinkLayer::sendTelegram(NPDU& npdu, AckType ack, uint16_t destinationAd return false; } - if (frame.npdu().octetCount() > 0) - { - LOGGER.info("<- %s", ((string)frame.apdu()).c_str()); - } - bool sendTheFrame = true; bool success = true; + #ifdef KNX_TUNNELING // TunnelOpti // Optimize performance when sending unicast data over tunnel wich is not meant to be used on the physical TP line @@ -253,6 +249,7 @@ bool DataLinkLayer::sendTelegram(NPDU& npdu, AckType ack, uint16_t destinationAd #endif + // The data link layer might be an open media link layer // and will setup rfSerialOrDoA, rfInfo and rfLfn that we also // have to send through the cEMI server tunnel diff --git a/src/knx/ip/ip_data_link_layer.cpp b/src/knx/ip/ip_data_link_layer.cpp index 8b27ddd..32e83a3 100644 --- a/src/knx/ip/ip_data_link_layer.cpp +++ b/src/knx/ip/ip_data_link_layer.cpp @@ -8,8 +8,16 @@ #include "knx_ip_search_response.h" #include "knx_ip_search_request_extended.h" #include "knx_ip_search_response_extended.h" +#include "../util/logger.h" + +const std::string ipaddr2str(const uint32_t addr) +{ + return to_string(addr & 0xFF000000 >> 24) + "." + to_string(addr & 0xFF0000 >> 16) + "." + to_string(addr & 0xFF00 >> 8) + "." + to_string(addr & 0xFF); +} + +#define LOGGER Logger::logger("IpDataLinkLayer") + -#ifdef KNX_TUNNELING #include "knx_ip_connect_request.h" #include "knx_ip_connect_response.h" #include "knx_ip_state_request.h" @@ -21,7 +29,7 @@ #include "knx_ip_description_request.h" #include "knx_ip_description_response.h" #include "knx_ip_config_request.h" -#endif + #include #include @@ -44,7 +52,7 @@ bool IpDataLinkLayer::sendFrame(CemiFrame& frame) if (isSendLimitReached()) return false; - bool success = sendBytes(packet.data(), packet.totalLength()); + bool success = sendMulicast(packet); #ifdef KNX_ACTIVITYCALLBACK if (_dllcb) @@ -55,7 +63,6 @@ bool IpDataLinkLayer::sendFrame(CemiFrame& frame) return success; } -#ifdef KNX_TUNNELING void IpDataLinkLayer::dataRequestToTunnel(CemiFrame& frame) { if (frame.addressType() == AddressType::GroupAddress) @@ -228,7 +235,8 @@ void IpDataLinkLayer::sendFrameToTunnel(KnxIpTunnelConnection* tunnel, CemiFrame if (frame.messageCode() != L_data_req && frame.messageCode() != L_data_con && frame.messageCode() != L_data_ind) req.serviceTypeIdentifier(DeviceConfigurationRequest); - _platform.sendBytesUniCast(tunnel->IpAddress, tunnel->PortData, req.data(), req.totalLength()); + + sendUnicast(tunnel->IpAddress, tunnel->PortData, req); } bool IpDataLinkLayer::isTunnelAddress(uint16_t addr) @@ -262,14 +270,14 @@ bool IpDataLinkLayer::isSentToTunnel(uint16_t address, bool isGrpAddr) return false; } } -#endif + void IpDataLinkLayer::loop() { if (!_enabled) return; -#ifdef KNX_TUNNELING + for (int i = 0; i < KNX_TUNNELING; i++) { @@ -288,7 +296,7 @@ void IpDataLinkLayer::loop() discReq.hpaiCtrl().code(IPV4_UDP); discReq.hpaiCtrl().ipAddress(tunnels[i].IpAddress); discReq.hpaiCtrl().ipPortNumber(tunnels[i].PortCtrl); - _platform.sendBytesUniCast(tunnels[i].IpAddress, tunnels[i].PortCtrl, discReq.data(), discReq.totalLength()); + sendUnicast(tunnels[i].IpAddress, tunnels[i].PortCtrl, discReq); tunnels[i].Reset(); } @@ -296,9 +304,6 @@ void IpDataLinkLayer::loop() } } -#endif - - uint8_t buffer[512]; uint16_t remotePort = 0; uint32_t remoteAddr = 0; @@ -324,6 +329,8 @@ void IpDataLinkLayer::loop() uint16_t code; popWord(code, buffer + 2); + LOGGER.info("loop: %s", enum_name((KnxIpServiceType)code).c_str()); + switch ((KnxIpServiceType)code) { case RoutingIndication: @@ -345,7 +352,7 @@ void IpDataLinkLayer::loop() _dllcb->activity((_netIndex << KNX_ACTIVITYCALLBACK_NET) | (KNX_ACTIVITYCALLBACK_DIR_SEND << KNX_ACTIVITYCALLBACK_DIR) | (KNX_ACTIVITYCALLBACK_IPUNICAST)); #endif - _platform.sendBytesUniCast(hpai.ipAddress(), hpai.ipPortNumber(), searchResponse.data(), searchResponse.totalLength()); + sendUnicast(hpai.ipAddress(), hpai.ipPortNumber(), searchResponse); break; } @@ -355,7 +362,7 @@ void IpDataLinkLayer::loop() break; } -#ifdef KNX_TUNNELING + case ConnectRequest: { @@ -407,11 +414,8 @@ void IpDataLinkLayer::loop() break; } -#endif - default: - print("Unhandled service identifier: "); - println(code, HEX); + LOGGER.warning("Unhandled service identifier: %s", word2hex(code).c_str()); break; } } @@ -545,9 +549,12 @@ void IpDataLinkLayer::loopHandleSearchRequestExtended(uint8_t* buffer, uint16_t { //println("requested MANUFACTURER_DATA but not implemented"); } + #ifdef KNX_TUNNELING + if (searchRequest.requestedDIB(TUNNELING_INFO)) searchResponse.setTunnelingInfo(_ipParameters, _deviceObject, tunnels); + #endif } @@ -557,11 +564,11 @@ void IpDataLinkLayer::loopHandleSearchRequestExtended(uint8_t* buffer, uint16_t return; } - _platform.sendBytesUniCast(searchRequest.hpai().ipAddress(), searchRequest.hpai().ipPortNumber(), searchResponse.data(), searchResponse.totalLength()); + sendUnicast(searchRequest.hpai().ipAddress(), searchRequest.hpai().ipPortNumber(), searchResponse); } -#ifdef KNX_TUNNELING + void IpDataLinkLayer::loopHandleConnectRequest(uint8_t* buffer, uint16_t length, uint32_t& src_addr, uint16_t& src_port) { KnxIpConnectRequest connRequest(buffer, length); @@ -622,7 +629,7 @@ void IpDataLinkLayer::loopHandleConnectRequest(uint8_t* buffer, uint16_t length, println("Only Tunnel/DeviceMgmt Connection ist supported!"); #endif KnxIpConnectResponse connRes(0x00, E_CONNECTION_TYPE); - _platform.sendBytesUniCast(connRequest.hpaiCtrl().ipAddress(), connRequest.hpaiCtrl().ipPortNumber(), connRes.data(), connRes.totalLength()); + sendUnicast(connRequest.hpaiCtrl().ipAddress(), connRequest.hpaiCtrl().ipPortNumber(), connRes); return; } @@ -633,7 +640,7 @@ void IpDataLinkLayer::loopHandleConnectRequest(uint8_t* buffer, uint16_t length, println("Only LinkLayer ist supported!"); #endif KnxIpConnectResponse connRes(0x00, E_TUNNELING_LAYER); - _platform.sendBytesUniCast(connRequest.hpaiCtrl().ipAddress(), connRequest.hpaiCtrl().ipPortNumber(), connRes.data(), connRes.totalLength()); + sendUnicast(connRequest.hpaiCtrl().ipAddress(), connRequest.hpaiCtrl().ipPortNumber(), connRes); return; } @@ -777,7 +784,7 @@ void IpDataLinkLayer::loopHandleConnectRequest(uint8_t* buffer, uint16_t length, discReq.hpaiCtrl().code(IPV4_UDP); discReq.hpaiCtrl().ipAddress(tunnels[firstResAndOccTunnel].IpAddress); discReq.hpaiCtrl().ipPortNumber(tunnels[firstResAndOccTunnel].PortCtrl); - _platform.sendBytesUniCast(tunnels[firstResAndOccTunnel].IpAddress, tunnels[firstResAndOccTunnel].PortCtrl, discReq.data(), discReq.totalLength()); + sendUnicast(tunnels[firstResAndOccTunnel].IpAddress, tunnels[firstResAndOccTunnel].PortCtrl, discReq); tunnels[firstResAndOccTunnel].Reset(); @@ -837,7 +844,7 @@ void IpDataLinkLayer::loopHandleConnectRequest(uint8_t* buffer, uint16_t length, { println("no free tunnel availible"); KnxIpConnectResponse connRes(0x00, E_NO_MORE_CONNECTIONS); - _platform.sendBytesUniCast(connRequest.hpaiCtrl().ipAddress(), connRequest.hpaiCtrl().ipPortNumber(), connRes.data(), connRes.totalLength()); + sendUnicast(connRequest.hpaiCtrl().ipAddress(), connRequest.hpaiCtrl().ipPortNumber(), connRes); return; } @@ -905,7 +912,7 @@ void IpDataLinkLayer::loopHandleConnectRequest(uint8_t* buffer, uint16_t length, KnxIpConnectResponse connRes(_ipParameters, tun->IndividualAddress, 3671, tun->ChannelId, connRequest.cri().type()); - _platform.sendBytesUniCast(tun->IpAddress, tun->PortCtrl, connRes.data(), connRes.totalLength()); + sendUnicast(tun->IpAddress, tun->PortCtrl, connRes); } void IpDataLinkLayer::loopHandleConnectionStateRequest(uint8_t* buffer, uint16_t length) @@ -930,7 +937,7 @@ void IpDataLinkLayer::loopHandleConnectionStateRequest(uint8_t* buffer, uint16_t println(stateRequest.channelId()); #endif KnxIpStateResponse stateRes(0x00, E_CONNECTION_ID); - _platform.sendBytesUniCast(stateRequest.hpaiCtrl().ipAddress(), stateRequest.hpaiCtrl().ipPortNumber(), stateRes.data(), stateRes.totalLength()); + sendUnicast(stateRequest.hpaiCtrl().ipAddress(), stateRequest.hpaiCtrl().ipPortNumber(), stateRes); return; } @@ -941,7 +948,7 @@ void IpDataLinkLayer::loopHandleConnectionStateRequest(uint8_t* buffer, uint16_t tun->lastHeartbeat = millis(); KnxIpStateResponse stateRes(tun->ChannelId, E_NO_ERROR); - _platform.sendBytesUniCast(stateRequest.hpaiCtrl().ipAddress(), stateRequest.hpaiCtrl().ipPortNumber(), stateRes.data(), stateRes.totalLength()); + sendUnicast(stateRequest.hpaiCtrl().ipAddress(), stateRequest.hpaiCtrl().ipPortNumber(), stateRes); } void IpDataLinkLayer::loopHandleDisconnectRequest(uint8_t* buffer, uint16_t length) @@ -971,13 +978,13 @@ void IpDataLinkLayer::loopHandleDisconnectRequest(uint8_t* buffer, uint16_t leng println(discReq.channelId()); #endif KnxIpDisconnectResponse discRes(0x00, E_CONNECTION_ID); - _platform.sendBytesUniCast(discReq.hpaiCtrl().ipAddress(), discReq.hpaiCtrl().ipPortNumber(), discRes.data(), discRes.totalLength()); + sendUnicast(discReq.hpaiCtrl().ipAddress(), discReq.hpaiCtrl().ipPortNumber(), discRes); return; } KnxIpDisconnectResponse discRes(tun->ChannelId, E_NO_ERROR); - _platform.sendBytesUniCast(discReq.hpaiCtrl().ipAddress(), discReq.hpaiCtrl().ipPortNumber(), discRes.data(), discRes.totalLength()); + sendUnicast(discReq.hpaiCtrl().ipAddress(), discReq.hpaiCtrl().ipPortNumber(), discRes); tun->Reset(); } @@ -985,7 +992,7 @@ void IpDataLinkLayer::loopHandleDescriptionRequest(uint8_t* buffer, uint16_t len { KnxIpDescriptionRequest descReq(buffer, length); KnxIpDescriptionResponse descRes(_ipParameters, _deviceObject); - _platform.sendBytesUniCast(descReq.hpaiCtrl().ipAddress(), descReq.hpaiCtrl().ipPortNumber(), descRes.data(), descRes.totalLength()); + sendUnicast(descReq.hpaiCtrl().ipAddress(), descReq.hpaiCtrl().ipPortNumber(), descRes); } void IpDataLinkLayer::loopHandleDeviceConfigurationRequest(uint8_t* buffer, uint16_t length) @@ -1008,7 +1015,7 @@ void IpDataLinkLayer::loopHandleDeviceConfigurationRequest(uint8_t* buffer, uint print("Channel ID nicht gefunden: "); println(confReq.connectionHeader().channelId()); KnxIpStateResponse stateRes(0x00, E_CONNECTION_ID); - _platform.sendBytesUniCast(0, 0, stateRes.data(), stateRes.totalLength()); + sendUnicast(0, 0, stateRes); return; } @@ -1018,7 +1025,7 @@ void IpDataLinkLayer::loopHandleDeviceConfigurationRequest(uint8_t* buffer, uint tunnAck.connectionHeader().channelId(tun->ChannelId); tunnAck.connectionHeader().sequenceCounter(confReq.connectionHeader().sequenceCounter()); tunnAck.connectionHeader().status(E_NO_ERROR); - _platform.sendBytesUniCast(tun->IpAddress, tun->PortData, tunnAck.data(), tunnAck.totalLength()); + sendUnicast(tun->IpAddress, tun->PortData, tunnAck); tun->lastHeartbeat = millis(); _cemiServer->frameReceived(confReq.frame()); @@ -1046,7 +1053,7 @@ void IpDataLinkLayer::loopHandleTunnelingRequest(uint8_t* buffer, uint16_t lengt println(tunnReq.connectionHeader().channelId()); #endif KnxIpStateResponse stateRes(0x00, E_CONNECTION_ID); - _platform.sendBytesUniCast(0, 0, stateRes.data(), stateRes.totalLength()); + sendUnicast(0, 0, stateRes); return; } @@ -1065,7 +1072,7 @@ void IpDataLinkLayer::loopHandleTunnelingRequest(uint8_t* buffer, uint16_t lengt tunnAck.connectionHeader().channelId(tun->ChannelId); tunnAck.connectionHeader().sequenceCounter(tunnReq.connectionHeader().sequenceCounter()); tunnAck.connectionHeader().status(E_NO_ERROR); - _platform.sendBytesUniCast(tun->IpAddress, tun->PortData, tunnAck.data(), tunnAck.totalLength()); + sendUnicast(tun->IpAddress, tun->PortData, tunnAck); return; } else if ((uint8_t)(sequence - 1) != tun->SequenceCounter_R) @@ -1085,7 +1092,7 @@ void IpDataLinkLayer::loopHandleTunnelingRequest(uint8_t* buffer, uint16_t lengt tunnAck.connectionHeader().channelId(tun->ChannelId); tunnAck.connectionHeader().sequenceCounter(tunnReq.connectionHeader().sequenceCounter()); tunnAck.connectionHeader().status(E_NO_ERROR); - _platform.sendBytesUniCast(tun->IpAddress, tun->PortData, tunnAck.data(), tunnAck.totalLength()); + sendUnicast(tun->IpAddress, tun->PortData, tunnAck); tun->SequenceCounter_R = tunnReq.connectionHeader().sequenceCounter(); @@ -1094,7 +1101,7 @@ void IpDataLinkLayer::loopHandleTunnelingRequest(uint8_t* buffer, uint16_t lengt _cemiServer->frameReceived(tunnReq.frame()); } -#endif + void IpDataLinkLayer::enabled(bool value) { @@ -1125,12 +1132,24 @@ DptMedium IpDataLinkLayer::mediumType() const return DptMedium::KNX_IP; } -bool IpDataLinkLayer::sendBytes(uint8_t* bytes, uint16_t length) +bool IpDataLinkLayer::sendMulicast(KnxIpFrame& ipFrame) { if (!_enabled) return false; - return _platform.sendBytesMultiCast(bytes, length); + LOGGER.info("sendMulicast %s", ipFrame.to_string().c_str()); + + return _platform.sendBytesMultiCast(ipFrame.data(), ipFrame.totalLength()); +} + +bool IpDataLinkLayer::sendUnicast(uint32_t addr, uint16_t port, KnxIpFrame& ipFrame) +{ + if (!_enabled) + return false; + + LOGGER.info("sendUnicast to %s:%d %s", ipaddr2str(addr).c_str(), port, ipFrame.to_string().c_str()); + + return _platform.sendBytesMultiCast(ipFrame.data(), ipFrame.totalLength()); } bool IpDataLinkLayer::isSendLimitReached() @@ -1171,7 +1190,7 @@ bool IpDataLinkLayer::isSendLimitReached() if (sum > 50) { - println("Dropping packet due to 50p/s limit"); + LOGGER.warning("Dropping packet due to 50p/s limit"); return true; // drop packet } else diff --git a/src/knx/ip/ip_data_link_layer.h b/src/knx/ip/ip_data_link_layer.h index 85a019b..4588ba2 100644 --- a/src/knx/ip/ip_data_link_layer.h +++ b/src/knx/ip/ip_data_link_layer.h @@ -5,6 +5,7 @@ #include "ip_parameter_object.h" #include "knx_ip_tunnel_connection.h" #include "service_families.h" +#include "knx_ip_frame.h" class IpDataLinkLayer : public DataLinkLayer { @@ -18,13 +19,11 @@ class IpDataLinkLayer : public DataLinkLayer void enabled(bool value); bool enabled() const; DptMedium mediumType() const override; -#ifdef KNX_TUNNELING void dataRequestToTunnel(CemiFrame& frame) override; void dataConfirmationToTunnel(CemiFrame& frame) override; void dataIndicationToTunnel(CemiFrame& frame) override; bool isTunnelAddress(uint16_t addr) override; bool isSentToTunnel(uint16_t address, bool isGrpAddr); -#endif private: bool _enabled = false; @@ -32,7 +31,6 @@ class IpDataLinkLayer : public DataLinkLayer uint8_t _frameCountBase = 0; uint32_t _frameCountTimeBase = 0; bool sendFrame(CemiFrame& frame); -#ifdef KNX_TUNNELING void sendFrameToTunnel(KnxIpTunnelConnection* tunnel, CemiFrame& frame); void loopHandleConnectRequest(uint8_t* buffer, uint16_t length, uint32_t& src_addr, uint16_t& src_port); void loopHandleConnectionStateRequest(uint8_t* buffer, uint16_t length); @@ -40,9 +38,9 @@ class IpDataLinkLayer : public DataLinkLayer void loopHandleDescriptionRequest(uint8_t* buffer, uint16_t length); void loopHandleDeviceConfigurationRequest(uint8_t* buffer, uint16_t length); void loopHandleTunnelingRequest(uint8_t* buffer, uint16_t length); -#endif void loopHandleSearchRequestExtended(uint8_t* buffer, uint16_t length); - bool sendBytes(uint8_t* buffer, uint16_t length); + bool sendMulicast(KnxIpFrame& ipFrame); + bool sendUnicast(uint32_t addr, uint16_t port, KnxIpFrame& ipFrame); bool isSendLimitReached(); IpParameterObject& _ipParameters; DataLinkLayerCallbacks* _dllcb; diff --git a/src/knx/ip/knx_ip_frame.cpp b/src/knx/ip/knx_ip_frame.cpp index 352901f..1a98294 100644 --- a/src/knx/ip/knx_ip_frame.cpp +++ b/src/knx/ip/knx_ip_frame.cpp @@ -33,14 +33,14 @@ void KnxIpFrame::protocolVersion(KnxIpVersion version) _data[1] = (uint8_t)version; } -uint16_t KnxIpFrame::serviceTypeIdentifier() const +KnxIpServiceType KnxIpFrame::serviceTypeIdentifier() const { - return getWord(_data + 2); + return (KnxIpServiceType)getWord(_data + 2); } -void KnxIpFrame::serviceTypeIdentifier(uint16_t identifier) +void KnxIpFrame::serviceTypeIdentifier(KnxIpServiceType identifier) { - pushWord(identifier, _data + 2); + pushWord((uint16_t) identifier, _data + 2); } uint16_t KnxIpFrame::totalLength() const @@ -76,3 +76,81 @@ KnxIpFrame::KnxIpFrame(uint16_t length) protocolVersion(KnxIp1_0); totalLength(length); } + +const std::string KnxIpFrame::to_string() const +{ + return enum_name(protocolVersion()) + " " + enum_name(serviceTypeIdentifier()); +} + +const string enum_name(const KnxIpVersion enum_val) +{ + switch (enum_val) + { + case KnxIp1_0: + return "KnxIp1_0"; + } + + return to_string(enum_val); +} + +const string enum_name(const KnxIpServiceType enum_val) +{ + switch (enum_val) + { + case SearchRequest: + return "SearchRequest"; + + case SearchResponse: + return "SearchResponse"; + + case DescriptionRequest: + return "DescriptionRequest"; + + case DescriptionResponse: + return "DescriptionResponse"; + + case ConnectRequest: + return "ConnectRequest"; + + case ConnectResponse: + return "ConnectResponse"; + + case ConnectionStateRequest: + return "ConnectionStateRequest"; + + case ConnectionStateResponse: + return "ConnectionStateResponse"; + + case DisconnectRequest: + return "DisconnectRequest"; + + case DisconnectResponse: + return "DisconnectResponse"; + + case SearchRequestExt: + return "SearchRequestExt"; + + case SearchResponseExt: + return "SearchResponseExt"; + + case DeviceConfigurationRequest: + return "DeviceConfigurationRequest"; + + case DeviceConfigurationAck: + return "DeviceConfigurationAck"; + + case TunnelingRequest: + return "TunnelingRequest"; + + case TunnelingAck: + return "TunnelingAck"; + + case RoutingIndication: + return "RoutingIndication"; + + case RoutingLostMessage: + return "RoutingLostMessage"; + } + + return to_string(enum_val); +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_frame.h b/src/knx/ip/knx_ip_frame.h index 3f7ab24..17819f7 100644 --- a/src/knx/ip/knx_ip_frame.h +++ b/src/knx/ip/knx_ip_frame.h @@ -8,6 +8,7 @@ enum KnxIpVersion { KnxIp1_0 = 0x10 }; +const string enum_name(const KnxIpVersion enum_val); enum KnxIpServiceType { @@ -30,6 +31,7 @@ enum KnxIpServiceType RoutingIndication = 0x530, RoutingLostMessage = 0x531, }; +const string enum_name(const KnxIpServiceType enum_val); class KnxIpFrame { @@ -41,12 +43,12 @@ class KnxIpFrame void headerLength(uint8_t length); KnxIpVersion protocolVersion() const; void protocolVersion(KnxIpVersion version); - uint16_t serviceTypeIdentifier() const; - void serviceTypeIdentifier(uint16_t identifier); + KnxIpServiceType serviceTypeIdentifier() const; + void serviceTypeIdentifier(KnxIpServiceType identifier); uint16_t totalLength() const; void totalLength(uint16_t length); uint8_t* data(); - + const std::string to_string() const; protected: bool _freeData = false; uint8_t* _data = 0; diff --git a/src/knx/knx_types.cpp b/src/knx/knx_types.cpp index 1f9d033..6049f38 100644 --- a/src/knx/knx_types.cpp +++ b/src/knx/knx_types.cpp @@ -441,29 +441,15 @@ const string enum_name(const SystemBroadcast enum_val) } -const string enum_name_in(Repetition enum_val) +const string enum_name(Repetition enum_val) { switch (enum_val) { case WasRepeated: - return "WasRepeated"; + return "WasRepeated/NoRepetiion"; case WasNotRepeated: - return "WasNotRepeated"; - } - - return to_string(enum_val); -} - -const string enum_name_out(Repetition enum_val) -{ - switch (enum_val) - { - case NoRepetiion: - return "NoRepetiion"; - - case RepetitionAllowed: - return "RepetitionAllowed"; + return "WasNotRepeated/RepetitionAllowed"; } return to_string(enum_val); @@ -704,3 +690,13 @@ const string enum_name(const FrameFormat enum_val) return to_string(enum_val); } + +const string format_ia(uint16_t ia) +{ + return to_string(ia & 0xF000 >> 24) + "/" + to_string(ia & 0x0F00 >> 16) + "/" + to_string(ia & 0x00FF); +} + +const string format_ga(uint16_t ga) +{ + return to_string(ga & 0xF800 >> 23) + "/" + to_string(ga & 0x70 >> 16) + "/" + to_string(ga & 0x00FF); +} diff --git a/src/knx/knx_types.h b/src/knx/knx_types.h index e95ff53..a4be8e9 100644 --- a/src/knx/knx_types.h +++ b/src/knx/knx_types.h @@ -1,5 +1,6 @@ #pragma once #include +#include using namespace std; enum FrameFormat @@ -117,8 +118,7 @@ enum Repetition RepetitionAllowed = 0x20, WasNotRepeated = 0x20, }; -const string enum_name_in(Repetition enum_val); -const string enum_name_out(Repetition enum_val); +const string enum_name(Repetition enum_val); enum SystemBroadcast { @@ -310,4 +310,7 @@ enum LCCONFIG PHYS_IACK_ALL = 0b10000000, PHYS_IACK_NACK = 0b11000000 }; -const string enum_name(const LCCONFIG enum_val); \ No newline at end of file +const string enum_name(const LCCONFIG enum_val); + +const string format_ia(uint16_t ia); +const string format_ga(uint16_t ga); \ No newline at end of file diff --git a/src/knx/secure_application_layer.cpp b/src/knx/secure_application_layer.cpp index 7eab51c..969f5af 100644 --- a/src/knx/secure_application_layer.cpp +++ b/src/knx/secure_application_layer.cpp @@ -660,7 +660,7 @@ void SecureApplicationLayer::sendSyncRequest(uint16_t dstAddr, bool dstAddrIsGro if (secure(request.data() + APDU_LPDU_DIFF, kSecureSyncRequest, _deviceObj.individualAddress(), dstAddr, dstAddrIsGroupAddr, tpci, asdu, sizeof(asdu), secCtrl, systemBcast)) { - LOGGER.info("SyncRequest: %s", ((string)request.apdu()).c_str()); + LOGGER.info("SyncRequest: %s", request.apdu().to_string().c_str()); if (_syncReqBroadcastOutgoing) { @@ -723,7 +723,7 @@ void SecureApplicationLayer::sendSyncResponse(uint16_t dstAddr, bool dstAddrIsGr { _lastSyncRes = millis(); - LOGGER.info("SyncResponse: %s", ((string)response.apdu()).c_str()); + LOGGER.info("SyncResponse: %s", response.apdu().to_string().c_str()); if (_syncReqBroadcastIncoming) { @@ -1063,7 +1063,7 @@ bool SecureApplicationLayer::decrypt(uint8_t* plainApdu, uint16_t plainApduLengt bool SecureApplicationLayer::decodeSecureApdu(APDU& secureApdu, APDU& plainApdu, SecurityControl& secCtrl) { // Decode secure APDU - LOGGER.info("decodeSecureApdu: Secure APDU: %s", ((string)secureApdu).c_str()); + LOGGER.info("decodeSecureApdu: Secure APDU: %s", secureApdu.to_string().c_str()); uint16_t srcAddress = secureApdu.frame().sourceAddress(); uint16_t dstAddress = secureApdu.frame().destinationAddress(); @@ -1085,7 +1085,7 @@ bool SecureApplicationLayer::decodeSecureApdu(APDU& secureApdu, APDU& plainApdu, // We are starting from TPCI octet (including): plainApdu.frame().data()+APDU_LPDU_DIFF if (decrypt(plainApdu.frame().data() + APDU_LPDU_DIFF, plainApdu.length() + 1, srcAddress, dstAddress, isDstAddrGroupAddr, tpci, secureApdu.data() + 1, secCtrl, isSystemBroadcast)) { - LOGGER.info("decodeSecureApdu: Plain APDU: %s", ((string)plainApdu.frame().apdu()).c_str()); + LOGGER.info("decodeSecureApdu: Plain APDU: %s", plainApdu.frame().apdu().to_string().c_str()); return true; } @@ -1260,7 +1260,7 @@ bool SecureApplicationLayer::createSecureApdu(APDU& plainApdu, APDU& secureApdu, { // Create secure APDU - LOGGER.info("createSecureApdu: Plain APDU: %s", ((string)plainApdu.frame().apdu()).c_str()); + LOGGER.info("createSecureApdu: Plain APDU: %s", plainApdu.frame().apdu().to_string().c_str()); uint16_t srcAddress = plainApdu.frame().sourceAddress(); uint16_t dstAddress = plainApdu.frame().destinationAddress(); @@ -1296,7 +1296,7 @@ bool SecureApplicationLayer::createSecureApdu(APDU& plainApdu, APDU& secureApdu, println(nextSequenceNumber(secCtrl.toolAccess), HEX); updateSequenceNumber(secCtrl.toolAccess, nextSequenceNumber(secCtrl.toolAccess) + 1); - LOGGER.info("createSecureApdu: Secure APDU: %s", ((string)secureApdu.frame().apdu()).c_str()); + LOGGER.info("createSecureApdu: Secure APDU: %s", secureApdu.frame().apdu().to_string().c_str()); return true; }