diff --git a/examples/knx-linux-coupler/main.cpp b/examples/knx-linux-coupler/main.cpp index 004215d4..d583b424 100644 --- a/examples/knx-linux-coupler/main.cpp +++ b/examples/knx-linux-coupler/main.cpp @@ -14,6 +14,8 @@ #include "fdsk.h" +using namespace Knx; + volatile sig_atomic_t loopActive = 1; void signalHandler(int sig) { diff --git a/examples/knx-usb/src/main.cpp b/examples/knx-usb/src/main.cpp index f9c01b7c..2320b636 100644 --- a/examples/knx-usb/src/main.cpp +++ b/examples/knx-usb/src/main.cpp @@ -19,16 +19,16 @@ Adafruit_USBD_HID usb_hid; // received data on interrupt OUT endpoint void setReportCallback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* data, uint16_t bufSize) { - // we don't use multiple report and report ID - (void) report_id; - (void) report_type; + // we don't use multiple report and report ID + (void) report_id; + (void) report_type; UsbTunnelInterface::receiveHidReport(data, bufSize); } bool sendHidReport(uint8_t* data, uint16_t length) { - // We do not use reportId of the TinyUSB sendReport()-API here but instead provide it in the first byte of the buffer + // We do not use reportId of the TinyUSB sendReport()-API here but instead provide it in the first byte of the buffer return usb_hid.sendReport(0, data, length); } @@ -68,7 +68,8 @@ void setup(void) usb_hid.begin(); // wait until device mounted - while( !USBDevice.mounted() ) delay(1); + while ( !USBDevice.mounted() ) + delay(1); println("KNX USB Interface enabled."); @@ -76,7 +77,7 @@ void setup(void) knx.readMemory(); if (knx.individualAddress() == 0) - knx.progMode(true); + knx.progMode(true); if (knx.configured()) @@ -101,10 +102,11 @@ void loop(void) knx.loop(); // only run the application code if the device was configured with ETS - if(!knx.configured()) + if (!knx.configured()) return; long now = millis(); + if ((now - lastsend) < 3000) return; @@ -116,11 +118,11 @@ void loop(void) output += ", " + String(temp); output += ", " + String(humi); Serial1.println(output); - + if (sendCounter++ == cyclSend) { sendCounter = 0; - + goTemperature.value(temp); goHumidity.value(humi); } diff --git a/examples/knxPython/knxmodule.cpp b/examples/knxPython/knxmodule.cpp index c774cb41..5e305ecd 100644 --- a/examples/knxPython/knxmodule.cpp +++ b/examples/knxPython/knxmodule.cpp @@ -18,6 +18,7 @@ namespace py = pybind11; #include "knx/platform/linux_platform.h" #include "knx/ip/bau57B0.h" #include "knx/interface_object/group_object_table_object.h" +using namespace Knx; LinuxPlatform* platform = 0; Bau57B0* bau = 0; diff --git a/src/knx.h b/src/knx.h index 59fcc01c..fa4a9830 100644 --- a/src/knx.h +++ b/src/knx.h @@ -246,3 +246,4 @@ knx-->Platform */ #include "knx/knx_facade.h" +using namespace Knx; \ No newline at end of file diff --git a/src/knx/application_layer/apdu.cpp b/src/knx/application_layer/apdu.cpp index 7d483b7c..f0b2295d 100644 --- a/src/knx/application_layer/apdu.cpp +++ b/src/knx/application_layer/apdu.cpp @@ -3,58 +3,63 @@ #include "../datalink_layer/cemi_frame.h" #include "../bits.h" -APDU::APDU(uint8_t* data, CemiFrame& frame): _data(data), _frame(frame) +namespace Knx { -} -ApduType APDU::type() const -{ - uint16_t apci; - apci = getWord(_data); - popWord(apci, _data); - apci &= 0x3ff; + APDU::APDU(uint8_t* data, CemiFrame& frame): _data(data), _frame(frame) + { + } - if ((apci >> 6) < 11 && (apci >> 6) != 7) //short apci - apci &= 0x3c0; + ApduType APDU::type() const + { + uint16_t apci; + apci = getWord(_data); + popWord(apci, _data); + apci &= 0x3ff; - return (ApduType)apci; -} + if ((apci >> 6) < 11 && (apci >> 6) != 7) //short apci + apci &= 0x3c0; -void APDU::type(ApduType atype) -{ - // ApduType is in big endian so convert to host first, pushWord converts back - pushWord((uint16_t)atype, _data); -} + return (ApduType)apci; + } -uint8_t* APDU::data() -{ - return _data + 1; -} + void APDU::type(ApduType atype) + { + // ApduType is in big endian so convert to host first, pushWord converts back + pushWord((uint16_t)atype, _data); + } -CemiFrame& APDU::frame() -{ - return _frame; -} + uint8_t* APDU::data() + { + return _data + 1; + } -uint8_t APDU::length() const -{ - return _frame.npdu().octetCount(); -} + CemiFrame& APDU::frame() + { + return _frame; + } -void APDU::printIt() const -{ -#ifndef KNX_NO_PRINT - print("APDU: "); - print(enum_name(type())); - print(" "); - print(_data[0] & 0x3, HEX); + uint8_t APDU::length() const + { + return _frame.npdu().octetCount(); + } - for (uint8_t i = 1; i < length() + 1; ++i) + void APDU::printIt() const { - if (i) - print(" "); +#ifndef KNX_NO_PRINT + print("APDU: "); + print(enum_name(type())); + print(" "); + print(_data[0] & 0x3, HEX); + + for (uint8_t i = 1; i < length() + 1; ++i) + { + if (i) + print(" "); + + print(_data[i], HEX); + } - print(_data[i], HEX); - } #endif -} + } +} \ No newline at end of file diff --git a/src/knx/application_layer/apdu.h b/src/knx/application_layer/apdu.h index 8d86decb..d68fe183 100644 --- a/src/knx/application_layer/apdu.h +++ b/src/knx/application_layer/apdu.h @@ -5,51 +5,55 @@ #include -class CemiFrame; - -/** - * This class represents an Application Protocol Data Unit. It is part of a CemiFrame. - */ -class APDU : public IPrintable +namespace Knx { - friend class CemiFrame; - - public: - /** - * Get the type of the APDU. - */ - ApduType type() const; - /** - * Set the type of the APDU. - */ - void type(ApduType atype); - /** - * Get a pointer to the data. - */ - uint8_t* data(); - /** - * Get the CemiFrame this APDU is part of. - */ - CemiFrame& frame(); - /** - * Get the length of the APDU. (This is actually the octet count of the NPDU.) - */ - uint8_t length() const; - /** - * print APDU - */ - void printIt() const; - - protected: - /** - * The constructor. - * @param data The data of the APDU. Encoding depends on the ::ApduType. The class doesn't - * take possession of this pointer. - * @param frame The CemiFrame this APDU is part of. - */ - APDU(uint8_t* data, CemiFrame& frame); - - private: - uint8_t* _data = 0; - CemiFrame& _frame; -}; \ No newline at end of file + + class CemiFrame; + + /** + * This class represents an Application Protocol Data Unit. It is part of a CemiFrame. + */ + class APDU : public IPrintable + { + friend class CemiFrame; + + public: + /** + * Get the type of the APDU. + */ + ApduType type() const; + /** + * Set the type of the APDU. + */ + void type(ApduType atype); + /** + * Get a pointer to the data. + */ + uint8_t* data(); + /** + * Get the CemiFrame this APDU is part of. + */ + CemiFrame& frame(); + /** + * Get the length of the APDU. (This is actually the octet count of the NPDU.) + */ + uint8_t length() const; + /** + * print APDU + */ + void printIt() const; + + protected: + /** + * The constructor. + * @param data The data of the APDU. Encoding depends on the ::ApduType. The class doesn't + * take possession of this pointer. + * @param frame The CemiFrame this APDU is part of. + */ + APDU(uint8_t* data, CemiFrame& frame); + + private: + uint8_t* _data = 0; + CemiFrame& _frame; + }; +} \ No newline at end of file diff --git a/src/knx/application_layer/application_layer.cpp b/src/knx/application_layer/application_layer.cpp index 085b97af..de88fc84 100644 --- a/src/knx/application_layer/application_layer.cpp +++ b/src/knx/application_layer/application_layer.cpp @@ -14,1550 +14,1553 @@ #define LOGGER Logger::logger("ApplicationLayer") -const SecurityControl ApplicationLayer::noSecurity +namespace Knx { - .toolAccess = false, .dataSecurity = DataSecurity::None -}; + const SecurityControl ApplicationLayer::noSecurity + { + .toolAccess = false, .dataSecurity = DataSecurity::None + }; -ApplicationLayer::ApplicationLayer(BusAccessUnit& bau) : _bau(bau) -{ -} + ApplicationLayer::ApplicationLayer(BusAccessUnit& bau) : _bau(bau) + { + } -void ApplicationLayer::transportLayer(TransportLayer& layer) -{ - _transportLayer = &layer; -} + void ApplicationLayer::transportLayer(TransportLayer& layer) + { + _transportLayer = &layer; + } -void ApplicationLayer::associationTableObject(AssociationTableObject& assocTable) -{ - _assocTable = &assocTable; -} + void ApplicationLayer::associationTableObject(AssociationTableObject& assocTable) + { + _assocTable = &assocTable; + } -#pragma region TL Callbacks + #pragma region TL Callbacks -void ApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) -{ - dataGroupIndication(hopType, priority, tsap, apdu, noSecurity); -} + void ApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) + { + dataGroupIndication(hopType, priority, tsap, apdu, noSecurity); + } -void ApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) -{ - LOGGER.info("dataGroupIndication ", apdu); + void ApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) + { + LOGGER.info("dataGroupIndication ", apdu); - if (_assocTable == nullptr) - return; + if (_assocTable == nullptr) + return; - uint8_t len = apdu.length(); - uint8_t dataArray[len]; - uint8_t* data = dataArray; - memcpy(data, apdu.data(), len); + uint8_t len = apdu.length(); + uint8_t dataArray[len]; + uint8_t* data = dataArray; + memcpy(data, apdu.data(), len); - if (len == 1) - { - //less than six bit are encoded in first byte - *data &= 0x3f; + if (len == 1) + { + //less than six bit are encoded in first byte + *data &= 0x3f; + } + else + { + data += 1; + len -= 1; + } + + uint16_t startIdx = 0; + int32_t asap = _assocTable->nextAsap(tsap, startIdx); + + for (; asap != -1; asap = _assocTable->nextAsap(tsap, startIdx)) + { + switch (apdu.type()) + { + case GroupValueRead: + _bau.groupValueReadIndication(asap, priority, hopType, secCtrl); + break; + + case GroupValueResponse: + _bau.groupValueReadAppLayerConfirm(asap, priority, hopType, secCtrl, data, len); + break; + + case GroupValueWrite: + _bau.groupValueWriteIndication(asap, priority, hopType, secCtrl, data, len); + + default: + /* other apdutypes are not valid here. If they appear do nothing */ + break; + } + } } - else + + void ApplicationLayer::dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status) { - data += 1; - len -= 1; + dataGroupConfirm(ack, hopType, priority, tsap, apdu, noSecurity, status); } - uint16_t startIdx = 0; - int32_t asap = _assocTable->nextAsap(tsap, startIdx); - - for (; asap != -1; asap = _assocTable->nextAsap(tsap, startIdx)) + void ApplicationLayer::dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl, bool status) { + LOGGER.info("dataGroupConfirm ", apdu); + switch (apdu.type()) { case GroupValueRead: - _bau.groupValueReadIndication(asap, priority, hopType, secCtrl); + if (_savedAsapReadRequest > 0) + _bau.groupValueReadLocalConfirm(ack, _savedAsapReadRequest, priority, hopType, secCtrl, status); + + _savedAsapReadRequest = 0; break; case GroupValueResponse: - _bau.groupValueReadAppLayerConfirm(asap, priority, hopType, secCtrl, data, len); + if (_savedAsapResponse > 0) + _bau.groupValueReadResponseConfirm(ack, _savedAsapResponse, priority, hopType, secCtrl, apdu.data(), apdu.length() - 1, status); + + _savedAsapResponse = 0; break; case GroupValueWrite: - _bau.groupValueWriteIndication(asap, priority, hopType, secCtrl, data, len); + if (_savedAsapWriteRequest > 0) + _bau.groupValueWriteLocalConfirm(ack, _savedAsapWriteRequest, priority, hopType, secCtrl, apdu.data(), apdu.length() - 1, status); - default: - /* other apdutypes are not valid here. If they appear do nothing */ + _savedAsapWriteRequest = 0; break; + + default: + print("datagroup-confirm: unhandled APDU-Type: "); + println(apdu.type()); } } -} - -void ApplicationLayer::dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status) -{ - dataGroupConfirm(ack, hopType, priority, tsap, apdu, noSecurity, status); -} -void ApplicationLayer::dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl, bool status) -{ - LOGGER.info("dataGroupConfirm ", apdu); + void ApplicationLayer::dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) + { + dataBroadcastIndication(hopType, priority, source, apdu, noSecurity); + } - switch (apdu.type()) + void ApplicationLayer::dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl& secCtrl) { - case GroupValueRead: - if (_savedAsapReadRequest > 0) - _bau.groupValueReadLocalConfirm(ack, _savedAsapReadRequest, priority, hopType, secCtrl, status); + LOGGER.info("dataBroadcastIndication ", apdu); + uint8_t* data = apdu.data(); - _savedAsapReadRequest = 0; - break; + switch (apdu.type()) + { + case IndividualAddressWrite: + { + uint16_t newAddress; + popWord(newAddress, data + 1); + _bau.individualAddressWriteIndication(hopType, secCtrl, newAddress); + break; + } - case GroupValueResponse: - if (_savedAsapResponse > 0) - _bau.groupValueReadResponseConfirm(ack, _savedAsapResponse, priority, hopType, secCtrl, apdu.data(), apdu.length() - 1, status); + case IndividualAddressRead: + _bau.individualAddressReadIndication(hopType, secCtrl); + break; - _savedAsapResponse = 0; - break; + case IndividualAddressResponse: + _bau.individualAddressReadAppLayerConfirm(hopType, secCtrl, apdu.frame().sourceAddress()); + break; - case GroupValueWrite: - if (_savedAsapWriteRequest > 0) - _bau.groupValueWriteLocalConfirm(ack, _savedAsapWriteRequest, priority, hopType, secCtrl, apdu.data(), apdu.length() - 1, status); + case IndividualAddressSerialNumberRead: + { + uint8_t* knxSerialNumber = &data[1]; + _bau.individualAddressSerialNumberReadIndication(priority, hopType, secCtrl, knxSerialNumber); + break; + } - _savedAsapWriteRequest = 0; - break; + case IndividualAddressSerialNumberResponse: + { + uint16_t domainAddress; + popWord(domainAddress, data + 7); + _bau.individualAddressSerialNumberReadAppLayerConfirm(hopType, secCtrl, data + 1, apdu.frame().sourceAddress(), + domainAddress); + break; + } - default: - print("datagroup-confirm: unhandled APDU-Type: "); - println(apdu.type()); - } -} + case IndividualAddressSerialNumberWrite: + { + uint8_t* knxSerialNumber = &data[1]; + uint16_t newIndividualAddress; + popWord(newIndividualAddress, &data[7]); + _bau.individualAddressSerialNumberWriteIndication(priority, hopType, secCtrl, newIndividualAddress, knxSerialNumber); + break; + } -void ApplicationLayer::dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) -{ - dataBroadcastIndication(hopType, priority, source, apdu, noSecurity); -} + default: + print("Broadcast-indication: unhandled APDU-Type: "); + println(apdu.type()); + break; + } + } -void ApplicationLayer::dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl& secCtrl) -{ - LOGGER.info("dataBroadcastIndication ", apdu); - uint8_t* data = apdu.data(); + void ApplicationLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, bool status) + { + dataBroadcastConfirm(ack, hopType, priority, apdu, noSecurity, status); + } - switch (apdu.type()) + void ApplicationLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl, bool status) { - case IndividualAddressWrite: + LOGGER.info("dataBroadcastConfirm ", apdu); + uint8_t* data = apdu.data(); + + switch (apdu.type()) { - uint16_t newAddress; - popWord(newAddress, data + 1); - _bau.individualAddressWriteIndication(hopType, secCtrl, newAddress); - break; - } + case IndividualAddressWrite: + { + uint16_t newAddress; + popWord(newAddress, data + 1); + _bau.individualAddressWriteLocalConfirm(ack, hopType, secCtrl, newAddress, status); + break; + } - case IndividualAddressRead: - _bau.individualAddressReadIndication(hopType, secCtrl); - break; + case IndividualAddressRead: + _bau.individualAddressReadLocalConfirm(ack, hopType, secCtrl, status); + break; - case IndividualAddressResponse: - _bau.individualAddressReadAppLayerConfirm(hopType, secCtrl, apdu.frame().sourceAddress()); - break; + case IndividualAddressResponse: + _bau.individualAddressReadResponseConfirm(ack, hopType, secCtrl, status); + break; - case IndividualAddressSerialNumberRead: - { - uint8_t* knxSerialNumber = &data[1]; - _bau.individualAddressSerialNumberReadIndication(priority, hopType, secCtrl, knxSerialNumber); - break; - } + case IndividualAddressSerialNumberRead: + _bau.individualAddressSerialNumberReadLocalConfirm(ack, hopType, secCtrl, data + 1, status); + break; - case IndividualAddressSerialNumberResponse: - { - uint16_t domainAddress; - popWord(domainAddress, data + 7); - _bau.individualAddressSerialNumberReadAppLayerConfirm(hopType, secCtrl, data + 1, apdu.frame().sourceAddress(), - domainAddress); - break; - } + case IndividualAddressSerialNumberResponse: + { + uint16_t domainAddress; + popWord(domainAddress, data + 7); + _bau.individualAddressSerialNumberReadResponseConfirm(ack, hopType, secCtrl, data + 1, domainAddress, status); + break; + } - case IndividualAddressSerialNumberWrite: - { - uint8_t* knxSerialNumber = &data[1]; - uint16_t newIndividualAddress; - popWord(newIndividualAddress, &data[7]); - _bau.individualAddressSerialNumberWriteIndication(priority, hopType, secCtrl, newIndividualAddress, knxSerialNumber); - break; - } + case IndividualAddressSerialNumberWrite: + { + uint16_t newAddress; + popWord(newAddress, data + 7); + _bau.individualAddressSerialNumberWriteLocalConfirm(ack, hopType, secCtrl, data + 1, newAddress, status); + break; + } - default: - print("Broadcast-indication: unhandled APDU-Type: "); - println(apdu.type()); - break; + default: + print("Broadcast-confirm: unhandled APDU-Type: "); + println(apdu.type()); + break; + } } -} -void ApplicationLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, bool status) -{ - dataBroadcastConfirm(ack, hopType, priority, apdu, noSecurity, status); -} - -void ApplicationLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl, bool status) -{ - LOGGER.info("dataBroadcastConfirm ", apdu); - uint8_t* data = apdu.data(); + void ApplicationLayer::dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) + { + dataSystemBroadcastIndication(hopType, priority, source, apdu, noSecurity); + } - switch (apdu.type()) + void ApplicationLayer::dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl& secCtrl) { - case IndividualAddressWrite: - { - uint16_t newAddress; - popWord(newAddress, data + 1); - _bau.individualAddressWriteLocalConfirm(ack, hopType, secCtrl, newAddress, status); - break; - } + LOGGER.info("dataSystemBroadcastIndication ", apdu); + const uint8_t* data = apdu.data(); - case IndividualAddressRead: - _bau.individualAddressReadLocalConfirm(ack, hopType, secCtrl, status); - break; + switch (apdu.type()) + { + // TODO: testInfo could be of any length + case SystemNetworkParameterRead: + { + uint16_t objectType; + uint16_t propertyId; + uint8_t testInfo[2]; + popWord(objectType, data + 1); + popWord(propertyId, data + 3); + popByte(testInfo[0], data + 4); + popByte(testInfo[1], data + 5); + propertyId = (propertyId >> 4) & 0x0FFF;; + testInfo[0] &= 0x0F; + _bau.systemNetworkParameterReadIndication(priority, hopType, secCtrl, objectType, propertyId, testInfo, sizeof(testInfo)); + break; + } - case IndividualAddressResponse: - _bau.individualAddressReadResponseConfirm(ack, hopType, secCtrl, status); - break; + case DomainAddressSerialNumberWrite: + { + const uint8_t* knxSerialNumber = &data[1]; + const uint8_t* domainAddress = &data[7]; + _bau.domainAddressSerialNumberWriteIndication(priority, hopType, secCtrl, domainAddress, knxSerialNumber); + break; + } - case IndividualAddressSerialNumberRead: - _bau.individualAddressSerialNumberReadLocalConfirm(ack, hopType, secCtrl, data + 1, status); - break; + case DomainAddressSerialNumberRead: + { + const uint8_t* knxSerialNumber = &data[1]; + _bau.domainAddressSerialNumberReadIndication(priority, hopType, secCtrl, knxSerialNumber); + break; + } - case IndividualAddressSerialNumberResponse: - { - uint16_t domainAddress; - popWord(domainAddress, data + 7); - _bau.individualAddressSerialNumberReadResponseConfirm(ack, hopType, secCtrl, data + 1, domainAddress, status); - break; + default: + LOGGER.warning("SystemBroadcast-indication: unhandled APDU-Type: %d", apdu.type()); + break; } + } + + void ApplicationLayer::dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, bool status) + { + dataSystemBroadcastConfirm(hopType, priority, apdu, noSecurity, status); + } + + void ApplicationLayer::dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl, bool status) + { + LOGGER.info("dataSystemBroadcastConfirm ", apdu); + const uint8_t* data = apdu.data(); - case IndividualAddressSerialNumberWrite: + switch (apdu.type()) { - uint16_t newAddress; - popWord(newAddress, data + 7); - _bau.individualAddressSerialNumberWriteLocalConfirm(ack, hopType, secCtrl, data + 1, newAddress, status); - break; + // TODO: testInfo could be of any length + case SystemNetworkParameterRead: + { + uint16_t objectType; + uint16_t propertyId; + uint8_t testInfo[2]; + popWord(objectType, data + 1); + popWord(propertyId, data + 3); + popByte(testInfo[0], data + 4); + popByte(testInfo[1], data + 5); + propertyId = (propertyId >> 4) & 0x0FFF;; + testInfo[0] &= 0x0F; + _bau.systemNetworkParameterReadLocalConfirm(priority, hopType, secCtrl, objectType, propertyId, testInfo, sizeof(testInfo), status); + break; + } + + case DomainAddressSerialNumberWrite: + { + const uint8_t* knxSerialNumber = &data[1]; + const uint8_t* domainAddress = &data[7]; + _bau.domainAddressSerialNumberWriteLocalConfirm(priority, hopType, secCtrl, domainAddress, knxSerialNumber, status); + break; + } + + case DomainAddressSerialNumberRead: + { + const uint8_t* knxSerialNumber = &data[1]; + _bau.domainAddressSerialNumberReadLocalConfirm(priority, hopType, secCtrl, knxSerialNumber, status); + break; + } + + default: + print("SystemBroadcast-confirm: unhandled APDU-Type: "); + println(apdu.type()); + break; } + } - default: - print("Broadcast-confirm: unhandled APDU-Type: "); - println(apdu.type()); - break; + void ApplicationLayer::dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) + { + dataIndividualIndication(hopType, priority, source, apdu, noSecurity); } -} -void ApplicationLayer::dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) -{ - dataSystemBroadcastIndication(hopType, priority, source, apdu, noSecurity); -} + void ApplicationLayer::dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) + { + individualIndication(hopType, priority, tsap, apdu, secCtrl); + } -void ApplicationLayer::dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl& secCtrl) -{ - LOGGER.info("dataSystemBroadcastIndication ", apdu); - const uint8_t* data = apdu.data(); + void ApplicationLayer::dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status) + { + dataIndividualConfirm(ack, hopType, priority, tsap, apdu, noSecurity, status); + } - switch (apdu.type()) + void ApplicationLayer::dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl, bool status) { - // TODO: testInfo could be of any length - case SystemNetworkParameterRead: - { - uint16_t objectType; - uint16_t propertyId; - uint8_t testInfo[2]; - popWord(objectType, data + 1); - popWord(propertyId, data + 3); - popByte(testInfo[0], data + 4); - popByte(testInfo[1], data + 5); - propertyId = (propertyId >> 4) & 0x0FFF;; - testInfo[0] &= 0x0F; - _bau.systemNetworkParameterReadIndication(priority, hopType, secCtrl, objectType, propertyId, testInfo, sizeof(testInfo)); - break; - } + individualConfirm(ack, hopType, priority, tsap, apdu, secCtrl, status); + } - case DomainAddressSerialNumberWrite: - { - const uint8_t* knxSerialNumber = &data[1]; - const uint8_t* domainAddress = &data[7]; - _bau.domainAddressSerialNumberWriteIndication(priority, hopType, secCtrl, domainAddress, knxSerialNumber); - break; - } + void ApplicationLayer::connectIndication(uint16_t tsap) + { + _connectedTsap = tsap; + } - case DomainAddressSerialNumberRead: + void ApplicationLayer::connectConfirm(uint16_t destination, uint16_t tsap, bool status) + { + if (status) { - const uint8_t* knxSerialNumber = &data[1]; - _bau.domainAddressSerialNumberReadIndication(priority, hopType, secCtrl, knxSerialNumber); - break; + _connectedTsap = tsap; + _bau.connectConfirm(tsap); } - - default: - LOGGER.warning("SystemBroadcast-indication: unhandled APDU-Type: %d", apdu.type()); - break; + else + _connectedTsap = -1; } -} -void ApplicationLayer::dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, bool status) -{ - dataSystemBroadcastConfirm(hopType, priority, apdu, noSecurity, status); -} + void ApplicationLayer::disconnectIndication(uint16_t tsap) + { + _connectedTsap = -1; + } -void ApplicationLayer::dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl, bool status) -{ - LOGGER.info("dataSystemBroadcastConfirm ", apdu); - const uint8_t* data = apdu.data(); + void ApplicationLayer::disconnectConfirm(Priority priority, uint16_t tsap, bool status) + { + _connectedTsap = -1; + } - switch (apdu.type()) + void ApplicationLayer::dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu) { - // TODO: testInfo could be of any length - case SystemNetworkParameterRead: - { - uint16_t objectType; - uint16_t propertyId; - uint8_t testInfo[2]; - popWord(objectType, data + 1); - popWord(propertyId, data + 3); - popByte(testInfo[0], data + 4); - popByte(testInfo[1], data + 5); - propertyId = (propertyId >> 4) & 0x0FFF;; - testInfo[0] &= 0x0F; - _bau.systemNetworkParameterReadLocalConfirm(priority, hopType, secCtrl, objectType, propertyId, testInfo, sizeof(testInfo), status); - break; - } + dataConnectedIndication(priority, tsap, apdu, noSecurity); + } - case DomainAddressSerialNumberWrite: - { - const uint8_t* knxSerialNumber = &data[1]; - const uint8_t* domainAddress = &data[7]; - _bau.domainAddressSerialNumberWriteLocalConfirm(priority, hopType, secCtrl, domainAddress, knxSerialNumber, status); - break; - } + void ApplicationLayer::dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) + { + individualIndication(NetworkLayerParameter, priority, tsap, apdu, secCtrl); + } - case DomainAddressSerialNumberRead: - { - const uint8_t* knxSerialNumber = &data[1]; - _bau.domainAddressSerialNumberReadLocalConfirm(priority, hopType, secCtrl, knxSerialNumber, status); - break; - } + void ApplicationLayer::dataConnectedConfirm(uint16_t tsap) + { + dataConnectedConfirm(tsap, noSecurity); + } - default: - print("SystemBroadcast-confirm: unhandled APDU-Type: "); - println(apdu.type()); - break; + void ApplicationLayer::dataConnectedConfirm(uint16_t tsap, const SecurityControl& secCtrl) + { + //FIXME: implement dataConnectedConfirm DataSecurity } -} + #pragma endregion + void ApplicationLayer::groupValueReadRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl) + { + if (_assocTable == nullptr) + return; -void ApplicationLayer::dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) -{ - dataIndividualIndication(hopType, priority, source, apdu, noSecurity); -} + _savedAsapReadRequest = asap; + CemiFrame frame(1); + APDU& apdu = frame.apdu(); + apdu.type(GroupValueRead); -void ApplicationLayer::dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) -{ - individualIndication(hopType, priority, tsap, apdu, secCtrl); -} + int32_t value = _assocTable->translateAsap(asap); -void ApplicationLayer::dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status) -{ - dataIndividualConfirm(ack, hopType, priority, tsap, apdu, noSecurity, status); -} + if (value < 0) + return; // there is no tsap in association table for this asap -void ApplicationLayer::dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl, bool status) -{ - individualConfirm(ack, hopType, priority, tsap, apdu, secCtrl, status); -} + uint16_t tsap = (uint16_t)value; -void ApplicationLayer::connectIndication(uint16_t tsap) -{ - _connectedTsap = tsap; -} + // first to bus then to itself + dataGroupRequest(ack, hopType, priority, tsap, apdu, secCtrl); + dataGroupIndication(hopType, priority, tsap, apdu, secCtrl); + } -void ApplicationLayer::connectConfirm(uint16_t destination, uint16_t tsap, bool status) -{ - if (status) + void ApplicationLayer::groupValueReadResponse(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength) { - _connectedTsap = tsap; - _bau.connectConfirm(tsap); + _savedAsapResponse = asap; + groupValueSend(GroupValueResponse, ack, asap, priority, hopType, secCtrl, data, dataLength); } - else - _connectedTsap = -1; -} -void ApplicationLayer::disconnectIndication(uint16_t tsap) -{ - _connectedTsap = -1; -} + void ApplicationLayer::groupValueWriteRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength) + { + _savedAsapWriteRequest = asap; + groupValueSend(GroupValueWrite, ack, asap, priority, hopType, secCtrl, data, dataLength); + } -void ApplicationLayer::disconnectConfirm(Priority priority, uint16_t tsap, bool status) -{ - _connectedTsap = -1; -} + void ApplicationLayer::individualAddressWriteRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress) + { + CemiFrame frame(3); + APDU& apdu = frame.apdu(); + apdu.type(IndividualAddressWrite); + uint8_t* apduData = apdu.data(); + pushWord(newaddress, apduData + 1); + dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); + } -void ApplicationLayer::dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu) -{ - dataConnectedIndication(priority, tsap, apdu, noSecurity); -} + void ApplicationLayer::individualAddressReadRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl) + { + CemiFrame frame(1); + APDU& apdu = frame.apdu(); + apdu.type(IndividualAddressRead); + dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); + } -void ApplicationLayer::dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) -{ - individualIndication(NetworkLayerParameter, priority, tsap, apdu, secCtrl); -} + void ApplicationLayer::individualAddressReadResponse(AckType ack, HopCountType hopType, const SecurityControl& secCtrl) + { + CemiFrame frame(1); + APDU& apdu = frame.apdu(); + apdu.type(IndividualAddressResponse); + dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); + } -void ApplicationLayer::dataConnectedConfirm(uint16_t tsap) -{ - dataConnectedConfirm(tsap, noSecurity); -} + void ApplicationLayer::individualAddressSerialNumberReadRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber) + { + CemiFrame frame(7); + APDU& apdu = frame.apdu(); + apdu.type(IndividualAddressSerialNumberRead); + uint8_t* data = apdu.data() + 1; + memcpy(data, serialNumber, 6); + dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); + } -void ApplicationLayer::dataConnectedConfirm(uint16_t tsap, const SecurityControl& secCtrl) -{ - //FIXME: implement dataConnectedConfirm DataSecurity -} -#pragma endregion -void ApplicationLayer::groupValueReadRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl) -{ - if (_assocTable == nullptr) - return; + void ApplicationLayer::individualAddressSerialNumberReadResponse(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, + uint8_t* serialNumber, uint16_t domainAddress) + { + CemiFrame frame(7); + APDU& apdu = frame.apdu(); + apdu.type(IndividualAddressSerialNumberResponse); + uint8_t* data = apdu.data() + 1; + memcpy(data, serialNumber, 6); + data += 6; + pushWord(domainAddress, data); + dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); + } - _savedAsapReadRequest = asap; - CemiFrame frame(1); - APDU& apdu = frame.apdu(); - apdu.type(GroupValueRead); + void ApplicationLayer::individualAddressSerialNumberWriteRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, + uint16_t newaddress) + { + CemiFrame frame(13); + APDU& apdu = frame.apdu(); + apdu.type(IndividualAddressSerialNumberWrite); + uint8_t* data = apdu.data() + 1; + memcpy(data, serialNumber, 6); + data += 6; + pushWord(newaddress, data); + dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); + } - int32_t value = _assocTable->translateAsap(asap); + void ApplicationLayer::deviceDescriptorReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t descriptorType) + { + CemiFrame frame(1); + APDU& apdu = frame.apdu(); + apdu.type(DeviceDescriptorRead); + uint8_t* data = apdu.data(); + *data |= (descriptorType & 0x3f); - if (value < 0) - return; // there is no tsap in association table for this asap + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } - uint16_t tsap = (uint16_t)value; + void ApplicationLayer::deviceDescriptorReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t descriptorType, uint8_t* deviceDescriptor) + { + uint8_t length = 0; - // first to bus then to itself - dataGroupRequest(ack, hopType, priority, tsap, apdu, secCtrl); - dataGroupIndication(hopType, priority, tsap, apdu, secCtrl); -} + switch (descriptorType) + { + case 0: + length = 3; + break; -void ApplicationLayer::groupValueReadResponse(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength) -{ - _savedAsapResponse = asap; - groupValueSend(GroupValueResponse, ack, asap, priority, hopType, secCtrl, data, dataLength); -} + case 2: + length = 14; + break; -void ApplicationLayer::groupValueWriteRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength) -{ - _savedAsapWriteRequest = asap; - groupValueSend(GroupValueWrite, ack, asap, priority, hopType, secCtrl, data, dataLength); -} + default: + length = 1; + descriptorType = 0x3f; + break; + } -void ApplicationLayer::individualAddressWriteRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress) -{ - CemiFrame frame(3); - APDU& apdu = frame.apdu(); - apdu.type(IndividualAddressWrite); - uint8_t* apduData = apdu.data(); - pushWord(newaddress, apduData + 1); - dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); -} - -void ApplicationLayer::individualAddressReadRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl) -{ - CemiFrame frame(1); - APDU& apdu = frame.apdu(); - apdu.type(IndividualAddressRead); - dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); -} + CemiFrame frame(length); + APDU& apdu = frame.apdu(); + apdu.type(DeviceDescriptorResponse); + uint8_t* data = apdu.data(); + *data |= (descriptorType & 0x3f); -void ApplicationLayer::individualAddressReadResponse(AckType ack, HopCountType hopType, const SecurityControl& secCtrl) -{ - CemiFrame frame(1); - APDU& apdu = frame.apdu(); - apdu.type(IndividualAddressResponse); - dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); -} + if (length > 1) + memcpy(data + 1, deviceDescriptor, length - 1); -void ApplicationLayer::individualAddressSerialNumberReadRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber) -{ - CemiFrame frame(7); - APDU& apdu = frame.apdu(); - apdu.type(IndividualAddressSerialNumberRead); - uint8_t* data = apdu.data() + 1; - memcpy(data, serialNumber, 6); - dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); -} - -void ApplicationLayer::individualAddressSerialNumberReadResponse(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, - uint8_t* serialNumber, uint16_t domainAddress) -{ - CemiFrame frame(7); - APDU& apdu = frame.apdu(); - apdu.type(IndividualAddressSerialNumberResponse); - uint8_t* data = apdu.data() + 1; - memcpy(data, serialNumber, 6); - data += 6; - pushWord(domainAddress, data); - dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); -} - -void ApplicationLayer::individualAddressSerialNumberWriteRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, - uint16_t newaddress) -{ - CemiFrame frame(13); - APDU& apdu = frame.apdu(); - apdu.type(IndividualAddressSerialNumberWrite); - uint8_t* data = apdu.data() + 1; - memcpy(data, serialNumber, 6); - data += 6; - pushWord(newaddress, data); - dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); -} - -void ApplicationLayer::deviceDescriptorReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t descriptorType) -{ - CemiFrame frame(1); - APDU& apdu = frame.apdu(); - apdu.type(DeviceDescriptorRead); - uint8_t* data = apdu.data(); - *data |= (descriptorType & 0x3f); + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} + void ApplicationLayer::connectRequest(uint16_t destination, Priority priority) + { + _transportLayer->connectRequest(destination, priority); + } -void ApplicationLayer::deviceDescriptorReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t descriptorType, uint8_t* deviceDescriptor) -{ - uint8_t length = 0; + void ApplicationLayer::disconnectRequest(Priority priority) + { + _transportLayer->disconnectRequest(_connectedTsap, priority); + } - switch (descriptorType) + void ApplicationLayer::restartRequest(AckType ack, Priority priority, HopCountType hopType, const SecurityControl& secCtrl) { - case 0: - length = 3; - break; + CemiFrame frame(1); + APDU& apdu = frame.apdu(); + apdu.type(Restart); - case 2: - length = 14; - break; + individualSend(ack, hopType, priority, _connectedTsap, apdu, secCtrl); + } - default: - length = 1; - descriptorType = 0x3f; - break; + void ApplicationLayer::restartResponse(AckType ack, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t errorCode, uint16_t processTime) + { + CemiFrame frame(4); + APDU& apdu = frame.apdu(); + apdu.type(Restart); + uint8_t* data = apdu.data(); + data[0] |= (1 << 5) | 1; // Set response bit and a restart type of "master reset". Only the master reset sends a response. + data[1] = errorCode; + data[2] = processTime >> 8; + data[3] = processTime & 0xFF; + + individualSend(ack, hopType, priority, _connectedTsap, apdu, secCtrl); } - CemiFrame frame(length); - APDU& apdu = frame.apdu(); - apdu.type(DeviceDescriptorResponse); - uint8_t* data = apdu.data(); - *data |= (descriptorType & 0x3f); + //TODO: ApplicationLayer::systemNetworkParameterReadRequest() + void ApplicationLayer::systemNetworkParameterReadResponse(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, + uint16_t objectType, uint16_t propertyId, + uint8_t* testInfo, uint16_t testInfoLength, + uint8_t* testResult, uint16_t testResultLength) + { + CemiFrame frame(testInfoLength + testResultLength + 3 + 1); // PID and testInfo share an octet (+3) and +1 for APCI byte(?) + APDU& apdu = frame.apdu(); + apdu.type(SystemNetworkParameterResponse); + uint8_t* data = apdu.data() + 1; - if (length > 1) - memcpy(data + 1, deviceDescriptor, length - 1); + pushWord(objectType, data); + pushWord((propertyId << 4) & 0xFFF0, data + 2); // Reserved bits for test_info are always 0 + uint8_t* pData = pushByteArray(&testInfo[1], testInfoLength - 1, data + 4); // TODO: upper reserved bits (testInfo + 0) have to put into the lower bits of data + 3 + memcpy(pData, testResult, testResultLength); - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} + //apdu.printPDU(); -void ApplicationLayer::connectRequest(uint16_t destination, Priority priority) -{ - _transportLayer->connectRequest(destination, priority); -} + dataSystemBroadcastRequest(AckDontCare, hopType, SystemPriority, apdu, secCtrl); + } -void ApplicationLayer::disconnectRequest(Priority priority) -{ - _transportLayer->disconnectRequest(_connectedTsap, priority); -} + //TODO: ApplicationLayer::domainAddressSerialNumberWriteRequest() + //TODO: ApplicationLayer::domainAddressSerialNumberReadRequest() + void ApplicationLayer::domainAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, + const uint8_t* knxSerialNumber) + { + CemiFrame frame(13); + APDU& apdu = frame.apdu(); + apdu.type(DomainAddressSerialNumberResponse); -void ApplicationLayer::restartRequest(AckType ack, Priority priority, HopCountType hopType, const SecurityControl& secCtrl) -{ - CemiFrame frame(1); - APDU& apdu = frame.apdu(); - apdu.type(Restart); + uint8_t* data = apdu.data() + 1; - individualSend(ack, hopType, priority, _connectedTsap, apdu, secCtrl); -} + memcpy(data, knxSerialNumber, 6); + memcpy(data + 6, rfDoA, 6); -void ApplicationLayer::restartResponse(AckType ack, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t errorCode, uint16_t processTime) -{ - CemiFrame frame(4); - APDU& apdu = frame.apdu(); - apdu.type(Restart); - uint8_t* data = apdu.data(); - data[0] |= (1 << 5) | 1; // Set response bit and a restart type of "master reset". Only the master reset sends a response. - data[1] = errorCode; - data[2] = processTime >> 8; - data[3] = processTime & 0xFF; - - individualSend(ack, hopType, priority, _connectedTsap, apdu, secCtrl); -} - -//TODO: ApplicationLayer::systemNetworkParameterReadRequest() -void ApplicationLayer::systemNetworkParameterReadResponse(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, - uint16_t objectType, uint16_t propertyId, - uint8_t* testInfo, uint16_t testInfoLength, - uint8_t* testResult, uint16_t testResultLength) -{ - CemiFrame frame(testInfoLength + testResultLength + 3 + 1); // PID and testInfo share an octet (+3) and +1 for APCI byte(?) - APDU& apdu = frame.apdu(); - apdu.type(SystemNetworkParameterResponse); - uint8_t* data = apdu.data() + 1; + //apdu.printPDU(); - pushWord(objectType, data); - pushWord((propertyId << 4) & 0xFFF0, data + 2); // Reserved bits for test_info are always 0 - uint8_t* pData = pushByteArray(&testInfo[1], testInfoLength - 1, data + 4); // TODO: upper reserved bits (testInfo + 0) have to put into the lower bits of data + 3 - memcpy(pData, testResult, testResultLength); + dataSystemBroadcastRequest(AckDontCare, hopType, SystemPriority, apdu, secCtrl); + } - //apdu.printPDU(); + //TODO: ApplicationLayer::IndividualAddressSerialNumberWriteRequest() + //TODO: ApplicationLayer::IndividualAddressSerialNumberReadRequest() + void ApplicationLayer::IndividualAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* domainAddress, + const uint8_t* knxSerialNumber) + { + CemiFrame frame(11); + APDU& apdu = frame.apdu(); + apdu.type(IndividualAddressSerialNumberResponse); - dataSystemBroadcastRequest(AckDontCare, hopType, SystemPriority, apdu, secCtrl); -} + uint8_t* data = apdu.data() + 1; -//TODO: ApplicationLayer::domainAddressSerialNumberWriteRequest() -//TODO: ApplicationLayer::domainAddressSerialNumberReadRequest() -void ApplicationLayer::domainAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, - const uint8_t* knxSerialNumber) -{ - CemiFrame frame(13); - APDU& apdu = frame.apdu(); - apdu.type(DomainAddressSerialNumberResponse); + memcpy(data, knxSerialNumber, 6); + memcpy(data + 6, domainAddress, 2); - uint8_t* data = apdu.data() + 1; + //apdu.printPDU(); - memcpy(data, knxSerialNumber, 6); - memcpy(data + 6, rfDoA, 6); + dataBroadcastRequest(AckDontCare, hopType, SystemPriority, apdu, secCtrl); + } - //apdu.printPDU(); + void ApplicationLayer::propertyValueReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) + { + CemiFrame frame(5); + APDU& apdu = frame.apdu(); + apdu.type(PropertyValueRead); + uint8_t* data = apdu.data(); + data += 1; + data = pushByte(objectIndex, data); + data = pushByte(propertyId, data); + pushWord(startIndex & 0xfff, data); + *data &= ((numberOfElements & 0xf) << 4); - dataSystemBroadcastRequest(AckDontCare, hopType, SystemPriority, apdu, secCtrl); -} + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } -//TODO: ApplicationLayer::IndividualAddressSerialNumberWriteRequest() -//TODO: ApplicationLayer::IndividualAddressSerialNumberReadRequest() -void ApplicationLayer::IndividualAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* domainAddress, - const uint8_t* knxSerialNumber) -{ - CemiFrame frame(11); - APDU& apdu = frame.apdu(); - apdu.type(IndividualAddressSerialNumberResponse); + void ApplicationLayer::propertyValueReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) + { + propertyDataSend(PropertyValueResponse, ack, priority, hopType, asap, secCtrl, objectIndex, propertyId, numberOfElements, + startIndex, data, length); + } - uint8_t* data = apdu.data() + 1; + void ApplicationLayer::propertyValueExtReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) + { + propertyExtDataSend(PropertyValueExtResponse, ack, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, numberOfElements, + startIndex, data, length); + } - memcpy(data, knxSerialNumber, 6); - memcpy(data + 6, domainAddress, 2); + void ApplicationLayer::propertyValueExtWriteConResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t returnCode) + { + uint8_t noOfElem = (returnCode != ReturnCodes::Success) ? 0 : numberOfElements; + propertyExtDataSend(PropertyValueExtWriteConResponse, ack, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, noOfElem, + startIndex, &returnCode, 1); + } - //apdu.printPDU(); + void ApplicationLayer::propertyValueWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) + { + propertyDataSend(PropertyValueWrite, ack, priority, hopType, asap, secCtrl, objectIndex, propertyId, numberOfElements, + startIndex, data, length); + } - dataBroadcastRequest(AckDontCare, hopType, SystemPriority, apdu, secCtrl); -} + void ApplicationLayer::adcReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t channelNr, uint8_t readCount, int16_t value) + { + CemiFrame frame(4); + APDU& apdu = frame.apdu(); + apdu.type(ADCResponse); + uint8_t* data = apdu.data(); + + data[0] |= (channelNr & 0b111111); + data[1] = readCount; + data[2] = value >> 8; + data[3] = value & 0xFF; + + if (asap == _connectedTsap) + dataConnectedRequest(asap, priority, apdu, secCtrl); + else + dataIndividualRequest(ack, hopType, priority, asap, apdu, secCtrl); + } -void ApplicationLayer::propertyValueReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) -{ - CemiFrame frame(5); - APDU& apdu = frame.apdu(); - apdu.type(PropertyValueRead); - uint8_t* data = apdu.data(); - data += 1; - data = pushByte(objectIndex, data); - data = pushByte(propertyId, data); - pushWord(startIndex & 0xfff, data); - *data &= ((numberOfElements & 0xf) << 4); - - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} - -void ApplicationLayer::propertyValueReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) -{ - propertyDataSend(PropertyValueResponse, ack, priority, hopType, asap, secCtrl, objectIndex, propertyId, numberOfElements, - startIndex, data, length); -} + void ApplicationLayer::functionPropertyStateResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t* resultData, uint8_t resultLength) + { + CemiFrame frame(3 + resultLength); + APDU& apdu = frame.apdu(); + apdu.type(FunctionPropertyStateResponse); + uint8_t* data = apdu.data() + 1; -void ApplicationLayer::propertyValueExtReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) -{ - propertyExtDataSend(PropertyValueExtResponse, ack, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, numberOfElements, - startIndex, data, length); -} + data[0] = objectIndex; + data[1] = propertyId; -void ApplicationLayer::propertyValueExtWriteConResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t returnCode) -{ - uint8_t noOfElem = (returnCode != ReturnCodes::Success) ? 0 : numberOfElements; - propertyExtDataSend(PropertyValueExtWriteConResponse, ack, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, noOfElem, - startIndex, &returnCode, 1); -} + if (resultLength > 0) + memcpy(&data[2], resultData, resultLength); -void ApplicationLayer::propertyValueWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) -{ - propertyDataSend(PropertyValueWrite, ack, priority, hopType, asap, secCtrl, objectIndex, propertyId, numberOfElements, - startIndex, data, length); -} + if (asap == _connectedTsap) + dataConnectedRequest(asap, priority, apdu, secCtrl); + else + dataIndividualRequest(ack, hopType, priority, asap, apdu, secCtrl); + } -void ApplicationLayer::adcReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t channelNr, uint8_t readCount, int16_t value) -{ - CemiFrame frame(4); - APDU& apdu = frame.apdu(); - apdu.type(ADCResponse); - uint8_t* data = apdu.data(); - - data[0] |= (channelNr & 0b111111); - data[1] = readCount; - data[2] = value >> 8; - data[3] = value & 0xFF; - - if (asap == _connectedTsap) - dataConnectedRequest(asap, priority, apdu, secCtrl); - else - dataIndividualRequest(ack, hopType, priority, asap, apdu, secCtrl); -} - -void ApplicationLayer::functionPropertyStateResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t* resultData, uint8_t resultLength) -{ - CemiFrame frame(3 + resultLength); - APDU& apdu = frame.apdu(); - apdu.type(FunctionPropertyStateResponse); - uint8_t* data = apdu.data() + 1; + void ApplicationLayer::functionPropertyExtStateResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint16_t objectType, uint8_t objectInstance, uint16_t propertyId, uint8_t* resultData, uint8_t resultLength) + { + CemiFrame frame(5 + resultLength + 1); + APDU& apdu = frame.apdu(); + apdu.type(FunctionPropertyExtStateResponse); + uint8_t* data = apdu.data() + 1; + + data[0] = ((uint16_t)objectType) >> 8; + data[1] = ((uint16_t)objectType) & 0xFF; + data[2] = objectInstance >> 4; + data[3] = ((objectInstance & 0x0F) << 4) | (propertyId >> 8); + data[4] = (propertyId & 0xFF); + + // data[5] must contain the return code + if (resultLength > 0) + memcpy(&data[5], resultData, resultLength); + + if (asap == _connectedTsap) + dataConnectedRequest(asap, priority, apdu, secCtrl); + else + dataIndividualRequest(ack, hopType, priority, asap, apdu, secCtrl); + } - data[0] = objectIndex; - data[1] = propertyId; + void ApplicationLayer::propertyDescriptionReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex) + { + CemiFrame frame(4); + APDU& apdu = frame.apdu(); + apdu.type(PropertyDescriptionRead); + uint8_t* data = apdu.data(); + data[1] = objectIndex; + data[2] = propertyId; + data[3] = propertyIndex; + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } - if (resultLength > 0) - memcpy(&data[2], resultData, resultLength); + void ApplicationLayer::propertyDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, + uint16_t maxNumberOfElements, uint8_t access) + { + CemiFrame frame(8); + APDU& apdu = frame.apdu(); + apdu.type(PropertyDescriptionResponse); + uint8_t* data = apdu.data(); + data[1] = objectIndex; + data[2] = propertyId; + data[3] = propertyIndex; + + if (writeEnable) + data[4] |= 0x80; + + data[4] |= (type & 0x3f); + pushWord(maxNumberOfElements & 0xfff, data + 5); + data[7] = access; + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } - if (asap == _connectedTsap) - dataConnectedRequest(asap, priority, apdu, secCtrl); - else - dataIndividualRequest(ack, hopType, priority, asap, apdu, secCtrl); -} + void ApplicationLayer::propertyExtDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint16_t objectType, uint16_t objectInstance, uint16_t propertyId, uint16_t propertyIndex, uint8_t descriptionType, bool writeEnable, uint8_t type, + uint16_t maxNumberOfElements, uint8_t access) + { + CemiFrame frame(16); + APDU& apdu = frame.apdu(); + apdu.type(PropertyExtDescriptionResponse); + uint8_t* data = apdu.data(); -void ApplicationLayer::functionPropertyExtStateResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint16_t objectType, uint8_t objectInstance, uint16_t propertyId, uint8_t* resultData, uint8_t resultLength) -{ - CemiFrame frame(5 + resultLength + 1); - APDU& apdu = frame.apdu(); - apdu.type(FunctionPropertyExtStateResponse); - uint8_t* data = apdu.data() + 1; - - data[0] = ((uint16_t)objectType) >> 8; - data[1] = ((uint16_t)objectType) & 0xFF; - data[2] = objectInstance >> 4; - data[3] = ((objectInstance & 0x0F) << 4) | (propertyId >> 8); - data[4] = (propertyId & 0xFF); - - // data[5] must contain the return code - if (resultLength > 0) - memcpy(&data[5], resultData, resultLength); - - if (asap == _connectedTsap) - dataConnectedRequest(asap, priority, apdu, secCtrl); - else - dataIndividualRequest(ack, hopType, priority, asap, apdu, secCtrl); -} - -void ApplicationLayer::propertyDescriptionReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex) -{ - CemiFrame frame(4); - APDU& apdu = frame.apdu(); - apdu.type(PropertyDescriptionRead); - uint8_t* data = apdu.data(); - data[1] = objectIndex; - data[2] = propertyId; - data[3] = propertyIndex; - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} - -void ApplicationLayer::propertyDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, - uint16_t maxNumberOfElements, uint8_t access) -{ - CemiFrame frame(8); - APDU& apdu = frame.apdu(); - apdu.type(PropertyDescriptionResponse); - uint8_t* data = apdu.data(); - data[1] = objectIndex; - data[2] = propertyId; - data[3] = propertyIndex; - - if (writeEnable) - data[4] |= 0x80; - - data[4] |= (type & 0x3f); - pushWord(maxNumberOfElements & 0xfff, data + 5); - data[7] = access; - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} - -void ApplicationLayer::propertyExtDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint16_t objectType, uint16_t objectInstance, uint16_t propertyId, uint16_t propertyIndex, uint8_t descriptionType, bool writeEnable, uint8_t type, - uint16_t maxNumberOfElements, uint8_t access) -{ - CemiFrame frame(16); - APDU& apdu = frame.apdu(); - apdu.type(PropertyExtDescriptionResponse); - uint8_t* data = apdu.data(); + data[1] = (objectType & 0xff00) >> 8; + data[2] = (objectType & 0x00ff); - data[1] = (objectType & 0xff00) >> 8; - data[2] = (objectType & 0x00ff); + data[3] = (objectInstance & 0x0ff0) >> 4; + data[4] = (objectInstance & 0x000f) << 4 | (propertyId & 0x0f00) >> 8; + data[5] = (propertyId & 0x00ff); - data[3] = (objectInstance & 0x0ff0) >> 4; - data[4] = (objectInstance & 0x000f) << 4 | (propertyId & 0x0f00) >> 8; - data[5] = (propertyId & 0x00ff); + data[6] = (descriptionType & 0x000f) << 4 | (propertyIndex & 0x0f00) >> 8; + data[7] = (propertyIndex & 0x00ff); + data[8] = 0; // DataPointType ?? + data[9] = 0; // DataPointType ?? + data[10] = 0; // DataPointType ?? + data[11] = 0; // DataPointType ?? - data[6] = (descriptionType & 0x000f) << 4 | (propertyIndex & 0x0f00) >> 8; - data[7] = (propertyIndex & 0x00ff); - data[8] = 0; // DataPointType ?? - data[9] = 0; // DataPointType ?? - data[10] = 0; // DataPointType ?? - data[11] = 0; // DataPointType ?? + if (writeEnable) + data[12] |= 0x80; - if (writeEnable) - data[12] |= 0x80; + data[12] |= (type & 0x3f); - data[12] |= (type & 0x3f); + pushWord(maxNumberOfElements & 0xfff, data + 13); + data[15] = access; + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } - pushWord(maxNumberOfElements & 0xfff, data + 13); - data[15] = access; - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} + void ApplicationLayer::memoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress) + { + CemiFrame frame(3); + APDU& apdu = frame.apdu(); + apdu.type(MemoryRead); + uint8_t* data = apdu.data(); + *data |= (number & 0x3f); + pushWord(memoryAddress, data + 1); + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } -void ApplicationLayer::memoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress) -{ - CemiFrame frame(3); - APDU& apdu = frame.apdu(); - apdu.type(MemoryRead); - uint8_t* data = apdu.data(); - *data |= (number & 0x3f); - pushWord(memoryAddress, data + 1); - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} - -void ApplicationLayer::memoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* memoryData) -{ - memorySend(MemoryResponse, ack, priority, hopType, asap, secCtrl, number, memoryAddress, memoryData); -} + void ApplicationLayer::memoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* memoryData) + { + memorySend(MemoryResponse, ack, priority, hopType, asap, secCtrl, number, memoryAddress, memoryData); + } -void ApplicationLayer::memoryRouterReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* memoryData) -{ - memoryRouterSend(MemoryRouterReadResponse, ack, priority, hopType, asap, secCtrl, number, memoryAddress, memoryData); -} + void ApplicationLayer::memoryRouterReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* memoryData) + { + memoryRouterSend(MemoryRouterReadResponse, ack, priority, hopType, asap, secCtrl, number, memoryAddress, memoryData); + } -void ApplicationLayer::memoryRoutingTableReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* memoryData) -{ - memoryRoutingTableSend(RoutingTableReadResponse, ack, priority, hopType, asap, secCtrl, number, memoryAddress, memoryData); -} + void ApplicationLayer::memoryRoutingTableReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* memoryData) + { + memoryRoutingTableSend(RoutingTableReadResponse, ack, priority, hopType, asap, secCtrl, number, memoryAddress, memoryData); + } -void ApplicationLayer::memoryExtReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ReturnCodes code, - uint8_t number, uint32_t memoryAddress, uint8_t* memoryData) -{ - CemiFrame frame(5 + number); - APDU& apdu = frame.apdu(); - apdu.type(MemoryExtReadResponse); - uint8_t* data = apdu.data(); - data[1] = code; - data[2] = (memoryAddress >> 16); - data[3] = (memoryAddress >> 8); - data[4] = (memoryAddress & 0xFF); - - memcpy(&data[5], memoryData, number); - - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} - -void ApplicationLayer::memoryExtWriteResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ReturnCodes code, - uint8_t number, uint32_t memoryAddress, uint8_t* memoryData) -{ - bool withCrc = code == ReturnCodes::SuccessWithCrc; + void ApplicationLayer::memoryExtReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ReturnCodes code, + uint8_t number, uint32_t memoryAddress, uint8_t* memoryData) + { + CemiFrame frame(5 + number); + APDU& apdu = frame.apdu(); + apdu.type(MemoryExtReadResponse); + uint8_t* data = apdu.data(); + data[1] = code; + data[2] = (memoryAddress >> 16); + data[3] = (memoryAddress >> 8); + data[4] = (memoryAddress & 0xFF); + + memcpy(&data[5], memoryData, number); + + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } - CemiFrame frame(5 + (withCrc ? 2 : 0)); - APDU& apdu = frame.apdu(); - apdu.type(MemoryExtWriteResponse); - uint8_t* data = apdu.data(); - data[1] = code; - data[2] = (memoryAddress >> 16); - data[3] = (memoryAddress >> 8); - data[4] = (memoryAddress & 0xFF); + void ApplicationLayer::memoryExtWriteResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ReturnCodes code, + uint8_t number, uint32_t memoryAddress, uint8_t* memoryData) + { + bool withCrc = code == ReturnCodes::SuccessWithCrc; + + CemiFrame frame(5 + (withCrc ? 2 : 0)); + APDU& apdu = frame.apdu(); + apdu.type(MemoryExtWriteResponse); + uint8_t* data = apdu.data(); + data[1] = code; + data[2] = (memoryAddress >> 16); + data[3] = (memoryAddress >> 8); + data[4] = (memoryAddress & 0xFF); + + if (withCrc) + { + uint16_t crc = crc16Ccitt(memoryData, number); + data[5] = crc >> 8; + data[6] = crc & 0xFF; + } - if (withCrc) + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } + + void ApplicationLayer::memoryWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t number, uint16_t memoryAddress, uint8_t* data) { - uint16_t crc = crc16Ccitt(memoryData, number); - data[5] = crc >> 8; - data[6] = crc & 0xFF; + memorySend(MemoryWrite, ack, priority, hopType, asap, secCtrl, number, memoryAddress, data); } - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} + void ApplicationLayer::userMemoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t number, uint32_t memoryAddress) + { + CemiFrame frame(4); + APDU& apdu = frame.apdu(); + apdu.type(UserMemoryRead); + uint8_t* data = apdu.data(); + data[1] |= (number & 0xf); + data[1] |= ((memoryAddress >> 12) & 0xf0); + pushWord(memoryAddress & 0xff, data + 2); + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } -void ApplicationLayer::memoryWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t number, uint16_t memoryAddress, uint8_t* data) -{ - memorySend(MemoryWrite, ack, priority, hopType, asap, secCtrl, number, memoryAddress, data); -} + void ApplicationLayer::userMemoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t number, uint32_t memoryAddress, uint8_t* memoryData) + { + userMemorySend(UserMemoryResponse, ack, priority, hopType, asap, secCtrl, number, memoryAddress, memoryData); + } -void ApplicationLayer::userMemoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t number, uint32_t memoryAddress) -{ - CemiFrame frame(4); - APDU& apdu = frame.apdu(); - apdu.type(UserMemoryRead); - uint8_t* data = apdu.data(); - data[1] |= (number & 0xf); - data[1] |= ((memoryAddress >> 12) & 0xf0); - pushWord(memoryAddress & 0xff, data + 2); - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} - -void ApplicationLayer::userMemoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t number, uint32_t memoryAddress, uint8_t* memoryData) -{ - userMemorySend(UserMemoryResponse, ack, priority, hopType, asap, secCtrl, number, memoryAddress, memoryData); -} + void ApplicationLayer::userMemoryWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t number, uint32_t memoryAddress, uint8_t* memoryData) + { + userMemorySend(UserMemoryWrite, ack, priority, hopType, asap, secCtrl, number, memoryAddress, memoryData); + } -void ApplicationLayer::userMemoryWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t number, uint32_t memoryAddress, uint8_t* memoryData) -{ - userMemorySend(UserMemoryWrite, ack, priority, hopType, asap, secCtrl, number, memoryAddress, memoryData); -} + void ApplicationLayer::userManufacturerInfoReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl) + { + CemiFrame frame(1); + APDU& apdu = frame.apdu(); + apdu.type(UserManufacturerInfoRead); + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } -void ApplicationLayer::userManufacturerInfoReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl) -{ - CemiFrame frame(1); - APDU& apdu = frame.apdu(); - apdu.type(UserManufacturerInfoRead); - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} - -void ApplicationLayer::userManufacturerInfoReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t* info) -{ - CemiFrame frame(4); - APDU& apdu = frame.apdu(); - apdu.type(UserMemoryRead); - uint8_t* data = apdu.data(); - memcpy(data + 1, info, 3); - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} - -void ApplicationLayer::authorizeRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key) -{ - CemiFrame frame(6); - APDU& apdu = frame.apdu(); - apdu.type(AuthorizeRequest); - uint8_t* data = apdu.data(); - pushInt(key, data + 2); - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} - -void ApplicationLayer::authorizeResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level) -{ - CemiFrame frame(2); - APDU& apdu = frame.apdu(); - apdu.type(AuthorizeResponse); - uint8_t* data = apdu.data(); - data[1] = level; - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} - -void ApplicationLayer::keyWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, uint32_t key) -{ - CemiFrame frame(6); - APDU& apdu = frame.apdu(); - apdu.type(KeyWrite); - uint8_t* data = apdu.data(); - data[1] = level; - pushInt(key, data + 2); - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} - -void ApplicationLayer::keyWriteResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level) -{ - CemiFrame frame(6); - APDU& apdu = frame.apdu(); - apdu.type(KeyResponse); - uint8_t* data = apdu.data(); - data[1] = level; - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} - -void ApplicationLayer::propertyDataSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) -{ - CemiFrame frame(5 + length); - APDU& apdu = frame.apdu(); - apdu.type(type); - uint8_t* apduData = apdu.data(); - apduData += 1; - apduData = pushByte(objectIndex, apduData); - apduData = pushByte(propertyId, apduData); - pushWord(startIndex & 0xfff, apduData); - *apduData |= ((numberOfElements & 0xf) << 4); - apduData += 2; - - if (length > 0) - memcpy(apduData, data, length); - - if (asap == _connectedTsap) - dataConnectedRequest(asap, priority, apdu, secCtrl); - else - dataIndividualRequest(ack, hopType, priority, asap, apdu, secCtrl); -} - -void ApplicationLayer::propertyExtDataSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) -{ - CemiFrame frame(9 + length); - APDU& apdu = frame.apdu(); - apdu.type(type); - uint8_t* apduData = apdu.data(); - apduData += 1; - - apduData[0] = ((uint16_t)objectType) >> 8; - apduData[1] = ((uint16_t)objectType) & 0xFF; - apduData[2] = objectInstance >> 4; - apduData[3] = ((objectInstance & 0x0F) << 4) | (propertyId >> 8); - apduData[4] = (propertyId & 0xFF); - apduData[5] = numberOfElements; - apduData[6] = (startIndex & 0x0FFF) >> 8; - apduData[7] = startIndex & 0xFF; - - if (length > 0) - memcpy(apduData + 8, data, length); - - if (asap == _connectedTsap) - dataConnectedRequest(asap, priority, apdu, secCtrl); - else - dataIndividualRequest(ack, hopType, priority, asap, apdu, secCtrl); -} - -void ApplicationLayer::groupValueSend(ApduType type, AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, - uint8_t* data, uint8_t& dataLength) -{ - if (_assocTable == nullptr) - return; + void ApplicationLayer::userManufacturerInfoReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t* info) + { + CemiFrame frame(4); + APDU& apdu = frame.apdu(); + apdu.type(UserMemoryRead); + uint8_t* data = apdu.data(); + memcpy(data + 1, info, 3); + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } + + void ApplicationLayer::authorizeRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key) + { + CemiFrame frame(6); + APDU& apdu = frame.apdu(); + apdu.type(AuthorizeRequest); + uint8_t* data = apdu.data(); + pushInt(key, data + 2); + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } + + void ApplicationLayer::authorizeResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level) + { + CemiFrame frame(2); + APDU& apdu = frame.apdu(); + apdu.type(AuthorizeResponse); + uint8_t* data = apdu.data(); + data[1] = level; + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } - CemiFrame frame(dataLength + 1); - APDU& apdu = frame.apdu(); - apdu.type(type); - uint8_t* apdudata = apdu.data(); + void ApplicationLayer::keyWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, uint32_t key) + { + CemiFrame frame(6); + APDU& apdu = frame.apdu(); + apdu.type(KeyWrite); + uint8_t* data = apdu.data(); + data[1] = level; + pushInt(key, data + 2); + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } - if (dataLength == 0) + void ApplicationLayer::keyWriteResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level) { - // data size is six bit or less. So store in first byte - *apdudata &= ~0x3f; - *apdudata |= (*data & 0x3f); + CemiFrame frame(6); + APDU& apdu = frame.apdu(); + apdu.type(KeyResponse); + uint8_t* data = apdu.data(); + data[1] = level; + individualSend(ack, hopType, priority, asap, apdu, secCtrl); } - else + + void ApplicationLayer::propertyDataSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) { - memcpy(apdudata + 1, data, dataLength); + CemiFrame frame(5 + length); + APDU& apdu = frame.apdu(); + apdu.type(type); + uint8_t* apduData = apdu.data(); + apduData += 1; + apduData = pushByte(objectIndex, apduData); + apduData = pushByte(propertyId, apduData); + pushWord(startIndex & 0xfff, apduData); + *apduData |= ((numberOfElements & 0xf) << 4); + apduData += 2; + + if (length > 0) + memcpy(apduData, data, length); + + if (asap == _connectedTsap) + dataConnectedRequest(asap, priority, apdu, secCtrl); + else + dataIndividualRequest(ack, hopType, priority, asap, apdu, secCtrl); } - // no need to check if there is a tsap. This is a response, so the read got through - uint16_t tsap = (uint16_t)_assocTable->translateAsap(asap); - dataGroupRequest(ack, hopType, priority, tsap, apdu, secCtrl); - dataGroupIndication(hopType, priority, tsap, apdu, secCtrl); -} + void ApplicationLayer::propertyExtDataSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) + { + CemiFrame frame(9 + length); + APDU& apdu = frame.apdu(); + apdu.type(type); + uint8_t* apduData = apdu.data(); + apduData += 1; + + apduData[0] = ((uint16_t)objectType) >> 8; + apduData[1] = ((uint16_t)objectType) & 0xFF; + apduData[2] = objectInstance >> 4; + apduData[3] = ((objectInstance & 0x0F) << 4) | (propertyId >> 8); + apduData[4] = (propertyId & 0xFF); + apduData[5] = numberOfElements; + apduData[6] = (startIndex & 0x0FFF) >> 8; + apduData[7] = startIndex & 0xFF; + + if (length > 0) + memcpy(apduData + 8, data, length); + + if (asap == _connectedTsap) + dataConnectedRequest(asap, priority, apdu, secCtrl); + else + dataIndividualRequest(ack, hopType, priority, asap, apdu, secCtrl); + } -void ApplicationLayer::memorySend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* memoryData) -{ - CemiFrame frame(3 + number); - APDU& apdu = frame.apdu(); - apdu.type(type); - uint8_t* data = apdu.data(); - *data |= (number & 0x3f); - pushWord(memoryAddress, data + 1); + void ApplicationLayer::groupValueSend(ApduType type, AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, + uint8_t* data, uint8_t& dataLength) + { + if (_assocTable == nullptr) + return; - if (number > 0) - memcpy(data + 3, memoryData, number); + CemiFrame frame(dataLength + 1); + APDU& apdu = frame.apdu(); + apdu.type(type); + uint8_t* apdudata = apdu.data(); - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} + if (dataLength == 0) + { + // data size is six bit or less. So store in first byte + *apdudata &= ~0x3f; + *apdudata |= (*data & 0x3f); + } + else + { + memcpy(apdudata + 1, data, dataLength); + } -void ApplicationLayer::memoryRouterSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* memoryData) -{ - CemiFrame frame(4 + number); - APDU& apdu = frame.apdu(); - apdu.type(type); - uint8_t* data = apdu.data(); - data[1] |= (number & 0xf); - pushWord(memoryAddress & 0xffff, data + 2); + // no need to check if there is a tsap. This is a response, so the read got through + uint16_t tsap = (uint16_t)_assocTable->translateAsap(asap); + dataGroupRequest(ack, hopType, priority, tsap, apdu, secCtrl); + dataGroupIndication(hopType, priority, tsap, apdu, secCtrl); + } - if (number > 0) - memcpy(data + 4, memoryData, number); + void ApplicationLayer::memorySend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* memoryData) + { + CemiFrame frame(3 + number); + APDU& apdu = frame.apdu(); + apdu.type(type); + uint8_t* data = apdu.data(); + *data |= (number & 0x3f); + pushWord(memoryAddress, data + 1); - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} + if (number > 0) + memcpy(data + 3, memoryData, number); -void ApplicationLayer::memoryRoutingTableSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* memoryData) -{ - CemiFrame frame(4 + number); - APDU& apdu = frame.apdu(); - apdu.type(type); - uint8_t* data = apdu.data(); - data[1] |= (number & 0xf); - pushWord(memoryAddress & 0xffff, data + 2); + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } - if (number > 0) - memcpy(data + 4, memoryData, number); + void ApplicationLayer::memoryRouterSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* memoryData) + { + CemiFrame frame(4 + number); + APDU& apdu = frame.apdu(); + apdu.type(type); + uint8_t* data = apdu.data(); + data[1] |= (number & 0xf); + pushWord(memoryAddress & 0xffff, data + 2); - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} + if (number > 0) + memcpy(data + 4, memoryData, number); -void ApplicationLayer::userMemorySend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress, uint8_t* memoryData) -{ - CemiFrame frame(4 + number); - APDU& apdu = frame.apdu(); - apdu.type(type); - uint8_t* data = apdu.data(); - data[1] |= (number & 0xf); - data[1] |= ((memoryAddress >> 12) & 0xf0); - pushWord(memoryAddress & 0xffff, data + 2); + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } - if (number > 0) - memcpy(data + 4, memoryData, number); + void ApplicationLayer::memoryRoutingTableSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* memoryData) + { + CemiFrame frame(4 + number); + APDU& apdu = frame.apdu(); + apdu.type(type); + uint8_t* data = apdu.data(); + data[1] |= (number & 0xf); + pushWord(memoryAddress & 0xffff, data + 2); - individualSend(ack, hopType, priority, asap, apdu, secCtrl); -} + if (number > 0) + memcpy(data + 4, memoryData, number); -void ApplicationLayer::individualIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) -{ - LOGGER.info("individualIndication ", apdu); - uint8_t* data = apdu.data(); + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } - switch (apdu.type()) + void ApplicationLayer::userMemorySend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress, uint8_t* memoryData) { - case DeviceDescriptorRead: - _bau.deviceDescriptorReadIndication(priority, hopType, tsap, secCtrl, *data & 0x3f); - break; + CemiFrame frame(4 + number); + APDU& apdu = frame.apdu(); + apdu.type(type); + uint8_t* data = apdu.data(); + data[1] |= (number & 0xf); + data[1] |= ((memoryAddress >> 12) & 0xf0); + pushWord(memoryAddress & 0xffff, data + 2); + + if (number > 0) + memcpy(data + 4, memoryData, number); + + individualSend(ack, hopType, priority, asap, apdu, secCtrl); + } - case DeviceDescriptorResponse: - _bau.deviceDescriptorReadAppLayerConfirm(priority, hopType, tsap, secCtrl, *data & 0x3f, data + 1); - break; + void ApplicationLayer::individualIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) + { + LOGGER.info("individualIndication ", apdu); + uint8_t* data = apdu.data(); - case Restart: - case RestartMasterReset: + switch (apdu.type()) { - // These reserved bits must be 0 - uint8_t reservedBits = data[0] & 0x1e; - - if (reservedBits != 0) - return; + case DeviceDescriptorRead: + _bau.deviceDescriptorReadIndication(priority, hopType, tsap, secCtrl, *data & 0x3f); + break; - // handle erase code for factory reset (setting FDSK again as toolkey, etc.) - RestartType restartType = (RestartType) (data[0] & 0x3f); - EraseCode eraseCode = EraseCode::Void; - uint8_t channel = 0; + case DeviceDescriptorResponse: + _bau.deviceDescriptorReadAppLayerConfirm(priority, hopType, tsap, secCtrl, *data & 0x3f, data + 1); + break; - if (restartType == RestartType::MasterReset) + case Restart: + case RestartMasterReset: { - eraseCode = (EraseCode) data[1]; - channel = data[2]; + // These reserved bits must be 0 + uint8_t reservedBits = data[0] & 0x1e; + + if (reservedBits != 0) + return; + + // handle erase code for factory reset (setting FDSK again as toolkey, etc.) + RestartType restartType = (RestartType) (data[0] & 0x3f); + EraseCode eraseCode = EraseCode::Void; + uint8_t channel = 0; + + if (restartType == RestartType::MasterReset) + { + eraseCode = (EraseCode) data[1]; + channel = data[2]; + } + + _bau.restartRequestIndication(priority, hopType, tsap, secCtrl, restartType, eraseCode, channel); + break; } - _bau.restartRequestIndication(priority, hopType, tsap, secCtrl, restartType, eraseCode, channel); - break; - } + case PropertyValueRead: + { + uint16_t startIndex; + popWord(startIndex, data + 3); + startIndex &= 0xfff; + _bau.propertyValueReadIndication(priority, hopType, tsap, secCtrl, data[1], data[2], data[3] >> 4, startIndex); + break; + } - case PropertyValueRead: - { - uint16_t startIndex; - popWord(startIndex, data + 3); - startIndex &= 0xfff; - _bau.propertyValueReadIndication(priority, hopType, tsap, secCtrl, data[1], data[2], data[3] >> 4, startIndex); - break; - } + case PropertyValueResponse: + { + uint16_t startIndex; + popWord(startIndex, data + 3); + startIndex &= 0xfff; + _bau.propertyValueReadAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1], data[2], data[3] >> 4, + startIndex, data + 5, apdu.length() - 5); + break; + } - case PropertyValueResponse: - { - uint16_t startIndex; - popWord(startIndex, data + 3); - startIndex &= 0xfff; - _bau.propertyValueReadAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1], data[2], data[3] >> 4, + case PropertyValueWrite: + { + uint16_t startIndex; + popWord(startIndex, data + 3); + startIndex &= 0xfff; + _bau.propertyValueWriteIndication(priority, hopType, tsap, secCtrl, data[1], data[2], data[3] >> 4, startIndex, data + 5, apdu.length() - 5); - break; - } + break; + } - case PropertyValueWrite: - { - uint16_t startIndex; - popWord(startIndex, data + 3); - startIndex &= 0xfff; - _bau.propertyValueWriteIndication(priority, hopType, tsap, secCtrl, data[1], data[2], data[3] >> 4, - startIndex, data + 5, apdu.length() - 5); - break; - } + case PropertyValueExtRead: + { + ObjectType objectType = (ObjectType)(((data[1] & 0xff) << 8) | (data[2] & 0xff)); + uint8_t objectInstance = ((data[3] & 0xff) << 4) | ((data[4] & 0xff) >> 4); + uint16_t propertyId = ((data[4] & 0xf) << 8) | (data[5] & 0xff); + uint8_t numberOfElements = data[6]; + uint16_t startIndex = ((data[7] & 0xf) << 8) | (data[8] & 0xff); + _bau.propertyValueExtReadIndication(priority, hopType, tsap, secCtrl, objectType, objectInstance, propertyId, numberOfElements, startIndex); + break; + } - case PropertyValueExtRead: - { - ObjectType objectType = (ObjectType)(((data[1] & 0xff) << 8) | (data[2] & 0xff)); - uint8_t objectInstance = ((data[3] & 0xff) << 4) | ((data[4] & 0xff) >> 4); - uint16_t propertyId = ((data[4] & 0xf) << 8) | (data[5] & 0xff); - uint8_t numberOfElements = data[6]; - uint16_t startIndex = ((data[7] & 0xf) << 8) | (data[8] & 0xff); - _bau.propertyValueExtReadIndication(priority, hopType, tsap, secCtrl, objectType, objectInstance, propertyId, numberOfElements, startIndex); - break; - } + case PropertyValueExtWriteCon: + case PropertyValueExtWriteUnCon: + { + ObjectType objectType = (ObjectType)(((data[1] & 0xff) << 8) | (data[2] & 0xff)); + uint8_t objectInstance = ((data[3] & 0xff) << 4) | ((data[4] & 0xff) >> 4); + uint16_t propertyId = ((data[4] & 0xf) << 8) | (data[5] & 0xff); + uint8_t numberOfElements = data[6]; + uint16_t startIndex = ((data[7] & 0xf) << 8) | (data[8] & 0xff); + bool confirmed = (apdu.type() == PropertyValueExtWriteCon); + _bau.propertyValueExtWriteIndication(priority, hopType, tsap, secCtrl, objectType, objectInstance, propertyId, numberOfElements, startIndex, + data + 9, apdu.length() - 9, confirmed); + break; + } - case PropertyValueExtWriteCon: - case PropertyValueExtWriteUnCon: - { - ObjectType objectType = (ObjectType)(((data[1] & 0xff) << 8) | (data[2] & 0xff)); - uint8_t objectInstance = ((data[3] & 0xff) << 4) | ((data[4] & 0xff) >> 4); - uint16_t propertyId = ((data[4] & 0xf) << 8) | (data[5] & 0xff); - uint8_t numberOfElements = data[6]; - uint16_t startIndex = ((data[7] & 0xf) << 8) | (data[8] & 0xff); - bool confirmed = (apdu.type() == PropertyValueExtWriteCon); - _bau.propertyValueExtWriteIndication(priority, hopType, tsap, secCtrl, objectType, objectInstance, propertyId, numberOfElements, startIndex, - data + 9, apdu.length() - 9, confirmed); - break; - } + case FunctionPropertyCommand: + _bau.functionPropertyCommandIndication(priority, hopType, tsap, secCtrl, data[1], data[2], &data[3], apdu.length() - 3); //TODO: check length + break; - case FunctionPropertyCommand: - _bau.functionPropertyCommandIndication(priority, hopType, tsap, secCtrl, data[1], data[2], &data[3], apdu.length() - 3); //TODO: check length - break; + case FunctionPropertyState: + _bau.functionPropertyStateIndication(priority, hopType, tsap, secCtrl, data[1], data[2], &data[3], apdu.length() - 3); //TODO: check length + break; - case FunctionPropertyState: - _bau.functionPropertyStateIndication(priority, hopType, tsap, secCtrl, data[1], data[2], &data[3], apdu.length() - 3); //TODO: check length - break; + case FunctionPropertyExtCommand: + { + ObjectType objectType = (ObjectType)(((data[1] & 0xff) << 8) | (data[2] & 0xff)); + uint8_t objectInstance = ((data[3] & 0xff) << 4) | ((data[4] & 0xff) >> 4); + uint16_t propertyId = ((data[4] & 0xf) << 8) | (data[5] & 0xff); + uint8_t* functionInput = &data[6]; + _bau.functionPropertyExtCommandIndication(priority, hopType, tsap, secCtrl, objectType, objectInstance, propertyId, functionInput, apdu.length() - 6); + break; + } - case FunctionPropertyExtCommand: - { - ObjectType objectType = (ObjectType)(((data[1] & 0xff) << 8) | (data[2] & 0xff)); - uint8_t objectInstance = ((data[3] & 0xff) << 4) | ((data[4] & 0xff) >> 4); - uint16_t propertyId = ((data[4] & 0xf) << 8) | (data[5] & 0xff); - uint8_t* functionInput = &data[6]; - _bau.functionPropertyExtCommandIndication(priority, hopType, tsap, secCtrl, objectType, objectInstance, propertyId, functionInput, apdu.length() - 6); - break; - } + case FunctionPropertyExtState: + { + ObjectType objectType = (ObjectType)(((data[1] & 0xff) << 8) | (data[2] & 0xff)); + uint8_t objectInstance = ((data[3] & 0xff) << 4) | ((data[4] & 0xff) >> 4); + uint16_t propertyId = ((data[4] & 0xf) << 8) | (data[5] & 0xff); + uint8_t* functionInput = &data[6]; + _bau.functionPropertyExtStateIndication(priority, hopType, tsap, secCtrl, objectType, objectInstance, propertyId, functionInput, apdu.length() - 6); + break; + } - case FunctionPropertyExtState: - { - ObjectType objectType = (ObjectType)(((data[1] & 0xff) << 8) | (data[2] & 0xff)); - uint8_t objectInstance = ((data[3] & 0xff) << 4) | ((data[4] & 0xff) >> 4); - uint16_t propertyId = ((data[4] & 0xf) << 8) | (data[5] & 0xff); - uint8_t* functionInput = &data[6]; - _bau.functionPropertyExtStateIndication(priority, hopType, tsap, secCtrl, objectType, objectInstance, propertyId, functionInput, apdu.length() - 6); - break; - } + case PropertyDescriptionRead: + _bau.propertyDescriptionReadIndication(priority, hopType, tsap, secCtrl, data[1], data[2], data[3]); + break; - case PropertyDescriptionRead: - _bau.propertyDescriptionReadIndication(priority, hopType, tsap, secCtrl, data[1], data[2], data[3]); - break; + case PropertyExtDescriptionRead: + { + ObjectType objectType = (ObjectType)(((data[1] & 0xff) << 8) | (data[2] & 0xff)); + uint16_t objectInstance = ((data[3] & 0xff) << 4) | ((data[4] & 0xf0) >> 4); + uint16_t propertyId = ((data[4] & 0x0f) << 8) | (data[5] & 0xff); + uint8_t descriptionType = (data[6] & 0xf0) >> 4; + uint16_t propertyIndex = ((data[7] & 0x0f) << 8) | (data[8] & 0xff); - case PropertyExtDescriptionRead: - { - ObjectType objectType = (ObjectType)(((data[1] & 0xff) << 8) | (data[2] & 0xff)); - uint16_t objectInstance = ((data[3] & 0xff) << 4) | ((data[4] & 0xf0) >> 4); - uint16_t propertyId = ((data[4] & 0x0f) << 8) | (data[5] & 0xff); - uint8_t descriptionType = (data[6] & 0xf0) >> 4; - uint16_t propertyIndex = ((data[7] & 0x0f) << 8) | (data[8] & 0xff); - - _bau.propertyExtDescriptionReadIndication(priority, hopType, tsap, secCtrl, objectType, objectInstance, propertyId, descriptionType, propertyIndex); - break; - } + _bau.propertyExtDescriptionReadIndication(priority, hopType, tsap, secCtrl, objectType, objectInstance, propertyId, descriptionType, propertyIndex); + break; + } - case PropertyDescriptionResponse: - _bau.propertyDescriptionReadAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1], data[2], data[3], - (data[4] & 0x80) > 0, data[4] & 0x3f, getWord(data + 5) & 0xfff, data[7]); - break; + case PropertyDescriptionResponse: + _bau.propertyDescriptionReadAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1], data[2], data[3], + (data[4] & 0x80) > 0, data[4] & 0x3f, getWord(data + 5) & 0xfff, data[7]); + break; - case MemoryRead: - _bau.memoryReadIndication(priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1)); - break; + case MemoryRead: + _bau.memoryReadIndication(priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1)); + break; - case MemoryResponse: - _bau.memoryReadAppLayerConfirm(priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3); - break; + case MemoryResponse: + _bau.memoryReadAppLayerConfirm(priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3); + break; - case MemoryWrite: - _bau.memoryWriteIndication(priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3); - break; + case MemoryWrite: + _bau.memoryWriteIndication(priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3); + break; - // EC - case MemoryRouterWrite: - print("MemoryRouterWrite: "); - _bau.memoryRouterWriteIndication(priority, hopType, tsap, secCtrl, data[1], getWord(data + 2), data + 4); - break; + // EC + case MemoryRouterWrite: + print("MemoryRouterWrite: "); + _bau.memoryRouterWriteIndication(priority, hopType, tsap, secCtrl, data[1], getWord(data + 2), data + 4); + break; - case MemoryRouterReadResponse: - _bau.memoryRouterReadAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1], getWord(data + 2), data + 4); - break; + case MemoryRouterReadResponse: + _bau.memoryRouterReadAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1], getWord(data + 2), data + 4); + break; - case RoutingTableOpen: - println("Received OpenRoutingTable APDU, doing nothing"); - break; + case RoutingTableOpen: + println("Received OpenRoutingTable APDU, doing nothing"); + break; - case RoutingTableRead: - _bau.memoryRoutingTableReadIndication(priority, hopType, tsap, secCtrl, data[1], getWord(data + 2)); - break; + case RoutingTableRead: + _bau.memoryRoutingTableReadIndication(priority, hopType, tsap, secCtrl, data[1], getWord(data + 2)); + break; - case RoutingTableReadResponse: - _bau.memoryRoutingTableReadAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1], getWord(data + 2), data + 4); - break; + case RoutingTableReadResponse: + _bau.memoryRoutingTableReadAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1], getWord(data + 2), data + 4); + break; - case RoutingTableWrite: - _bau.memoryRoutingTableWriteIndication(priority, hopType, tsap, secCtrl, data[1], getWord(data + 2), data + 4); - break; + case RoutingTableWrite: + _bau.memoryRoutingTableWriteIndication(priority, hopType, tsap, secCtrl, data[1], getWord(data + 2), data + 4); + break; - // end EC + // end EC - case MemoryExtRead: - { - uint8_t number = data[1]; - uint32_t memoryAddress = ((data[2] & 0xff) << 16) | ((data[3] & 0xff) << 8) | (data[4] & 0xff); - _bau.memoryExtReadIndication(priority, hopType, tsap, secCtrl, number, memoryAddress); - break; - } + case MemoryExtRead: + { + uint8_t number = data[1]; + uint32_t memoryAddress = ((data[2] & 0xff) << 16) | ((data[3] & 0xff) << 8) | (data[4] & 0xff); + _bau.memoryExtReadIndication(priority, hopType, tsap, secCtrl, number, memoryAddress); + break; + } - //case MemoryExtReadResponse: - // _bau.memoryExtReadAppLayerConfirm(priority, hopType, tsap, secCtrl, data[0], getInt(data + 1), data + 4); // TODO return code - // break; - case MemoryExtWrite: - { - uint8_t number = data[1]; - uint32_t memoryAddress = ((data[2] & 0xff) << 16) | ((data[3] & 0xff) << 8) | (data[4] & 0xff); - _bau.memoryExtWriteIndication(priority, hopType, tsap, secCtrl, number, memoryAddress, data + 5); - break; - } + //case MemoryExtReadResponse: + // _bau.memoryExtReadAppLayerConfirm(priority, hopType, tsap, secCtrl, data[0], getInt(data + 1), data + 4); // TODO return code + // break; + case MemoryExtWrite: + { + uint8_t number = data[1]; + uint32_t memoryAddress = ((data[2] & 0xff) << 16) | ((data[3] & 0xff) << 8) | (data[4] & 0xff); + _bau.memoryExtWriteIndication(priority, hopType, tsap, secCtrl, number, memoryAddress, data + 5); + break; + } - //case MemoryExtWriteResponse: - // _bau.memoryExtWriteAppLayerConfirm(priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3); // TODO return code - // break; - case UserMemoryRead: - { - uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3]; - _bau.userMemoryReadIndication(priority, hopType, tsap, secCtrl, data[1] & 0xf, address); - break; - } + //case MemoryExtWriteResponse: + // _bau.memoryExtWriteAppLayerConfirm(priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3); // TODO return code + // break; + case UserMemoryRead: + { + uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3]; + _bau.userMemoryReadIndication(priority, hopType, tsap, secCtrl, data[1] & 0xf, address); + break; + } - case UserMemoryResponse: - { - uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3]; - _bau.userMemoryReadAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1] & 0xf, address, data + 4); - break; - } + case UserMemoryResponse: + { + uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3]; + _bau.userMemoryReadAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1] & 0xf, address, data + 4); + break; + } - case UserMemoryWrite: - { - uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3]; - _bau.userMemoryWriteIndication(priority, hopType, tsap, secCtrl, data[1] & 0xf, address, data + 4); - break; - } + case UserMemoryWrite: + { + uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3]; + _bau.userMemoryWriteIndication(priority, hopType, tsap, secCtrl, data[1] & 0xf, address, data + 4); + break; + } + + case UserManufacturerInfoRead: + _bau.userManufacturerInfoIndication(priority, hopType, tsap, secCtrl); + break; - case UserManufacturerInfoRead: - _bau.userManufacturerInfoIndication(priority, hopType, tsap, secCtrl); - break; + case UserManufacturerInfoResponse: + _bau.userManufacturerInfoAppLayerConfirm(priority, hopType, tsap, secCtrl, data + 1); + break; - case UserManufacturerInfoResponse: - _bau.userManufacturerInfoAppLayerConfirm(priority, hopType, tsap, secCtrl, data + 1); - break; + case AuthorizeRequest: + _bau.authorizeIndication(priority, hopType, tsap, secCtrl, getInt(data + 2)); + break; - case AuthorizeRequest: - _bau.authorizeIndication(priority, hopType, tsap, secCtrl, getInt(data + 2)); - break; + case AuthorizeResponse: + _bau.authorizeAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1]); + break; - case AuthorizeResponse: - _bau.authorizeAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1]); - break; + case KeyWrite: + _bau.keyWriteIndication(priority, hopType, tsap, secCtrl, data[1], getInt(data + 2)); + break; - case KeyWrite: - _bau.keyWriteIndication(priority, hopType, tsap, secCtrl, data[1], getInt(data + 2)); - break; + case KeyResponse: + _bau.keyWriteAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1]); + break; - case KeyResponse: - _bau.keyWriteAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1]); - break; + case ADCRead: + { + //Since we don't have an adc for bus voltage, we just send zero as readCount + uint8_t channelNr = data[0] & 0b111111; + this->adcReadResponse(AckRequested, priority, hopType, tsap, secCtrl, channelNr, 0, 0); + break; + } - case ADCRead: - { - //Since we don't have an adc for bus voltage, we just send zero as readCount - uint8_t channelNr = data[0] & 0b111111; - this->adcReadResponse(AckRequested, priority, hopType, tsap, secCtrl, channelNr, 0, 0); - break; + default: + LOGGER.warning("Individual-indication: unhandled APDU-Type: ", apdu); } - - default: - LOGGER.warning("Individual-indication: unhandled APDU-Type: ", apdu); } -} -void ApplicationLayer::individualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl, bool status) -{ - LOGGER.info("individualConfirm ", apdu); - uint8_t* data = apdu.data(); - - switch (apdu.type()) + void ApplicationLayer::individualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl, bool status) { - case DeviceDescriptorRead: - _bau.deviceDescriptorReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, *data & 0x3f, status); - break; + LOGGER.info("individualConfirm ", apdu); + uint8_t* data = apdu.data(); - case DeviceDescriptorResponse: - _bau.deviceDescriptorReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, *data & 0x3f, data + 1, status); - break; + switch (apdu.type()) + { + case DeviceDescriptorRead: + _bau.deviceDescriptorReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, *data & 0x3f, status); + break; - case Restart: - _bau.restartRequestLocalConfirm(ack, priority, hopType, tsap, secCtrl, status); - break; + case DeviceDescriptorResponse: + _bau.deviceDescriptorReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, *data & 0x3f, data + 1, status); + break; - case PropertyValueRead: - { - uint16_t startIndex; - popWord(startIndex, data + 3); - startIndex &= 0xfff; - _bau.propertyValueReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[1], data[2], data[3] >> 4, - startIndex, status); - break; - } + case Restart: + _bau.restartRequestLocalConfirm(ack, priority, hopType, tsap, secCtrl, status); + break; - case PropertyValueResponse: - { - uint16_t startIndex; - popWord(startIndex, data + 3); - startIndex &= 0xfff; - _bau.propertyValueReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[1], data[2], data[3] >> 4, - startIndex, data + 5, apdu.length() - 5, status); - break; - } + case PropertyValueRead: + { + uint16_t startIndex; + popWord(startIndex, data + 3); + startIndex &= 0xfff; + _bau.propertyValueReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[1], data[2], data[3] >> 4, + startIndex, status); + break; + } - case PropertyValueWrite: - { - uint16_t startIndex; - popWord(startIndex, data + 3); - startIndex &= 0xfff; - _bau.propertyValueWriteLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[1], data[2], data[3] >> 4, - startIndex, data + 5, apdu.length() - 5, status); - break; - } + case PropertyValueResponse: + { + uint16_t startIndex; + popWord(startIndex, data + 3); + startIndex &= 0xfff; + _bau.propertyValueReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[1], data[2], data[3] >> 4, + startIndex, data + 5, apdu.length() - 5, status); + break; + } - case PropertyDescriptionRead: - _bau.propertyDescriptionReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[1], data[2], data[3], status); - break; + case PropertyValueWrite: + { + uint16_t startIndex; + popWord(startIndex, data + 3); + startIndex &= 0xfff; + _bau.propertyValueWriteLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[1], data[2], data[3] >> 4, + startIndex, data + 5, apdu.length() - 5, status); + break; + } - case PropertyExtDescriptionRead: - _bau.propertyExtDescriptionReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[1], data[2], data[3], status); - break; + case PropertyDescriptionRead: + _bau.propertyDescriptionReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[1], data[2], data[3], status); + break; - case PropertyDescriptionResponse: - _bau.propertyDescriptionReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[1], data[2], data[3], - (data[4] & 0x80) > 0, data[4] & 0x3f, getWord(data + 5) & 0xfff, data[7], status); - break; + case PropertyExtDescriptionRead: + _bau.propertyExtDescriptionReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[1], data[2], data[3], status); + break; - case MemoryRead: - _bau.memoryReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), status); - break; + case PropertyDescriptionResponse: + _bau.propertyDescriptionReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[1], data[2], data[3], + (data[4] & 0x80) > 0, data[4] & 0x3f, getWord(data + 5) & 0xfff, data[7], status); + break; - case MemoryResponse: - _bau.memoryReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3, status); - break; + case MemoryRead: + _bau.memoryReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), status); + break; - case MemoryWrite: - _bau.memoryWriteLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3, status); - break; + case MemoryResponse: + _bau.memoryReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3, status); + break; - case MemoryExtRead: - _bau.memoryExtReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), status); - break; + case MemoryWrite: + _bau.memoryWriteLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3, status); + break; - case MemoryExtReadResponse: - _bau.memoryExtReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3, status); - break; + case MemoryExtRead: + _bau.memoryExtReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), status); + break; - case MemoryExtWrite: - _bau.memoryExtWriteLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3, status); - break; + case MemoryExtReadResponse: + _bau.memoryExtReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3, status); + break; - case MemoryExtWriteResponse: - _bau.memoryExtWriteResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3, status); - break; + case MemoryExtWrite: + _bau.memoryExtWriteLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3, status); + break; - case UserMemoryRead: - { - uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3]; - _bau.memoryReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[1] & 0xf, address, status); - break; - } + case MemoryExtWriteResponse: + _bau.memoryExtWriteResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3, status); + break; - case UserMemoryResponse: - { - uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3]; - _bau.memoryReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[1] & 0xf, address, data + 4, status); - break; - } + case UserMemoryRead: + { + uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3]; + _bau.memoryReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[1] & 0xf, address, status); + break; + } - case UserMemoryWrite: - { - uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3]; - _bau.memoryWriteLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[1] & 0xf, address, data + 4, status); - break; - } + case UserMemoryResponse: + { + uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3]; + _bau.memoryReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[1] & 0xf, address, data + 4, status); + break; + } - case UserManufacturerInfoRead: - _bau.userManufacturerInfoLocalConfirm(ack, priority, hopType, tsap, secCtrl, status); - break; + case UserMemoryWrite: + { + uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3]; + _bau.memoryWriteLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[1] & 0xf, address, data + 4, status); + break; + } - case UserManufacturerInfoResponse: - _bau.userManufacturerInfoResponseConfirm(ack, priority, hopType, tsap, secCtrl, data + 1, status); - break; + case UserManufacturerInfoRead: + _bau.userManufacturerInfoLocalConfirm(ack, priority, hopType, tsap, secCtrl, status); + break; - case AuthorizeRequest: - _bau.authorizeLocalConfirm(ack, priority, hopType, tsap, secCtrl, getInt(data + 2), status); - break; + case UserManufacturerInfoResponse: + _bau.userManufacturerInfoResponseConfirm(ack, priority, hopType, tsap, secCtrl, data + 1, status); + break; - case AuthorizeResponse: - _bau.authorizeResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[1], status); - break; + case AuthorizeRequest: + _bau.authorizeLocalConfirm(ack, priority, hopType, tsap, secCtrl, getInt(data + 2), status); + break; - case KeyWrite: - _bau.keyWriteLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[1], getInt(data + 2), status); - break; + case AuthorizeResponse: + _bau.authorizeResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[1], status); + break; - case KeyResponse: - _bau.keyWriteResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[1], status); - break; + case KeyWrite: + _bau.keyWriteLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[1], getInt(data + 2), status); + break; - default: - print("Individual-confirm: unhandled APDU-Type: "); - println(apdu.type()); + case KeyResponse: + _bau.keyWriteResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[1], status); + break; + + default: + print("Individual-confirm: unhandled APDU-Type: "); + println(apdu.type()); + } } -} -void ApplicationLayer::individualSend(AckType ack, HopCountType hopType, Priority priority, uint16_t asap, APDU& apdu, const SecurityControl& secCtrl) -{ - if (asap == _connectedTsap) - dataConnectedRequest(asap, priority, apdu, secCtrl); - else - dataIndividualRequest(ack, hopType, priority, asap, apdu, secCtrl); -} + void ApplicationLayer::individualSend(AckType ack, HopCountType hopType, Priority priority, uint16_t asap, APDU& apdu, const SecurityControl& secCtrl) + { + if (asap == _connectedTsap) + dataConnectedRequest(asap, priority, apdu, secCtrl); + else + dataIndividualRequest(ack, hopType, priority, asap, apdu, secCtrl); + } -bool ApplicationLayer::isConnected() -{ - return (_connectedTsap >= 0); -} + bool ApplicationLayer::isConnected() + { + return (_connectedTsap >= 0); + } -void ApplicationLayer::dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) -{ - (void)secCtrl; // We do not need security related information in the plain application layer - _transportLayer->dataGroupRequest(ack, hopType, priority, tsap, apdu); -} -void ApplicationLayer::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl) -{ - (void)secCtrl; // We do not need security related information in the plain application layer - _transportLayer->dataBroadcastRequest(ack, hopType, SystemPriority, apdu); -} -void ApplicationLayer::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl) -{ - (void)secCtrl; // We do not need security related information in the plain application layer - _transportLayer->dataSystemBroadcastRequest(ack, hopType, SystemPriority, apdu); -} -void ApplicationLayer::dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu, const SecurityControl& secCtrl) -{ - (void)secCtrl; // We do not need security related information in the plain application layer - _transportLayer->dataIndividualRequest(ack, hopType, priority, destination, apdu); -} -void ApplicationLayer::dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu, const SecurityControl& secCtrl) -{ - (void)secCtrl; // We do not need security related information in the plain application layer - // apdu must be valid until it was confirmed - _transportLayer->dataConnectedRequest(tsap, priority, apdu); -} + void ApplicationLayer::dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) + { + (void)secCtrl; // We do not need security related information in the plain application layer + _transportLayer->dataGroupRequest(ack, hopType, priority, tsap, apdu); + } + void ApplicationLayer::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl) + { + (void)secCtrl; // We do not need security related information in the plain application layer + _transportLayer->dataBroadcastRequest(ack, hopType, SystemPriority, apdu); + } + void ApplicationLayer::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl) + { + (void)secCtrl; // We do not need security related information in the plain application layer + _transportLayer->dataSystemBroadcastRequest(ack, hopType, SystemPriority, apdu); + } + void ApplicationLayer::dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu, const SecurityControl& secCtrl) + { + (void)secCtrl; // We do not need security related information in the plain application layer + _transportLayer->dataIndividualRequest(ack, hopType, priority, destination, apdu); + } + void ApplicationLayer::dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu, const SecurityControl& secCtrl) + { + (void)secCtrl; // We do not need security related information in the plain application layer + // apdu must be valid until it was confirmed + _transportLayer->dataConnectedRequest(tsap, priority, apdu); + } +} \ No newline at end of file diff --git a/src/knx/application_layer/application_layer.h b/src/knx/application_layer/application_layer.h index 276ec0db..1d268d53 100644 --- a/src/knx/application_layer/application_layer.h +++ b/src/knx/application_layer/application_layer.h @@ -5,225 +5,229 @@ #include -class AssociationTableObject; -class BusAccessUnit; -class TransportLayer; -/** - * This is an implementation of the application layer as specified in @cite knx:3/5/1. - * It provides methods for the BusAccessUnit to do different things and translates this - * call to an APDU and calls the correct method of the TransportLayer. - * It also takes calls from TransportLayer, decodes the submitted APDU and calls the corresponding - * methods of the BusAccessUnit class. - */ -class ApplicationLayer +namespace Knx { - public: - /** - * The constructor. - * @param assocTable The AssociationTable is used to translate between asap (i.e. group objects) and group addresses. - * @param bau methods are called here depending of the content of the APDU - */ - ApplicationLayer(BusAccessUnit& bau); - /** - * Assigns the TransportLayer to which encoded APDU are submitted to. - */ - void transportLayer(TransportLayer& layer); - - void associationTableObject(AssociationTableObject& assocTable); - - // from transport layer - // Note: without data secure feature, the application layer is just used with SecurityControl.dataSecurity = None - // hooks that can be implemented by derived class (e.g. SecureApplicationLayer) - - #pragma region Transport - Layer - Callbacks - /** - * Somebody send us an APDU via multicast communication. See 3.2 of @cite knx:3/3/4. - * See also ApplicationLayer::dataGroupConfirm and TransportLayer::dataGroupRequest. - * This method is called by the TransportLayer. - * - * @param tsap used the find the correct GroupObject with the help of the AssociationTableObject. - * See 3.1.1 of @cite knx:3/3/7 - * - * @param apdu The submitted APDU. - * - * @param priority The ::Priority of the received request. - * - * @param hopType Should routing be endless or should the NetworkLayer::hopCount be used? See also ::HopCountType. - */ - virtual void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu); - /** - * Report the status of an APDU that we sent via multicast communication back to us. See 3.2 of @cite knx:3/3/4. - * See also ApplicationLayer::dataGroupConfirm and TransportLayer::dataGroupRequest. This method is called by - * the TransportLayer. - * - * @param tsap used the find the correct GroupObject with the help of the AssociationTableObject. - * See 3.1.1 of @cite knx:3/3/7 - * - * @param apdu The submitted APDU. - * - * @param priority The ::Priority of the received request. - * - * @param hopType Should routing be endless or should the NetworkLayer::hopCount be used? See also ::HopCountType. - * - * @param status Was the request successful? - * - * @param ack Did we want a DataLinkLayer acknowledgement? See ::AckType. - */ - virtual void dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status); - virtual void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu); - virtual void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, bool status); - virtual void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu); - virtual void dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, bool status); - virtual void dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu); - virtual void dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status); - virtual void dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu); - virtual void dataConnectedConfirm(uint16_t tsap); - void connectIndication(uint16_t tsap); - void connectConfirm(uint16_t destination, uint16_t tsap, bool status); - void disconnectIndication(uint16_t tsap); - void disconnectConfirm(Priority priority, uint16_t tsap, bool status); - #pragma endregion - - #pragma region from bau - void groupValueReadRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl); - void groupValueReadResponse(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength); - void groupValueWriteRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength); - void individualAddressWriteRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress); - void individualAddressReadRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl); - void individualAddressReadResponse(AckType ack, HopCountType hopType, const SecurityControl& secCtrl); - void individualAddressSerialNumberReadRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber); - void individualAddressSerialNumberReadResponse(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, - uint16_t domainAddress); - void individualAddressSerialNumberWriteRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, - uint16_t newaddress); - void deviceDescriptorReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t descriptorType); - void deviceDescriptorReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t descriptorType, uint8_t* deviceDescriptor); - void connectRequest(uint16_t destination, Priority priority); - void disconnectRequest(Priority priority); - bool isConnected(); - void restartRequest(AckType ack, Priority priority, HopCountType hopType, const SecurityControl& secCtrl); - void restartResponse(AckType ack, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t errorCode, uint16_t processTime); - void propertyValueReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex); - void propertyValueReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length); - void propertyValueExtReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length); - void propertyValueExtWriteConResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t returnCode); - void propertyValueWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length); - void adcReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t channelNr, uint8_t readCount, int16_t value); - void functionPropertyStateResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t* resultData, uint8_t resultLength); - void functionPropertyExtStateResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint16_t objectType, uint8_t objectInstance, uint16_t propertyId, uint8_t* resultData, uint8_t resultLength); - void propertyDescriptionReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex); - void propertyDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, - uint16_t maxNumberOfElements, uint8_t access); - void propertyExtDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint16_t objectType, uint16_t objectInstance, uint16_t propertyId, uint16_t propertyIndex, uint8_t descriptionType, bool writeEnable, uint8_t type, - uint16_t maxNumberOfElements, uint8_t access); - void memoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress); - void memoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data); - void memoryRouterReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data); - void memoryRoutingTableReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data); - void memoryExtReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ReturnCodes code, uint8_t number, - uint32_t memoryAddress, uint8_t* data); - void memoryExtWriteResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ReturnCodes code, uint8_t number, - uint32_t memoryAddress, uint8_t* memoryData); - void memoryWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data); - void userMemoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress); - void userMemoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress, uint8_t* memoryData); - void userMemoryWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress, uint8_t* memoryData); - void userManufacturerInfoReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl); - void userManufacturerInfoReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t* info); - void authorizeRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key); - void authorizeResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level); - void keyWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, uint32_t key); - void keyWriteResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level); - - void systemNetworkParameterReadResponse(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, - uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength, - uint8_t* testResult, uint16_t testResultLength); - void domainAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, - const uint8_t* knxSerialNumber); - void IndividualAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* domainAddress, - const uint8_t* knxSerialNumber); - #pragma endregion - - protected: - #pragma region hooks - void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl); - void dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, - APDU& apdu, const SecurityControl& secCtrl, bool status); - void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl& secCtrl); - void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl, bool status); - void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl& secCtrl); - void dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl, bool status); - void dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl& secCtrl); - void dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl, bool status); - void dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl); - void dataConnectedConfirm(uint16_t tsap, const SecurityControl& secCtrl); - #pragma endregion - - // to transport layer - virtual void dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl); - virtual void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl); - virtual void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl); - virtual void dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu, const SecurityControl& secCtrl); - virtual void dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu, const SecurityControl& secCtrl); // apdu must be valid until it was confirmed - - uint16_t getConnectedTsasp() - { - return _connectedTsap; - } - - // Protected: we need to access it in derived class SecureApplicationLayer - TransportLayer* _transportLayer = 0; - - static const SecurityControl noSecurity; - - private: - void propertyDataSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, - uint8_t length); - void propertyExtDataSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length); - void memorySend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* memoryData); - // Added EC - void memoryRouterSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* memoryData); - void memoryRoutingTableSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* memoryData); - // - void userMemorySend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t number, uint32_t memoryAddress, uint8_t* memoryData); - void groupValueSend(ApduType type, AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t& dataLength); - void individualIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl); - void individualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl, bool status); - void individualSend(AckType ack, HopCountType hopType, Priority priority, uint16_t asap, APDU& apdu, const SecurityControl& secCtrl); - - uint16_t _savedAsapReadRequest = 0; - uint16_t _savedAsapWriteRequest = 0; - uint16_t _savedAsapResponse = 0; - AssociationTableObject* _assocTable = nullptr; - BusAccessUnit& _bau; - - int32_t _connectedTsap = -1; -}; + + class AssociationTableObject; + class BusAccessUnit; + class TransportLayer; + /** + * This is an implementation of the application layer as specified in @cite knx:3/5/1. + * It provides methods for the BusAccessUnit to do different things and translates this + * call to an APDU and calls the correct method of the TransportLayer. + * It also takes calls from TransportLayer, decodes the submitted APDU and calls the corresponding + * methods of the BusAccessUnit class. + */ + class ApplicationLayer + { + public: + /** + * The constructor. + * @param assocTable The AssociationTable is used to translate between asap (i.e. group objects) and group addresses. + * @param bau methods are called here depending of the content of the APDU + */ + ApplicationLayer(BusAccessUnit& bau); + /** + * Assigns the TransportLayer to which encoded APDU are submitted to. + */ + void transportLayer(TransportLayer& layer); + + void associationTableObject(AssociationTableObject& assocTable); + + // from transport layer + // Note: without data secure feature, the application layer is just used with SecurityControl.dataSecurity = None + // hooks that can be implemented by derived class (e.g. SecureApplicationLayer) + + #pragma region Transport - Layer - Callbacks + /** + * Somebody send us an APDU via multicast communication. See 3.2 of @cite knx:3/3/4. + * See also ApplicationLayer::dataGroupConfirm and TransportLayer::dataGroupRequest. + * This method is called by the TransportLayer. + * + * @param tsap used the find the correct GroupObject with the help of the AssociationTableObject. + * See 3.1.1 of @cite knx:3/3/7 + * + * @param apdu The submitted APDU. + * + * @param priority The ::Priority of the received request. + * + * @param hopType Should routing be endless or should the NetworkLayer::hopCount be used? See also ::HopCountType. + */ + virtual void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu); + /** + * Report the status of an APDU that we sent via multicast communication back to us. See 3.2 of @cite knx:3/3/4. + * See also ApplicationLayer::dataGroupConfirm and TransportLayer::dataGroupRequest. This method is called by + * the TransportLayer. + * + * @param tsap used the find the correct GroupObject with the help of the AssociationTableObject. + * See 3.1.1 of @cite knx:3/3/7 + * + * @param apdu The submitted APDU. + * + * @param priority The ::Priority of the received request. + * + * @param hopType Should routing be endless or should the NetworkLayer::hopCount be used? See also ::HopCountType. + * + * @param status Was the request successful? + * + * @param ack Did we want a DataLinkLayer acknowledgement? See ::AckType. + */ + virtual void dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status); + virtual void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu); + virtual void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, bool status); + virtual void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu); + virtual void dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, bool status); + virtual void dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu); + virtual void dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status); + virtual void dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu); + virtual void dataConnectedConfirm(uint16_t tsap); + void connectIndication(uint16_t tsap); + void connectConfirm(uint16_t destination, uint16_t tsap, bool status); + void disconnectIndication(uint16_t tsap); + void disconnectConfirm(Priority priority, uint16_t tsap, bool status); + #pragma endregion + + #pragma region from bau + void groupValueReadRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl); + void groupValueReadResponse(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength); + void groupValueWriteRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength); + void individualAddressWriteRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress); + void individualAddressReadRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl); + void individualAddressReadResponse(AckType ack, HopCountType hopType, const SecurityControl& secCtrl); + void individualAddressSerialNumberReadRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber); + void individualAddressSerialNumberReadResponse(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, + uint16_t domainAddress); + void individualAddressSerialNumberWriteRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, + uint16_t newaddress); + void deviceDescriptorReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t descriptorType); + void deviceDescriptorReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t descriptorType, uint8_t* deviceDescriptor); + void connectRequest(uint16_t destination, Priority priority); + void disconnectRequest(Priority priority); + bool isConnected(); + void restartRequest(AckType ack, Priority priority, HopCountType hopType, const SecurityControl& secCtrl); + void restartResponse(AckType ack, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t errorCode, uint16_t processTime); + void propertyValueReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex); + void propertyValueReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length); + void propertyValueExtReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length); + void propertyValueExtWriteConResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t returnCode); + void propertyValueWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length); + void adcReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t channelNr, uint8_t readCount, int16_t value); + void functionPropertyStateResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t* resultData, uint8_t resultLength); + void functionPropertyExtStateResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint16_t objectType, uint8_t objectInstance, uint16_t propertyId, uint8_t* resultData, uint8_t resultLength); + void propertyDescriptionReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex); + void propertyDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, + uint16_t maxNumberOfElements, uint8_t access); + void propertyExtDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint16_t objectType, uint16_t objectInstance, uint16_t propertyId, uint16_t propertyIndex, uint8_t descriptionType, bool writeEnable, uint8_t type, + uint16_t maxNumberOfElements, uint8_t access); + void memoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress); + void memoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data); + void memoryRouterReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data); + void memoryRoutingTableReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data); + void memoryExtReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ReturnCodes code, uint8_t number, + uint32_t memoryAddress, uint8_t* data); + void memoryExtWriteResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ReturnCodes code, uint8_t number, + uint32_t memoryAddress, uint8_t* memoryData); + void memoryWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data); + void userMemoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress); + void userMemoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress, uint8_t* memoryData); + void userMemoryWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress, uint8_t* memoryData); + void userManufacturerInfoReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl); + void userManufacturerInfoReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t* info); + void authorizeRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key); + void authorizeResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level); + void keyWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, uint32_t key); + void keyWriteResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level); + + void systemNetworkParameterReadResponse(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, + uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength, + uint8_t* testResult, uint16_t testResultLength); + void domainAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, + const uint8_t* knxSerialNumber); + void IndividualAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* domainAddress, + const uint8_t* knxSerialNumber); + #pragma endregion + + protected: + #pragma region hooks + void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl); + void dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, + APDU& apdu, const SecurityControl& secCtrl, bool status); + void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl& secCtrl); + void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl, bool status); + void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl& secCtrl); + void dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl, bool status); + void dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl& secCtrl); + void dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl, bool status); + void dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl); + void dataConnectedConfirm(uint16_t tsap, const SecurityControl& secCtrl); + #pragma endregion + + // to transport layer + virtual void dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl); + virtual void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl); + virtual void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl); + virtual void dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu, const SecurityControl& secCtrl); + virtual void dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu, const SecurityControl& secCtrl); // apdu must be valid until it was confirmed + + uint16_t getConnectedTsasp() + { + return _connectedTsap; + } + + // Protected: we need to access it in derived class SecureApplicationLayer + TransportLayer* _transportLayer = 0; + + static const SecurityControl noSecurity; + + private: + void propertyDataSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, + uint8_t length); + void propertyExtDataSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length); + void memorySend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* memoryData); + // Added EC + void memoryRouterSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* memoryData); + void memoryRoutingTableSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* memoryData); + // + void userMemorySend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t number, uint32_t memoryAddress, uint8_t* memoryData); + void groupValueSend(ApduType type, AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t& dataLength); + void individualIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl); + void individualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl, bool status); + void individualSend(AckType ack, HopCountType hopType, Priority priority, uint16_t asap, APDU& apdu, const SecurityControl& secCtrl); + + uint16_t _savedAsapReadRequest = 0; + uint16_t _savedAsapWriteRequest = 0; + uint16_t _savedAsapResponse = 0; + AssociationTableObject* _assocTable = nullptr; + BusAccessUnit& _bau; + + int32_t _connectedTsap = -1; + }; +} \ No newline at end of file diff --git a/src/knx/bau/bau.cpp b/src/knx/bau/bau.cpp index e4810164..2315c644 100644 --- a/src/knx/bau/bau.cpp +++ b/src/knx/bau/bau.cpp @@ -1,392 +1,397 @@ #include "bau.h" -void BusAccessUnit::groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, bool status) -{ -} - -void BusAccessUnit::groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl) -{ -} - -void BusAccessUnit::groupValueReadResponseConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopTtype, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength, bool status) -{ -} - -void BusAccessUnit::groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength) -{ -} - -void BusAccessUnit::groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength, bool status) -{ -} - -void BusAccessUnit::groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength) -{ -} - -void BusAccessUnit::individualAddressWriteLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress, bool status) -{ -} - -void BusAccessUnit::individualAddressWriteIndication(HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress) -{ -} - -void BusAccessUnit::individualAddressReadLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, bool status) -{ -} - -void BusAccessUnit::individualAddressReadIndication(HopCountType hopType, const SecurityControl& secCtrl) -{ -} - -void BusAccessUnit::individualAddressReadResponseConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, bool status) -{ -} - -void BusAccessUnit::individualAddressReadAppLayerConfirm(HopCountType hopType, const SecurityControl& secCtrl, uint16_t individualAddress) -{ -} - -void BusAccessUnit::individualAddressSerialNumberReadLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, bool status) -{ -} - -void BusAccessUnit::individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber) -{ -} - -void BusAccessUnit::individualAddressSerialNumberReadResponseConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, uint16_t domainAddress, bool status) -{ -} - -void BusAccessUnit::individualAddressSerialNumberReadAppLayerConfirm(HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, uint16_t individualAddress, uint16_t domainAddress) -{ -} - -void BusAccessUnit::individualAddressSerialNumberWriteLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, uint16_t newaddress, bool status) -{ -} - -void BusAccessUnit::individualAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newIndividualAddress, - uint8_t* knxSerialNumber) -{ -} - -void BusAccessUnit::deviceDescriptorReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptorType, bool status) -{ -} - -void BusAccessUnit::deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptorType) -{ -} - -void BusAccessUnit::deviceDescriptorReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptor_type, - uint8_t* device_descriptor, bool status) -{ -} - -void BusAccessUnit::deviceDescriptorReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptortype, uint8_t* deviceDescriptor) -{ -} - -void BusAccessUnit::restartRequestLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, bool status) -{ -} - -void BusAccessUnit::restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, RestartType restartType, EraseCode eraseCode, uint8_t channel) -{ -} - -void BusAccessUnit::propertyValueReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, bool status) -{ -} - -void BusAccessUnit::propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) -{ -} - -void BusAccessUnit::propertyValueExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) -{ -} - -void BusAccessUnit::functionPropertyCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t* data, uint8_t length) -{ -} - -void BusAccessUnit::functionPropertyStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t* data, uint8_t length) -{ -} - -void BusAccessUnit::functionPropertyExtCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t* data, uint8_t length) -{ -} - -void BusAccessUnit::functionPropertyExtStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t* data, uint8_t length) -{ -} - -void BusAccessUnit::propertyValueReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool status) -{ -} - -void BusAccessUnit::propertyValueReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) -{ -} - -void BusAccessUnit::propertyValueWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool status) -{ -} - -void BusAccessUnit::propertyValueWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) -{ -} - -void BusAccessUnit::propertyValueExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool confirmed) -{ -} - -void BusAccessUnit::propertyDescriptionReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool status) -{ -} - -void BusAccessUnit::propertyExtDescriptionReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint16_t objectIndex, uint8_t propertyId, uint16_t propertyIndex, bool status) -{ -} - -void BusAccessUnit::propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex) -{ -} - -void BusAccessUnit::propertyExtDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint16_t objectType, uint16_t objectInstance, uint16_t propertyId, uint8_t descriptionType, uint16_t propertyIndex) -{ -} -void BusAccessUnit::propertyDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, uint16_t maxNumberOfElements, uint8_t access) +namespace Knx { -} -void BusAccessUnit::propertyDescriptionReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, uint16_t maxNumberOfElements, uint8_t access, bool status) -{ -} - -void BusAccessUnit::propertyDescriptionReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, uint16_t maxNumberOfElements, uint8_t access) -{ -} - -void BusAccessUnit::memoryReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, bool status) -{ -} - -void BusAccessUnit::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress) -{ -} - -void BusAccessUnit::memoryReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data, bool status) -{ -} - -void BusAccessUnit::memoryReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data) -{ -} + void BusAccessUnit::groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, bool status) + { + } -void BusAccessUnit::memoryWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data, bool status) -{ -} + void BusAccessUnit::groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl) + { + } -void BusAccessUnit::memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data) -{ -} - -void BusAccessUnit::memoryRouterWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data) -{ -} -void BusAccessUnit::memoryRouterReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data) -{ -} -void BusAccessUnit::memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress) -{ -} -void BusAccessUnit::memoryRoutingTableReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data) -{ -} -void BusAccessUnit::memoryRoutingTableWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data) -{ -} + void BusAccessUnit::groupValueReadResponseConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopTtype, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength, bool status) + { + } -void BusAccessUnit::memoryExtReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, bool status) -{ -} + void BusAccessUnit::groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength) + { + } -void BusAccessUnit::memoryExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress) -{ -} + void BusAccessUnit::groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength, bool status) + { + } -void BusAccessUnit::memoryExtReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data, bool status) -{ -} + void BusAccessUnit::groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength) + { + } -void BusAccessUnit::memoryExtReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data) -{ -} + void BusAccessUnit::individualAddressWriteLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress, bool status) + { + } -void BusAccessUnit::memoryExtWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data, bool status) -{ -} + void BusAccessUnit::individualAddressWriteIndication(HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress) + { + } -void BusAccessUnit::memoryExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data) -{ -} + void BusAccessUnit::individualAddressReadLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, bool status) + { + } -void BusAccessUnit::memoryExtWriteResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data, bool status) -{ -} + void BusAccessUnit::individualAddressReadIndication(HopCountType hopType, const SecurityControl& secCtrl) + { + } -void BusAccessUnit::memoryExtWriteAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data) -{ -} + void BusAccessUnit::individualAddressReadResponseConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, bool status) + { + } -void BusAccessUnit::userMemoryReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, bool status) -{ -} + void BusAccessUnit::individualAddressReadAppLayerConfirm(HopCountType hopType, const SecurityControl& secCtrl, uint16_t individualAddress) + { + } -void BusAccessUnit::userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress) -{ -} + void BusAccessUnit::individualAddressSerialNumberReadLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, bool status) + { + } -void BusAccessUnit::userMemoryReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* memoryData, bool status) -{ -} + void BusAccessUnit::individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber) + { + } -void BusAccessUnit::userMemoryReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* memoryData) -{ -} + void BusAccessUnit::individualAddressSerialNumberReadResponseConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, uint16_t domainAddress, bool status) + { + } -void BusAccessUnit::userMemoryWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* memoryData, bool status) -{ -} + void BusAccessUnit::individualAddressSerialNumberReadAppLayerConfirm(HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, uint16_t individualAddress, uint16_t domainAddress) + { + } -void BusAccessUnit::userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* memoryData) -{ -} + void BusAccessUnit::individualAddressSerialNumberWriteLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, uint16_t newaddress, bool status) + { + } -void BusAccessUnit::userManufacturerInfoLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, bool status) -{ -} + void BusAccessUnit::individualAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newIndividualAddress, + uint8_t* knxSerialNumber) + { + } -void BusAccessUnit::userManufacturerInfoIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl) -{ -} + void BusAccessUnit::deviceDescriptorReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptorType, bool status) + { + } -void BusAccessUnit::userManufacturerInfoResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t* info, bool status) -{ -} + void BusAccessUnit::deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptorType) + { + } -void BusAccessUnit::userManufacturerInfoAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t* info) -{ -} + void BusAccessUnit::deviceDescriptorReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptor_type, + uint8_t* device_descriptor, bool status) + { + } -void BusAccessUnit::authorizeLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key, bool status) -{ -} + void BusAccessUnit::deviceDescriptorReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptortype, uint8_t* deviceDescriptor) + { + } -void BusAccessUnit::authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key) -{ -} + void BusAccessUnit::restartRequestLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, bool status) + { + } -void BusAccessUnit::authorizeResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, bool status) -{ -} + void BusAccessUnit::restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, RestartType restartType, EraseCode eraseCode, uint8_t channel) + { + } -void BusAccessUnit::authorizeAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level) -{ -} - -void BusAccessUnit::keyWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, uint32_t key, bool status) -{ -} - -void BusAccessUnit::keyWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, uint32_t key) -{ -} - -void BusAccessUnit::keyWriteResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, bool status) -{ -} - -void BusAccessUnit::keyWriteAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level) -{ -} - -void BusAccessUnit::connectConfirm(uint16_t destination) -{ -} - -void BusAccessUnit::systemNetworkParameterReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, - uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength) -{ -} - -void BusAccessUnit::domainAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, - const uint8_t* knxSerialNumber) -{ -} - -void BusAccessUnit::domainAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber) -{ -} - -void BusAccessUnit::systemNetworkParameterReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, - uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength, bool status) -{ -} - -void BusAccessUnit::domainAddressSerialNumberWriteLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, - const uint8_t* knxSerialNumber, bool status) -{ -} - -void BusAccessUnit::domainAddressSerialNumberReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber, bool status) -{ -} - -void BusAccessUnit::propertyValueRead(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, - uint8_t& numberOfElements, uint16_t startIndex, - uint8_t** data, uint32_t& length) -{ -} - -void BusAccessUnit::propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, - uint8_t& numberOfElements, uint16_t startIndex, - uint8_t* data, uint32_t length) -{ -} - -void BusAccessUnit::beforeRestartCallback(BeforeRestartCallback func) -{ -} - -BeforeRestartCallback BusAccessUnit::beforeRestartCallback() -{ - return 0; -} - -void BusAccessUnit::functionPropertyCallback(FunctionPropertyCallback func) -{ -} - -FunctionPropertyCallback BusAccessUnit::functionPropertyCallback() -{ - return 0; -} - -void BusAccessUnit::functionPropertyStateCallback(FunctionPropertyCallback func) -{ -} - -FunctionPropertyCallback BusAccessUnit::functionPropertyStateCallback() -{ - return 0; + void BusAccessUnit::propertyValueReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, bool status) + { + } + + void BusAccessUnit::propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) + { + } + + void BusAccessUnit::propertyValueExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) + { + } + + void BusAccessUnit::functionPropertyCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t* data, uint8_t length) + { + } + + void BusAccessUnit::functionPropertyStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t* data, uint8_t length) + { + } + + void BusAccessUnit::functionPropertyExtCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t* data, uint8_t length) + { + } + + void BusAccessUnit::functionPropertyExtStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t* data, uint8_t length) + { + } + + void BusAccessUnit::propertyValueReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool status) + { + } + + void BusAccessUnit::propertyValueReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) + { + } + + void BusAccessUnit::propertyValueWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool status) + { + } + + void BusAccessUnit::propertyValueWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) + { + } + + void BusAccessUnit::propertyValueExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool confirmed) + { + } + + void BusAccessUnit::propertyDescriptionReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool status) + { + } + + void BusAccessUnit::propertyExtDescriptionReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint16_t objectIndex, uint8_t propertyId, uint16_t propertyIndex, bool status) + { + } + + void BusAccessUnit::propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex) + { + } + + void BusAccessUnit::propertyExtDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint16_t objectType, uint16_t objectInstance, uint16_t propertyId, uint8_t descriptionType, uint16_t propertyIndex) + { + } + + void BusAccessUnit::propertyDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, uint16_t maxNumberOfElements, uint8_t access) + { + } + + void BusAccessUnit::propertyDescriptionReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, uint16_t maxNumberOfElements, uint8_t access, bool status) + { + } + + void BusAccessUnit::propertyDescriptionReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, uint16_t maxNumberOfElements, uint8_t access) + { + } + + void BusAccessUnit::memoryReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, bool status) + { + } + + void BusAccessUnit::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress) + { + } + + void BusAccessUnit::memoryReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data, bool status) + { + } + + void BusAccessUnit::memoryReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data) + { + } + + void BusAccessUnit::memoryWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data, bool status) + { + } + + void BusAccessUnit::memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data) + { + } + + void BusAccessUnit::memoryRouterWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data) + { + } + void BusAccessUnit::memoryRouterReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data) + { + } + void BusAccessUnit::memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress) + { + } + void BusAccessUnit::memoryRoutingTableReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data) + { + } + void BusAccessUnit::memoryRoutingTableWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data) + { + } + + void BusAccessUnit::memoryExtReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, bool status) + { + } + + void BusAccessUnit::memoryExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress) + { + } + + void BusAccessUnit::memoryExtReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data, bool status) + { + } + + void BusAccessUnit::memoryExtReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data) + { + } + + void BusAccessUnit::memoryExtWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data, bool status) + { + } + + void BusAccessUnit::memoryExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data) + { + } + + void BusAccessUnit::memoryExtWriteResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data, bool status) + { + } + + void BusAccessUnit::memoryExtWriteAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data) + { + } + + void BusAccessUnit::userMemoryReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, bool status) + { + } + + void BusAccessUnit::userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress) + { + } + + void BusAccessUnit::userMemoryReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* memoryData, bool status) + { + } + + void BusAccessUnit::userMemoryReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* memoryData) + { + } + + void BusAccessUnit::userMemoryWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* memoryData, bool status) + { + } + + void BusAccessUnit::userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* memoryData) + { + } + + void BusAccessUnit::userManufacturerInfoLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, bool status) + { + } + + void BusAccessUnit::userManufacturerInfoIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl) + { + } + + void BusAccessUnit::userManufacturerInfoResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t* info, bool status) + { + } + + void BusAccessUnit::userManufacturerInfoAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t* info) + { + } + + void BusAccessUnit::authorizeLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key, bool status) + { + } + + void BusAccessUnit::authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key) + { + } + + void BusAccessUnit::authorizeResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, bool status) + { + } + + void BusAccessUnit::authorizeAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level) + { + } + + void BusAccessUnit::keyWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, uint32_t key, bool status) + { + } + + void BusAccessUnit::keyWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, uint32_t key) + { + } + + void BusAccessUnit::keyWriteResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, bool status) + { + } + + void BusAccessUnit::keyWriteAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level) + { + } + + void BusAccessUnit::connectConfirm(uint16_t destination) + { + } + + void BusAccessUnit::systemNetworkParameterReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, + uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength) + { + } + + void BusAccessUnit::domainAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, + const uint8_t* knxSerialNumber) + { + } + + void BusAccessUnit::domainAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber) + { + } + + void BusAccessUnit::systemNetworkParameterReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, + uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength, bool status) + { + } + + void BusAccessUnit::domainAddressSerialNumberWriteLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, + const uint8_t* knxSerialNumber, bool status) + { + } + + void BusAccessUnit::domainAddressSerialNumberReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber, bool status) + { + } + + void BusAccessUnit::propertyValueRead(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, + uint8_t& numberOfElements, uint16_t startIndex, + uint8_t** data, uint32_t& length) + { + } + + void BusAccessUnit::propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, + uint8_t& numberOfElements, uint16_t startIndex, + uint8_t* data, uint32_t length) + { + } + + void BusAccessUnit::beforeRestartCallback(BeforeRestartCallback func) + { + } + + BeforeRestartCallback BusAccessUnit::beforeRestartCallback() + { + return 0; + } + + void BusAccessUnit::functionPropertyCallback(FunctionPropertyCallback func) + { + } + + FunctionPropertyCallback BusAccessUnit::functionPropertyCallback() + { + return 0; + } + + void BusAccessUnit::functionPropertyStateCallback(FunctionPropertyCallback func) + { + } + + FunctionPropertyCallback BusAccessUnit::functionPropertyStateCallback() + { + return 0; + } } \ No newline at end of file diff --git a/src/knx/bau/bau.h b/src/knx/bau/bau.h index 3a3de51a..02da05c6 100644 --- a/src/knx/bau/bau.h +++ b/src/knx/bau/bau.h @@ -5,182 +5,185 @@ #include -typedef void (*BeforeRestartCallback)(void); -typedef bool (*FunctionPropertyCallback)(uint8_t objectIndex, uint8_t propertyId, uint8_t length, uint8_t* data, uint8_t* resultData, uint8_t& resultLength); - -class BusAccessUnit +namespace Knx { - public: - virtual ~BusAccessUnit() {} - virtual void groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, bool status); - virtual void groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl); - virtual void groupValueReadResponseConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopTtype, const SecurityControl& secCtrl, - uint8_t* data, uint8_t dataLength, bool status); - virtual void groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, - uint8_t* data, uint8_t dataLength); - virtual void groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, - uint8_t* data, uint8_t dataLength, bool status); - virtual void groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, - uint8_t* data, uint8_t dataLength); - virtual void individualAddressWriteLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, - uint16_t newaddress, bool status); - virtual void individualAddressWriteIndication(HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress); - virtual void individualAddressReadLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, bool status); - virtual void individualAddressReadIndication(HopCountType hopType, const SecurityControl& secCtrl); - virtual void individualAddressReadResponseConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, bool status); - virtual void individualAddressReadAppLayerConfirm(HopCountType hopType, const SecurityControl& secCtrl, uint16_t individualAddress); - virtual void individualAddressSerialNumberReadLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, - uint8_t* serialNumber, bool status); - virtual void individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber); - virtual void individualAddressSerialNumberReadResponseConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, - uint8_t* serialNumber, uint16_t domainAddress, bool status); - virtual void individualAddressSerialNumberReadAppLayerConfirm(HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, - uint16_t individualAddress, uint16_t domainAddress); - virtual void individualAddressSerialNumberWriteLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, - uint16_t newaddress, bool status); - virtual void individualAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newIndividualAddress, - uint8_t* knxSerialNumber); - virtual void deviceDescriptorReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t descriptorType, bool status); - virtual void deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptorType); - virtual void deviceDescriptorReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t descriptor_type, uint8_t* device_descriptor, bool status); - virtual void deviceDescriptorReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t descriptortype, uint8_t* deviceDescriptor); - virtual void restartRequestLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, bool status); - virtual void restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, RestartType restartType, EraseCode eraseCode, uint8_t channel); - virtual void propertyValueReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, bool status); - virtual void propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex); - virtual void propertyValueExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex); - virtual void functionPropertyCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t* data, uint8_t length); - virtual void functionPropertyStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t* data, uint8_t length); - virtual void functionPropertyExtCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, - uint8_t propertyId, uint8_t* data, uint8_t length); - virtual void functionPropertyExtStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, - uint8_t propertyId, uint8_t* data, uint8_t length); - virtual void propertyValueReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool status); - virtual void propertyValueReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length); - virtual void propertyValueWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool status); - virtual void propertyValueWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length); - virtual void propertyValueExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool confirmed); - virtual void propertyDescriptionReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool status); - virtual void propertyExtDescriptionReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint16_t objectIndex, uint8_t propertyId, uint16_t propertyIndex, bool status); - virtual void propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex); - virtual void propertyExtDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint16_t objectType, uint16_t objectInstance, uint16_t propertyId, uint8_t descriptionType, uint16_t propertyIndex); - virtual void propertyDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, - uint16_t maxNumberOfElements, uint8_t access); - virtual void propertyDescriptionReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, - uint16_t maxNumberOfElements, uint8_t access, bool status); - virtual void propertyDescriptionReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, - uint16_t maxNumberOfElements, uint8_t access); - virtual void memoryReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, bool status); - virtual void memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress); - virtual void memoryReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data, bool status); - virtual void memoryReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + typedef void (*BeforeRestartCallback)(void); + typedef bool (*FunctionPropertyCallback)(uint8_t objectIndex, uint8_t propertyId, uint8_t length, uint8_t* data, uint8_t* resultData, uint8_t& resultLength); + + class BusAccessUnit + { + public: + virtual ~BusAccessUnit() {} + virtual void groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, bool status); + virtual void groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl); + virtual void groupValueReadResponseConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopTtype, const SecurityControl& secCtrl, + uint8_t* data, uint8_t dataLength, bool status); + virtual void groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, + uint8_t* data, uint8_t dataLength); + virtual void groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, + uint8_t* data, uint8_t dataLength, bool status); + virtual void groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, + uint8_t* data, uint8_t dataLength); + virtual void individualAddressWriteLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, + uint16_t newaddress, bool status); + virtual void individualAddressWriteIndication(HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress); + virtual void individualAddressReadLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, bool status); + virtual void individualAddressReadIndication(HopCountType hopType, const SecurityControl& secCtrl); + virtual void individualAddressReadResponseConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, bool status); + virtual void individualAddressReadAppLayerConfirm(HopCountType hopType, const SecurityControl& secCtrl, uint16_t individualAddress); + virtual void individualAddressSerialNumberReadLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, + uint8_t* serialNumber, bool status); + virtual void individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber); + virtual void individualAddressSerialNumberReadResponseConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, + uint8_t* serialNumber, uint16_t domainAddress, bool status); + virtual void individualAddressSerialNumberReadAppLayerConfirm(HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, + uint16_t individualAddress, uint16_t domainAddress); + virtual void individualAddressSerialNumberWriteLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, + uint16_t newaddress, bool status); + virtual void individualAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newIndividualAddress, + uint8_t* knxSerialNumber); + virtual void deviceDescriptorReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t descriptorType, bool status); + virtual void deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptorType); + virtual void deviceDescriptorReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t descriptor_type, uint8_t* device_descriptor, bool status); + virtual void deviceDescriptorReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t descriptortype, uint8_t* deviceDescriptor); + virtual void restartRequestLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, bool status); + virtual void restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, RestartType restartType, EraseCode eraseCode, uint8_t channel); + virtual void propertyValueReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, bool status); + virtual void propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex); + virtual void propertyValueExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex); + virtual void functionPropertyCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t* data, uint8_t length); + virtual void functionPropertyStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t* data, uint8_t length); + virtual void functionPropertyExtCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, + uint8_t propertyId, uint8_t* data, uint8_t length); + virtual void functionPropertyExtStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, + uint8_t propertyId, uint8_t* data, uint8_t length); + virtual void propertyValueReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool status); + virtual void propertyValueReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length); + virtual void propertyValueWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool status); + virtual void propertyValueWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length); + virtual void propertyValueExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool confirmed); + virtual void propertyDescriptionReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool status); + virtual void propertyExtDescriptionReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint16_t objectIndex, uint8_t propertyId, uint16_t propertyIndex, bool status); + virtual void propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex); + virtual void propertyExtDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint16_t objectType, uint16_t objectInstance, uint16_t propertyId, uint8_t descriptionType, uint16_t propertyIndex); + virtual void propertyDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, + uint16_t maxNumberOfElements, uint8_t access); + virtual void propertyDescriptionReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, + uint16_t maxNumberOfElements, uint8_t access, bool status); + virtual void propertyDescriptionReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, + uint16_t maxNumberOfElements, uint8_t access); + virtual void memoryReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, bool status); + virtual void memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress); + virtual void memoryReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data, bool status); + virtual void memoryReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data); + virtual void memoryWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data, bool status); + virtual void memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data); - virtual void memoryWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data, bool status); - virtual void memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data); - virtual void memoryRouterWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data); - virtual void memoryRouterReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data); - virtual void memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress); - virtual void memoryRoutingTableReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data); - virtual void memoryRoutingTableWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data); - virtual void memoryExtReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress, bool status); - virtual void memoryExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress); - virtual void memoryExtReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress, uint8_t* data, bool status); - virtual void memoryExtReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress, uint8_t* data); - virtual void memoryExtWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress, uint8_t* data, bool status); - virtual void memoryExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress, uint8_t* data); - virtual void memoryExtWriteResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress, uint8_t* data, bool status); - virtual void memoryExtWriteAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress, uint8_t* data); - virtual void userMemoryReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress, bool status); - virtual void userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress); - virtual void userMemoryReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress, uint8_t* memoryData, bool status); - virtual void userMemoryReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress, uint8_t* memoryData); - virtual void userMemoryWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress, uint8_t* memoryData, bool status); - virtual void userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress, uint8_t* memoryData); - virtual void userManufacturerInfoLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, bool status); - virtual void userManufacturerInfoIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl); - virtual void userManufacturerInfoResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t* info, bool status); - virtual void userManufacturerInfoAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t* info); - virtual void authorizeLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key, bool status); - virtual void authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key); - virtual void authorizeResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, - bool status); - virtual void authorizeAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level); - virtual void keyWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, - uint32_t key, bool status); - virtual void keyWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, - uint32_t key); - virtual void keyWriteResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, - bool status); - virtual void keyWriteAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level); - virtual void connectConfirm(uint16_t destination); - virtual void systemNetworkParameterReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, - uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength); + virtual void memoryRouterWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data); + virtual void memoryRouterReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data); + virtual void memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress); + virtual void memoryRoutingTableReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data); + virtual void memoryRoutingTableWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data); + virtual void memoryExtReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress, bool status); + virtual void memoryExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress); + virtual void memoryExtReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress, uint8_t* data, bool status); + virtual void memoryExtReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress, uint8_t* data); + virtual void memoryExtWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress, uint8_t* data, bool status); + virtual void memoryExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress, uint8_t* data); + virtual void memoryExtWriteResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress, uint8_t* data, bool status); + virtual void memoryExtWriteAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress, uint8_t* data); + virtual void userMemoryReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress, bool status); + virtual void userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress); + virtual void userMemoryReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress, uint8_t* memoryData, bool status); + virtual void userMemoryReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress, uint8_t* memoryData); + virtual void userMemoryWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress, uint8_t* memoryData, bool status); + virtual void userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress, uint8_t* memoryData); + virtual void userManufacturerInfoLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, bool status); + virtual void userManufacturerInfoIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl); + virtual void userManufacturerInfoResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t* info, bool status); + virtual void userManufacturerInfoAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint8_t* info); + virtual void authorizeLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key, bool status); + virtual void authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key); + virtual void authorizeResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, + bool status); + virtual void authorizeAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level); + virtual void keyWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, + uint32_t key, bool status); + virtual void keyWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, + uint32_t key); + virtual void keyWriteResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, + bool status); + virtual void keyWriteAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level); + virtual void connectConfirm(uint16_t destination); + virtual void systemNetworkParameterReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, + uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength); - virtual void domainAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, - const uint8_t* knxSerialNumber); + virtual void domainAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, + const uint8_t* knxSerialNumber); - virtual void domainAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber); + virtual void domainAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber); - virtual void systemNetworkParameterReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, - uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength, bool status); + virtual void systemNetworkParameterReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, + uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength, bool status); - virtual void domainAddressSerialNumberWriteLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, - const uint8_t* knxSerialNumber, bool status); + virtual void domainAddressSerialNumberWriteLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, + const uint8_t* knxSerialNumber, bool status); - virtual void domainAddressSerialNumberReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber, bool status); + virtual void domainAddressSerialNumberReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber, bool status); - virtual void propertyValueRead(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, - uint8_t& numberOfElements, uint16_t startIndex, - uint8_t** data, uint32_t& length); + virtual void propertyValueRead(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, + uint8_t& numberOfElements, uint16_t startIndex, + uint8_t** data, uint32_t& length); - virtual void propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, - uint8_t& numberOfElements, uint16_t startIndex, - uint8_t* data, uint32_t length); - virtual void beforeRestartCallback(BeforeRestartCallback func); - virtual BeforeRestartCallback beforeRestartCallback(); - virtual void functionPropertyCallback(FunctionPropertyCallback func); - virtual FunctionPropertyCallback functionPropertyCallback(); - virtual void functionPropertyStateCallback(FunctionPropertyCallback func); - virtual FunctionPropertyCallback functionPropertyStateCallback(); -}; + virtual void propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, + uint8_t& numberOfElements, uint16_t startIndex, + uint8_t* data, uint32_t length); + virtual void beforeRestartCallback(BeforeRestartCallback func); + virtual BeforeRestartCallback beforeRestartCallback(); + virtual void functionPropertyCallback(FunctionPropertyCallback func); + virtual FunctionPropertyCallback functionPropertyCallback(); + virtual void functionPropertyStateCallback(FunctionPropertyCallback func); + virtual FunctionPropertyCallback functionPropertyStateCallback(); + }; +} \ No newline at end of file diff --git a/src/knx/bau/bau_systemB.cpp b/src/knx/bau/bau_systemB.cpp index 85787e27..d16c2e4a 100644 --- a/src/knx/bau/bau_systemB.cpp +++ b/src/knx/bau/bau_systemB.cpp @@ -5,423 +5,433 @@ #include #include -enum NmReadSerialNumberType +namespace Knx { - NM_Read_SerialNumber_By_ProgrammingMode = 0x01, - NM_Read_SerialNumber_By_ExFactoryState = 0x02, - NM_Read_SerialNumber_By_PowerReset = 0x03, - NM_Read_SerialNumber_By_ManufacturerSpecific = 0xFE, -}; - -static constexpr auto kFunctionPropertyResultBufferMaxSize = 0xFF; -static constexpr auto kRestartProcessTime = 3; - -BauSystemB::BauSystemB(Platform& platform): _memory(platform, _deviceObj), - _appProgram(_memory), - _platform(platform) -{ - _memory.addSaveRestore(&_appProgram); -} -void BauSystemB::readMemory() -{ - _memory.readMemory(); -} + enum NmReadSerialNumberType + { + NM_Read_SerialNumber_By_ProgrammingMode = 0x01, + NM_Read_SerialNumber_By_ExFactoryState = 0x02, + NM_Read_SerialNumber_By_PowerReset = 0x03, + NM_Read_SerialNumber_By_ManufacturerSpecific = 0xFE, + }; + + static constexpr auto kFunctionPropertyResultBufferMaxSize = 0xFF; + static constexpr auto kRestartProcessTime = 3; + + BauSystemB::BauSystemB(Platform& platform): _memory(platform, _deviceObj), + _appProgram(_memory), + _platform(platform) + { + _memory.addSaveRestore(&_appProgram); + } -void BauSystemB::writeMemory() -{ - _memory.writeMemory(); -} + void BauSystemB::readMemory() + { + _memory.readMemory(); + } -Platform& BauSystemB::platform() -{ - return _platform; -} + void BauSystemB::writeMemory() + { + _memory.writeMemory(); + } -ApplicationProgramObject& BauSystemB::parameters() -{ - return _appProgram; -} + Platform& BauSystemB::platform() + { + return _platform; + } -DeviceObject& BauSystemB::deviceObject() -{ - return _deviceObj; -} + ApplicationProgramObject& BauSystemB::parameters() + { + return _appProgram; + } -uint8_t BauSystemB::checkmasterResetValidity(EraseCode eraseCode, uint8_t channel) -{ - static constexpr uint8_t successCode = 0x00; // Where does this come from? It is the code for "success". - static constexpr uint8_t invalidEraseCode = 0x02; // Where does this come from? It is the error code for "unspported erase code". + DeviceObject& BauSystemB::deviceObject() + { + return _deviceObj; + } - switch (eraseCode) + uint8_t BauSystemB::checkmasterResetValidity(EraseCode eraseCode, uint8_t channel) { - case EraseCode::ConfirmedRestart: - { - println("Confirmed restart requested."); - return successCode; - } + static constexpr uint8_t successCode = 0x00; // Where does this come from? It is the code for "success". + static constexpr uint8_t invalidEraseCode = 0x02; // Where does this come from? It is the error code for "unspported erase code". - case EraseCode::ResetAP: + switch (eraseCode) { - // TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER) - println("ResetAP requested. Not implemented yet."); - return successCode; - } + case EraseCode::ConfirmedRestart: + { + println("Confirmed restart requested."); + return successCode; + } - case EraseCode::ResetIA: - { - // TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER) - println("ResetIA requested. Not implemented yet."); - return successCode; - } + case EraseCode::ResetAP: + { + // TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER) + println("ResetAP requested. Not implemented yet."); + return successCode; + } - case EraseCode::ResetLinks: - { - // TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER) - println("ResetLinks requested. Not implemented yet."); - return successCode; - } + case EraseCode::ResetIA: + { + // TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER) + println("ResetIA requested. Not implemented yet."); + return successCode; + } - case EraseCode::ResetParam: - { - // TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER) - println("ResetParam requested. Not implemented yet."); - return successCode; - } + case EraseCode::ResetLinks: + { + // TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER) + println("ResetLinks requested. Not implemented yet."); + return successCode; + } - case EraseCode::FactoryReset: - { - // TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER) - println("Factory reset requested. type: with IA"); - return successCode; - } + case EraseCode::ResetParam: + { + // TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER) + println("ResetParam requested. Not implemented yet."); + return successCode; + } - case EraseCode::FactoryResetWithoutIA: - { - // TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER) - println("Factory reset requested. type: without IA"); - return successCode; - } + case EraseCode::FactoryReset: + { + // TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER) + println("Factory reset requested. type: with IA"); + return successCode; + } - default: - { - print("Unhandled erase code: "); - println(eraseCode, HEX); - return invalidEraseCode; + case EraseCode::FactoryResetWithoutIA: + { + // TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER) + println("Factory reset requested. type: without IA"); + return successCode; + } + + default: + { + print("Unhandled erase code: "); + println(eraseCode, HEX); + return invalidEraseCode; + } } } -} -void BauSystemB::deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptorType) -{ - if (descriptorType != 0) - descriptorType = 0x3f; - - uint8_t data[2]; - pushWord(_deviceObj.maskVersion(), data); - applicationLayer().deviceDescriptorReadResponse(AckRequested, priority, hopType, asap, secCtrl, descriptorType, data); -} -void BauSystemB::memoryRouterWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data) -{ - print("Writing memory at: "); - print(memoryAddress, HEX); - print(" length: "); - print(number); - print(" data: "); - printHex("=>", data, number); - _memory.writeMemory(memoryAddress, number, data); + void BauSystemB::deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptorType) + { + if (descriptorType != 0) + descriptorType = 0x3f; - if (_deviceObj.verifyMode()) + uint8_t data[2]; + pushWord(_deviceObj.maskVersion(), data); + applicationLayer().deviceDescriptorReadResponse(AckRequested, priority, hopType, asap, secCtrl, descriptorType, data); + } + void BauSystemB::memoryRouterWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data) { - print("Sending Read indication"); - memoryRouterReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress, data); + print("Writing memory at: "); + print(memoryAddress, HEX); + print(" length: "); + print(number); + print(" data: "); + printHex("=>", data, number); + _memory.writeMemory(memoryAddress, number, data); + + if (_deviceObj.verifyMode()) + { + print("Sending Read indication"); + memoryRouterReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress, data); + } } -} - -void BauSystemB::memoryRouterReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data) -{ - applicationLayer().memoryRouterReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, data); -} -void BauSystemB::memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data) -{ - applicationLayer().memoryRoutingTableReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, data); -} -void BauSystemB::memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress) -{ - memoryRoutingTableReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress, _memory.toAbsolute(memoryAddress)); -} - -void BauSystemB::memoryRoutingTableWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data) -{ - print("Writing memory at: "); - print(memoryAddress, HEX); - print(" length: "); - print(number); - print(" data: "); - printHex("=>", data, number); - _memory.writeMemory(memoryAddress, number, data); - - if (_deviceObj.verifyMode()) - memoryRoutingTableReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress, data); -} - -void BauSystemB::memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data) -{ - _memory.writeMemory(memoryAddress, number, data); - - if (_deviceObj.verifyMode()) - memoryReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress, data); -} + void BauSystemB::memoryRouterReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data) + { + applicationLayer().memoryRouterReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, data); + } -void BauSystemB::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data) -{ - applicationLayer().memoryReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, data); -} + void BauSystemB::memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data) + { + applicationLayer().memoryRoutingTableReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, data); + } + void BauSystemB::memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress) + { + memoryRoutingTableReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress, _memory.toAbsolute(memoryAddress)); + } -void BauSystemB::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress) -{ - applicationLayer().memoryReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, - _memory.toAbsolute(memoryAddress)); -} + void BauSystemB::memoryRoutingTableWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data) + { + print("Writing memory at: "); + print(memoryAddress, HEX); + print(" length: "); + print(number); + print(" data: "); + printHex("=>", data, number); + _memory.writeMemory(memoryAddress, number, data); + + if (_deviceObj.verifyMode()) + memoryRoutingTableReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress, data); + } -void BauSystemB::memoryExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data) -{ - _memory.writeMemory(memoryAddress, number, data); + void BauSystemB::memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data) + { + _memory.writeMemory(memoryAddress, number, data); - applicationLayer().memoryExtWriteResponse(AckRequested, priority, hopType, asap, secCtrl, ReturnCodes::Success, number, memoryAddress, _memory.toAbsolute(memoryAddress)); -} + if (_deviceObj.verifyMode()) + memoryReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress, data); + } -void BauSystemB::memoryExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress) -{ - applicationLayer().memoryExtReadResponse(AckRequested, priority, hopType, asap, secCtrl, ReturnCodes::Success, number, memoryAddress, _memory.toAbsolute(memoryAddress)); -} + void BauSystemB::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data) + { + applicationLayer().memoryReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, data); + } -void BauSystemB::doMasterReset(EraseCode eraseCode, uint8_t channel) -{ - _deviceObj.masterReset(eraseCode, channel); - _appProgram.masterReset(eraseCode, channel); -} + void BauSystemB::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress) + { + applicationLayer().memoryReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, + _memory.toAbsolute(memoryAddress)); + } -void BauSystemB::restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, RestartType restartType, EraseCode eraseCode, uint8_t channel) -{ - if (restartType == RestartType::BasicRestart) + void BauSystemB::memoryExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data) { - println("Basic restart requested"); + _memory.writeMemory(memoryAddress, number, data); - if (_beforeRestart != 0) - _beforeRestart(); + applicationLayer().memoryExtWriteResponse(AckRequested, priority, hopType, asap, secCtrl, ReturnCodes::Success, number, memoryAddress, _memory.toAbsolute(memoryAddress)); } - else if (restartType == RestartType::MasterReset) + + void BauSystemB::memoryExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress) { - uint8_t errorCode = checkmasterResetValidity(eraseCode, channel); - // We send the restart response now before actually applying the reset values - // Processing time is kRestartProcessTime (example 3 seconds) that we require for the applying the master reset with restart - applicationLayer().restartResponse(AckRequested, priority, hopType, secCtrl, errorCode, (errorCode == 0) ? kRestartProcessTime : 0); - doMasterReset(eraseCode, channel); + applicationLayer().memoryExtReadResponse(AckRequested, priority, hopType, asap, secCtrl, ReturnCodes::Success, number, memoryAddress, _memory.toAbsolute(memoryAddress)); } - else + + void BauSystemB::doMasterReset(EraseCode eraseCode, uint8_t channel) { - // Cannot happen as restartType is just one bit - println("Unhandled restart type."); - _platform.fatalError(); + _deviceObj.masterReset(eraseCode, channel); + _appProgram.masterReset(eraseCode, channel); } - // Flush the EEPROM before resetting - _memory.writeMemory(); - _platform.restart(); -} - -void BauSystemB::authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key) -{ - applicationLayer().authorizeResponse(AckRequested, priority, hopType, asap, secCtrl, 0); -} + void BauSystemB::restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, RestartType restartType, EraseCode eraseCode, uint8_t channel) + { + if (restartType == RestartType::BasicRestart) + { + println("Basic restart requested"); -void BauSystemB::userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress) -{ - applicationLayer().userMemoryReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, - _memory.toAbsolute(memoryAddress)); -} + if (_beforeRestart != 0) + _beforeRestart(); + } + else if (restartType == RestartType::MasterReset) + { + uint8_t errorCode = checkmasterResetValidity(eraseCode, channel); + // We send the restart response now before actually applying the reset values + // Processing time is kRestartProcessTime (example 3 seconds) that we require for the applying the master reset with restart + applicationLayer().restartResponse(AckRequested, priority, hopType, secCtrl, errorCode, (errorCode == 0) ? kRestartProcessTime : 0); + doMasterReset(eraseCode, channel); + } + else + { + // Cannot happen as restartType is just one bit + println("Unhandled restart type."); + _platform.fatalError(); + } -void BauSystemB::userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data) -{ - _memory.writeMemory(memoryAddress, number, data); + // Flush the EEPROM before resetting + _memory.writeMemory(); + _platform.restart(); + } - if (_deviceObj.verifyMode()) - userMemoryReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress); -} + void BauSystemB::authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key) + { + applicationLayer().authorizeResponse(AckRequested, priority, hopType, asap, secCtrl, 0); + } -void BauSystemB::propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t propertyIndex) -{ - uint8_t pid = propertyId; - bool writeEnable = false; - uint8_t type = 0; - uint16_t numberOfElements = 0; - uint8_t access = 0; - InterfaceObject* obj = getInterfaceObject(objectIndex); - - if (obj) - obj->readPropertyDescription(pid, propertyIndex, writeEnable, type, numberOfElements, access); - - applicationLayer().propertyDescriptionReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, pid, propertyIndex, - writeEnable, type, numberOfElements, access); -} - -void BauSystemB::propertyExtDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint16_t objectType, uint16_t objectInstance, uint16_t propertyId, uint8_t descriptionType, uint16_t propertyIndex) -{ - uint8_t pid = propertyId; - uint8_t pidx = propertyIndex; + void BauSystemB::userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress) + { + applicationLayer().userMemoryReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, + _memory.toAbsolute(memoryAddress)); + } - if (propertyId > 0xFF || propertyIndex > 0xFF) + void BauSystemB::userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data) { - println("BauSystemB::propertyExtDescriptionReadIndication: propertyId or Idx > 256 are not supported"); - return; + _memory.writeMemory(memoryAddress, number, data); + + if (_deviceObj.verifyMode()) + userMemoryReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress); } - if (descriptionType != 0) + void BauSystemB::propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t propertyIndex) { - println("BauSystemB::propertyExtDescriptionReadIndication: only descriptionType 0 supported"); - return; + uint8_t pid = propertyId; + bool writeEnable = false; + uint8_t type = 0; + uint16_t numberOfElements = 0; + uint8_t access = 0; + InterfaceObject* obj = getInterfaceObject(objectIndex); + + if (obj) + obj->readPropertyDescription(pid, propertyIndex, writeEnable, type, numberOfElements, access); + + applicationLayer().propertyDescriptionReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, pid, propertyIndex, + writeEnable, type, numberOfElements, access); } - bool writeEnable = false; - uint8_t type = 0; - uint16_t numberOfElements = 0; - uint8_t access = 0; - InterfaceObject* obj = getInterfaceObject((ObjectType)objectType, objectInstance); + void BauSystemB::propertyExtDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint16_t objectType, uint16_t objectInstance, uint16_t propertyId, uint8_t descriptionType, uint16_t propertyIndex) + { + uint8_t pid = propertyId; + uint8_t pidx = propertyIndex; - if (obj) - obj->readPropertyDescription(pid, pidx, writeEnable, type, numberOfElements, access); + if (propertyId > 0xFF || propertyIndex > 0xFF) + { + println("BauSystemB::propertyExtDescriptionReadIndication: propertyId or Idx > 256 are not supported"); + return; + } - applicationLayer().propertyExtDescriptionReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, propertyIndex, - descriptionType, writeEnable, type, numberOfElements, access); -} + if (descriptionType != 0) + { + println("BauSystemB::propertyExtDescriptionReadIndication: only descriptionType 0 supported"); + return; + } -void BauSystemB::propertyValueWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) -{ - InterfaceObject* obj = getInterfaceObject(objectIndex); + bool writeEnable = false; + uint8_t type = 0; + uint16_t numberOfElements = 0; + uint8_t access = 0; + InterfaceObject* obj = getInterfaceObject((ObjectType)objectType, objectInstance); - if (obj) - obj->writeProperty((PropertyID)propertyId, startIndex, data, numberOfElements); + if (obj) + obj->readPropertyDescription(pid, pidx, writeEnable, type, numberOfElements, access); - propertyValueReadIndication(priority, hopType, asap, secCtrl, objectIndex, propertyId, numberOfElements, startIndex); -} + applicationLayer().propertyExtDescriptionReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, propertyIndex, + descriptionType, writeEnable, type, numberOfElements, access); + } -void BauSystemB::propertyValueExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool confirmed) -{ - uint8_t returnCode = ReturnCodes::Success; + void BauSystemB::propertyValueWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) + { + InterfaceObject* obj = getInterfaceObject(objectIndex); - InterfaceObject* obj = getInterfaceObject(objectType, objectInstance); + if (obj) + obj->writeProperty((PropertyID)propertyId, startIndex, data, numberOfElements); - if (obj) - obj->writeProperty((PropertyID)propertyId, startIndex, data, numberOfElements); - else - returnCode = ReturnCodes::AddressVoid; + propertyValueReadIndication(priority, hopType, asap, secCtrl, objectIndex, propertyId, numberOfElements, startIndex); + } - if (confirmed) + void BauSystemB::propertyValueExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool confirmed) { - applicationLayer().propertyValueExtWriteConResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, numberOfElements, startIndex, returnCode); + uint8_t returnCode = ReturnCodes::Success; + + InterfaceObject* obj = getInterfaceObject(objectType, objectInstance); + + if (obj) + obj->writeProperty((PropertyID)propertyId, startIndex, data, numberOfElements); + else + returnCode = ReturnCodes::AddressVoid; + + if (confirmed) + { + applicationLayer().propertyValueExtWriteConResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, numberOfElements, startIndex, returnCode); + } } -} -void BauSystemB::propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) -{ - uint8_t size = 0; - uint8_t elementCount = numberOfElements; + void BauSystemB::propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) + { + uint8_t size = 0; + uint8_t elementCount = numberOfElements; #ifdef LOG_KNX_PROP - print("propertyValueReadIndication: ObjIdx "); - print(objectIndex); - print(" propId "); - print(propertyId); - print(" num "); - print(numberOfElements); - print(" start "); - print(startIndex); + print("propertyValueReadIndication: ObjIdx "); + print(objectIndex); + print(" propId "); + print(propertyId); + print(" num "); + print(numberOfElements); + print(" start "); + print(startIndex); #endif - InterfaceObject* obj = getInterfaceObject(objectIndex); + InterfaceObject* obj = getInterfaceObject(objectIndex); - if (obj) - { - uint8_t elementSize = obj->propertySize((PropertyID)propertyId); + if (obj) + { + uint8_t elementSize = obj->propertySize((PropertyID)propertyId); - if (startIndex > 0) - size = elementSize * numberOfElements; + if (startIndex > 0) + size = elementSize * numberOfElements; + else + size = sizeof(uint16_t); // size of property array entry 0 which contains the current number of elements + } else - size = sizeof(uint16_t); // size of property array entry 0 which contains the current number of elements - } - else - elementCount = 0; + elementCount = 0; - uint8_t data[size]; + uint8_t data[size]; - if (obj) - obj->readProperty((PropertyID)propertyId, startIndex, elementCount, data); + if (obj) + obj->readProperty((PropertyID)propertyId, startIndex, elementCount, data); - if (elementCount == 0) - size = 0; + if (elementCount == 0) + size = 0; - applicationLayer().propertyValueReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, propertyId, elementCount, - startIndex, data, size); -} - -void BauSystemB::propertyValueExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) -{ - uint8_t size = 0; - uint8_t elementCount = numberOfElements; - InterfaceObject* obj = getInterfaceObject(objectType, objectInstance); + applicationLayer().propertyValueReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, propertyId, elementCount, + startIndex, data, size); + } - if (obj) + void BauSystemB::propertyValueExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) { - uint8_t elementSize = obj->propertySize((PropertyID)propertyId); + uint8_t size = 0; + uint8_t elementCount = numberOfElements; + InterfaceObject* obj = getInterfaceObject(objectType, objectInstance); - if (startIndex > 0) - size = elementSize * numberOfElements; + if (obj) + { + uint8_t elementSize = obj->propertySize((PropertyID)propertyId); + + if (startIndex > 0) + size = elementSize * numberOfElements; + else + size = sizeof(uint16_t); // size of propert array entry 0 which is the size + } else - size = sizeof(uint16_t); // size of propert array entry 0 which is the size - } - else - elementCount = 0; + elementCount = 0; - uint8_t data[size]; + uint8_t data[size]; - if (obj) - obj->readProperty((PropertyID)propertyId, startIndex, elementCount, data); + if (obj) + obj->readProperty((PropertyID)propertyId, startIndex, elementCount, data); - if (elementCount == 0) - size = 0; + if (elementCount == 0) + size = 0; - applicationLayer().propertyValueExtReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, elementCount, - startIndex, data, size); -} + applicationLayer().propertyValueExtReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, elementCount, + startIndex, data, size); + } -void BauSystemB::functionPropertyCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t* data, uint8_t length) -{ - uint8_t resultData[kFunctionPropertyResultBufferMaxSize]; - uint8_t resultLength = sizeof(resultData); // tell the callee the maximum size of the buffer + void BauSystemB::functionPropertyCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t* data, uint8_t length) + { + uint8_t resultData[kFunctionPropertyResultBufferMaxSize]; + uint8_t resultLength = sizeof(resultData); // tell the callee the maximum size of the buffer - bool handled = false; + bool handled = false; - InterfaceObject* obj = getInterfaceObject(objectIndex); + InterfaceObject* obj = getInterfaceObject(objectIndex); - if (obj) - { - if (obj->property((PropertyID)propertyId)->Type() == PDT_FUNCTION) + if (obj) { - obj->command((PropertyID)propertyId, data, length, resultData, resultLength); - handled = true; + if (obj->property((PropertyID)propertyId)->Type() == PDT_FUNCTION) + { + obj->command((PropertyID)propertyId, data, length, resultData, resultLength); + handled = true; + } + else + { + if (_functionProperty != 0) + if (_functionProperty(objectIndex, propertyId, length, data, resultData, resultLength)) + handled = true; + } } else { @@ -429,35 +439,35 @@ void BauSystemB::functionPropertyCommandIndication(Priority priority, HopCountTy if (_functionProperty(objectIndex, propertyId, length, data, resultData, resultLength)) handled = true; } - } - else - { - if (_functionProperty != 0) - if (_functionProperty(objectIndex, propertyId, length, data, resultData, resultLength)) - handled = true; - } - //only return a value it was handled by a property or function - if (handled) - applicationLayer().functionPropertyStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, propertyId, resultData, resultLength); -} + //only return a value it was handled by a property or function + if (handled) + applicationLayer().functionPropertyStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, propertyId, resultData, resultLength); + } -void BauSystemB::functionPropertyStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t* data, uint8_t length) -{ - uint8_t resultData[kFunctionPropertyResultBufferMaxSize]; - uint8_t resultLength = sizeof(resultData); // tell the callee the maximum size of the buffer + void BauSystemB::functionPropertyStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t* data, uint8_t length) + { + uint8_t resultData[kFunctionPropertyResultBufferMaxSize]; + uint8_t resultLength = sizeof(resultData); // tell the callee the maximum size of the buffer - bool handled = true; + bool handled = true; - InterfaceObject* obj = getInterfaceObject(objectIndex); + InterfaceObject* obj = getInterfaceObject(objectIndex); - if (obj) - { - if (obj->property((PropertyID)propertyId)->Type() == PDT_FUNCTION) + if (obj) { - obj->state((PropertyID)propertyId, data, length, resultData, resultLength); - handled = true; + if (obj->property((PropertyID)propertyId)->Type() == PDT_FUNCTION) + { + obj->state((PropertyID)propertyId, data, length, resultData, resultLength); + handled = true; + } + else + { + if (_functionPropertyState != 0) + if (_functionPropertyState(objectIndex, propertyId, length, data, resultData, resultLength)) + handled = true; + } } else { @@ -465,55 +475,102 @@ void BauSystemB::functionPropertyStateIndication(Priority priority, HopCountType if (_functionPropertyState(objectIndex, propertyId, length, data, resultData, resultLength)) handled = true; } - } - else - { - if (_functionPropertyState != 0) - if (_functionPropertyState(objectIndex, propertyId, length, data, resultData, resultLength)) - handled = true; - } - - //only return a value it was handled by a property or function - if (handled) - applicationLayer().functionPropertyStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, propertyId, resultData, resultLength); -} -void BauSystemB::functionPropertyExtCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, - uint8_t propertyId, uint8_t* data, uint8_t length) -{ - uint8_t resultData[kFunctionPropertyResultBufferMaxSize]; - uint8_t resultLength = 1; // we always have to include the return code at least - - InterfaceObject* obj = getInterfaceObject(objectType, objectInstance); + //only return a value it was handled by a property or function + if (handled) + applicationLayer().functionPropertyStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, propertyId, resultData, resultLength); + } - if (obj) + void BauSystemB::functionPropertyExtCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, + uint8_t propertyId, uint8_t* data, uint8_t length) { - PropertyDataType propType = obj->property((PropertyID)propertyId)->Type(); + uint8_t resultData[kFunctionPropertyResultBufferMaxSize]; + uint8_t resultLength = 1; // we always have to include the return code at least - if (propType == PDT_FUNCTION) + InterfaceObject* obj = getInterfaceObject(objectType, objectInstance); + + if (obj) { - // The first byte is reserved and 0 for PDT_FUNCTION - uint8_t reservedByte = data[0]; + PropertyDataType propType = obj->property((PropertyID)propertyId)->Type(); - if (reservedByte != 0x00) + if (propType == PDT_FUNCTION) { - resultData[0] = ReturnCodes::DataVoid; + // The first byte is reserved and 0 for PDT_FUNCTION + uint8_t reservedByte = data[0]; + + if (reservedByte != 0x00) + { + resultData[0] = ReturnCodes::DataVoid; + } + else + { + resultLength = sizeof(resultData); // tell the callee the maximum size of the buffer + obj->command((PropertyID)propertyId, data, length, resultData, resultLength); + // resultLength was modified by the callee + } + } + else if (propType == PDT_CONTROL) + { + uint8_t count = 1; + // write the event + obj->writeProperty((PropertyID)propertyId, 1, data, count); + + if (count == 1) + { + // Read the current state (one byte only) for the response + obj->readProperty((PropertyID)propertyId, 1, count, &resultData[1]); + resultLength = count ? 2 : 1; + resultData[0] = count ? ReturnCodes::Success : ReturnCodes::DataVoid; + } + else + { + resultData[0] = ReturnCodes::AddressVoid; + } } else { - resultLength = sizeof(resultData); // tell the callee the maximum size of the buffer - obj->command((PropertyID)propertyId, data, length, resultData, resultLength); - // resultLength was modified by the callee + resultData[0] = ReturnCodes::DataTypeConflict; } } - else if (propType == PDT_CONTROL) + else { - uint8_t count = 1; - // write the event - obj->writeProperty((PropertyID)propertyId, 1, data, count); + resultData[0] = ReturnCodes::GenericError; + } - if (count == 1) + applicationLayer().functionPropertyExtStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, resultData, resultLength); + } + + void BauSystemB::functionPropertyExtStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, + uint8_t propertyId, uint8_t* data, uint8_t length) + { + uint8_t resultData[kFunctionPropertyResultBufferMaxSize]; + uint8_t resultLength = sizeof(resultData); // tell the callee the maximum size of the buffer + + InterfaceObject* obj = getInterfaceObject(objectType, objectInstance); + + if (obj) + { + PropertyDataType propType = obj->property((PropertyID)propertyId)->Type(); + + if (propType == PDT_FUNCTION) + { + // The first byte is reserved and 0 for PDT_FUNCTION + uint8_t reservedByte = data[0]; + + if (reservedByte != 0x00) + { + resultData[0] = ReturnCodes::DataVoid; + } + else + { + resultLength = sizeof(resultData); // tell the callee the maximum size of the buffer + obj->state((PropertyID)propertyId, data, length, resultData, resultLength); + // resultLength was modified by the callee + } + } + else if (propType == PDT_CONTROL) { + uint8_t count = 1; // Read the current state (one byte only) for the response obj->readProperty((PropertyID)propertyId, 1, count, &resultData[1]); resultLength = count ? 2 : 1; @@ -521,294 +578,241 @@ void BauSystemB::functionPropertyExtCommandIndication(Priority priority, HopCoun } else { - resultData[0] = ReturnCodes::AddressVoid; + resultData[0] = ReturnCodes::DataTypeConflict; } } else { - resultData[0] = ReturnCodes::DataTypeConflict; + resultData[0] = ReturnCodes::GenericError; } + + applicationLayer().functionPropertyExtStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, resultData, resultLength); } - else + + void BauSystemB::individualAddressReadIndication(HopCountType hopType, const SecurityControl& secCtrl) { - resultData[0] = ReturnCodes::GenericError; + if (_deviceObj.progMode()) + applicationLayer().individualAddressReadResponse(AckRequested, hopType, secCtrl); } - applicationLayer().functionPropertyExtStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, resultData, resultLength); -} + void BauSystemB::individualAddressWriteIndication(HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress) + { + if (_deviceObj.progMode()) + _deviceObj.individualAddress(newaddress); + } -void BauSystemB::functionPropertyExtStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, - uint8_t propertyId, uint8_t* data, uint8_t length) -{ - uint8_t resultData[kFunctionPropertyResultBufferMaxSize]; - uint8_t resultLength = sizeof(resultData); // tell the callee the maximum size of the buffer + void BauSystemB::individualAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newIndividualAddress, + uint8_t* knxSerialNumber) + { + // If the received serial number matches our serial number + // then store the received new individual address in the device object + if (!memcmp(knxSerialNumber, _deviceObj.propertyData(PID_SERIAL_NUMBER), 6)) + _deviceObj.individualAddress(newIndividualAddress); + } - InterfaceObject* obj = getInterfaceObject(objectType, objectInstance); + void BauSystemB::individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber) + { + // If the received serial number matches our serial number + // then send a response with the serial number. The domain address is set to 0 for closed media. + // An open medium BAU has to override this method and provide a proper domain address. + if (!memcmp(knxSerialNumber, _deviceObj.propertyData(PID_SERIAL_NUMBER), 6)) + { + uint8_t emptyDomainAddress[2] = {0x00}; + applicationLayer().IndividualAddressSerialNumberReadResponse(priority, hopType, secCtrl, emptyDomainAddress, knxSerialNumber); + } + } - if (obj) + void BauSystemB::addSaveRestore(SaveRestore* obj) { - PropertyDataType propType = obj->property((PropertyID)propertyId)->Type(); + _memory.addSaveRestore(obj); + } - if (propType == PDT_FUNCTION) - { - // The first byte is reserved and 0 for PDT_FUNCTION - uint8_t reservedByte = data[0]; + bool BauSystemB::restartRequest(uint16_t asap, const SecurityControl secCtrl) + { + if (applicationLayer().isConnected()) + return false; + + _restartState = Connecting; // order important, has to be set BEFORE connectRequest + _restartSecurity = secCtrl; + applicationLayer().connectRequest(asap, SystemPriority); + applicationLayer().deviceDescriptorReadRequest(AckRequested, SystemPriority, NetworkLayerParameter, asap, secCtrl, 0); + return true; + } - if (reservedByte != 0x00) - { - resultData[0] = ReturnCodes::DataVoid; - } - else - { - resultLength = sizeof(resultData); // tell the callee the maximum size of the buffer - obj->state((PropertyID)propertyId, data, length, resultData, resultLength); - // resultLength was modified by the callee - } - } - else if (propType == PDT_CONTROL) + void BauSystemB::connectConfirm(uint16_t tsap) + { + if (_restartState == Connecting) { - uint8_t count = 1; - // Read the current state (one byte only) for the response - obj->readProperty((PropertyID)propertyId, 1, count, &resultData[1]); - resultLength = count ? 2 : 1; - resultData[0] = count ? ReturnCodes::Success : ReturnCodes::DataVoid; + /* restart connection is confirmed, go to the next state */ + _restartState = Connected; + _restartDelay = millis(); } else { - resultData[0] = ReturnCodes::DataTypeConflict; + _restartState = Idle; } } - else - { - resultData[0] = ReturnCodes::GenericError; - } - - applicationLayer().functionPropertyExtStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, resultData, resultLength); -} -void BauSystemB::individualAddressReadIndication(HopCountType hopType, const SecurityControl& secCtrl) -{ - if (_deviceObj.progMode()) - applicationLayer().individualAddressReadResponse(AckRequested, hopType, secCtrl); -} + void BauSystemB::nextRestartState() + { + switch (_restartState) + { + case Idle: + /* inactive state, do nothing */ + break; -void BauSystemB::individualAddressWriteIndication(HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress) -{ - if (_deviceObj.progMode()) - _deviceObj.individualAddress(newaddress); -} + case Connecting: + /* wait for connection, we do nothing here */ + break; -void BauSystemB::individualAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newIndividualAddress, - uint8_t* knxSerialNumber) -{ - // If the received serial number matches our serial number - // then store the received new individual address in the device object - if (!memcmp(knxSerialNumber, _deviceObj.propertyData(PID_SERIAL_NUMBER), 6)) - _deviceObj.individualAddress(newIndividualAddress); -} + case Connected: -void BauSystemB::individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber) -{ - // If the received serial number matches our serial number - // then send a response with the serial number. The domain address is set to 0 for closed media. - // An open medium BAU has to override this method and provide a proper domain address. - if (!memcmp(knxSerialNumber, _deviceObj.propertyData(PID_SERIAL_NUMBER), 6)) - { - uint8_t emptyDomainAddress[2] = {0x00}; - applicationLayer().IndividualAddressSerialNumberReadResponse(priority, hopType, secCtrl, emptyDomainAddress, knxSerialNumber); - } -} + /* connection confirmed, we send restartRequest, but we wait a moment (sending ACK etc)... */ + if (millis() - _restartDelay > 30) + { + applicationLayer().restartRequest(AckRequested, SystemPriority, NetworkLayerParameter, _restartSecurity); + _restartState = Restarted; + _restartDelay = millis(); + } -void BauSystemB::addSaveRestore(SaveRestore* obj) -{ - _memory.addSaveRestore(obj); -} + break; -bool BauSystemB::restartRequest(uint16_t asap, const SecurityControl secCtrl) -{ - if (applicationLayer().isConnected()) - return false; + case Restarted: - _restartState = Connecting; // order important, has to be set BEFORE connectRequest - _restartSecurity = secCtrl; - applicationLayer().connectRequest(asap, SystemPriority); - applicationLayer().deviceDescriptorReadRequest(AckRequested, SystemPriority, NetworkLayerParameter, asap, secCtrl, 0); - return true; -} + /* restart is finished, we send a disconnect */ + if (millis() - _restartDelay > 30) + { + applicationLayer().disconnectRequest(SystemPriority); + _restartState = Idle; + } -void BauSystemB::connectConfirm(uint16_t tsap) -{ - if (_restartState == Connecting) - { - /* restart connection is confirmed, go to the next state */ - _restartState = Connected; - _restartDelay = millis(); - } - else - { - _restartState = Idle; + default: + break; + } } -} -void BauSystemB::nextRestartState() -{ - switch (_restartState) + void BauSystemB::systemNetworkParameterReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, + uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength) { - case Idle: - /* inactive state, do nothing */ - break; + uint8_t operand; - case Connecting: - /* wait for connection, we do nothing here */ - break; + popByte(operand, testInfo + 1); // First byte (+ 0) contains only 4 reserved bits (0) - case Connected: + // See KNX spec. 3.5.2 p.33 (Management Procedures: Procedures with A_SystemNetworkParameter_Read) + switch ((NmReadSerialNumberType)operand) + { + case NM_Read_SerialNumber_By_ProgrammingMode: // NM_Read_SerialNumber_By_ProgrammingMode - /* connection confirmed, we send restartRequest, but we wait a moment (sending ACK etc)... */ - if (millis() - _restartDelay > 30) - { - applicationLayer().restartRequest(AckRequested, SystemPriority, NetworkLayerParameter, _restartSecurity); - _restartState = Restarted; - _restartDelay = millis(); - } + // Only send a reply if programming mode is on + if (_deviceObj.progMode() && (objectType == OT_DEVICE) && (propertyId == PID_SERIAL_NUMBER)) + { + // Send reply. testResult data is KNX serial number + applicationLayer().systemNetworkParameterReadResponse(priority, hopType, secCtrl, objectType, propertyId, + testInfo, testInfoLength, (uint8_t*)_deviceObj.propertyData(PID_SERIAL_NUMBER), 6); + } - break; + break; - case Restarted: + case NM_Read_SerialNumber_By_ExFactoryState: // NM_Read_SerialNumber_By_ExFactoryState + break; - /* restart is finished, we send a disconnect */ - if (millis() - _restartDelay > 30) - { - applicationLayer().disconnectRequest(SystemPriority); - _restartState = Idle; - } + case NM_Read_SerialNumber_By_PowerReset: // NM_Read_SerialNumber_By_PowerReset + break; - default: - break; + case NM_Read_SerialNumber_By_ManufacturerSpecific: // Manufacturer specific use of A_SystemNetworkParameter_Read + break; + } } -} -void BauSystemB::systemNetworkParameterReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, - uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength) -{ - uint8_t operand; - - popByte(operand, testInfo + 1); // First byte (+ 0) contains only 4 reserved bits (0) + void BauSystemB::systemNetworkParameterReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, + uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength, bool status) + { + } - // See KNX spec. 3.5.2 p.33 (Management Procedures: Procedures with A_SystemNetworkParameter_Read) - switch ((NmReadSerialNumberType)operand) + void BauSystemB::propertyValueRead(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, + uint8_t& numberOfElements, uint16_t startIndex, + uint8_t** data, uint32_t& length) { - case NM_Read_SerialNumber_By_ProgrammingMode: // NM_Read_SerialNumber_By_ProgrammingMode + uint32_t size = 0; + uint8_t elementCount = numberOfElements; - // Only send a reply if programming mode is on - if (_deviceObj.progMode() && (objectType == OT_DEVICE) && (propertyId == PID_SERIAL_NUMBER)) - { - // Send reply. testResult data is KNX serial number - applicationLayer().systemNetworkParameterReadResponse(priority, hopType, secCtrl, objectType, propertyId, - testInfo, testInfoLength, (uint8_t*)_deviceObj.propertyData(PID_SERIAL_NUMBER), 6); - } + InterfaceObject* obj = getInterfaceObject(objectType, objectInstance); - break; + if (obj) + { + uint8_t elementSize = obj->propertySize((PropertyID)propertyId); - case NM_Read_SerialNumber_By_ExFactoryState: // NM_Read_SerialNumber_By_ExFactoryState - break; + if (startIndex > 0) + size = elementSize * numberOfElements; + else + size = sizeof(uint16_t); // size of property array entry 0 which contains the current number of elements - case NM_Read_SerialNumber_By_PowerReset: // NM_Read_SerialNumber_By_PowerReset - break; + *data = new uint8_t [size]; + obj->readProperty((PropertyID)propertyId, startIndex, elementCount, *data); + } + else + { + elementCount = 0; + *data = nullptr; + } - case NM_Read_SerialNumber_By_ManufacturerSpecific: // Manufacturer specific use of A_SystemNetworkParameter_Read - break; + numberOfElements = elementCount; + length = size; } -} - -void BauSystemB::systemNetworkParameterReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, - uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength, bool status) -{ -} -void BauSystemB::propertyValueRead(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, - uint8_t& numberOfElements, uint16_t startIndex, - uint8_t** data, uint32_t& length) -{ - uint32_t size = 0; - uint8_t elementCount = numberOfElements; - - InterfaceObject* obj = getInterfaceObject(objectType, objectInstance); - - if (obj) + void BauSystemB::propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, + uint8_t& numberOfElements, uint16_t startIndex, + uint8_t* data, uint32_t length) { - uint8_t elementSize = obj->propertySize((PropertyID)propertyId); + InterfaceObject* obj = getInterfaceObject(objectType, objectInstance); - if (startIndex > 0) - size = elementSize * numberOfElements; + if (obj) + obj->writeProperty((PropertyID)propertyId, startIndex, data, numberOfElements); else - size = sizeof(uint16_t); // size of property array entry 0 which contains the current number of elements - - *data = new uint8_t [size]; - obj->readProperty((PropertyID)propertyId, startIndex, elementCount, *data); + numberOfElements = 0; } - else + + Memory& BauSystemB::memory() { - elementCount = 0; - *data = nullptr; + return _memory; } - numberOfElements = elementCount; - length = size; -} - -void BauSystemB::propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, - uint8_t& numberOfElements, uint16_t startIndex, - uint8_t* data, uint32_t length) -{ - InterfaceObject* obj = getInterfaceObject(objectType, objectInstance); - - if (obj) - obj->writeProperty((PropertyID)propertyId, startIndex, data, numberOfElements); - else - numberOfElements = 0; -} - -Memory& BauSystemB::memory() -{ - return _memory; -} - -void BauSystemB::versionCheckCallback(VersionCheckCallback func) -{ - _memory.versionCheckCallback(func); -} + void BauSystemB::versionCheckCallback(VersionCheckCallback func) + { + _memory.versionCheckCallback(func); + } -VersionCheckCallback BauSystemB::versionCheckCallback() -{ - return _memory.versionCheckCallback(); -} + VersionCheckCallback BauSystemB::versionCheckCallback() + { + return _memory.versionCheckCallback(); + } -void BauSystemB::beforeRestartCallback(BeforeRestartCallback func) -{ - _beforeRestart = func; -} + void BauSystemB::beforeRestartCallback(BeforeRestartCallback func) + { + _beforeRestart = func; + } -BeforeRestartCallback BauSystemB::beforeRestartCallback() -{ - return _beforeRestart; -} + BeforeRestartCallback BauSystemB::beforeRestartCallback() + { + return _beforeRestart; + } -void BauSystemB::functionPropertyCallback(FunctionPropertyCallback func) -{ - _functionProperty = func; -} + void BauSystemB::functionPropertyCallback(FunctionPropertyCallback func) + { + _functionProperty = func; + } -FunctionPropertyCallback BauSystemB::functionPropertyCallback() -{ - return _functionProperty; -} -void BauSystemB::functionPropertyStateCallback(FunctionPropertyCallback func) -{ - _functionPropertyState = func; -} + FunctionPropertyCallback BauSystemB::functionPropertyCallback() + { + return _functionProperty; + } + void BauSystemB::functionPropertyStateCallback(FunctionPropertyCallback func) + { + _functionPropertyState = func; + } -FunctionPropertyCallback BauSystemB::functionPropertyStateCallback() -{ - return _functionPropertyState; + FunctionPropertyCallback BauSystemB::functionPropertyStateCallback() + { + return _functionPropertyState; + } } \ No newline at end of file diff --git a/src/knx/bau/bau_systemB.h b/src/knx/bau/bau_systemB.h index 06db3799..e0efd04a 100644 --- a/src/knx/bau/bau_systemB.h +++ b/src/knx/bau/bau_systemB.h @@ -13,122 +13,126 @@ #include "../platform/platform.h" #include "../util/memory.h" -class BauSystemB : protected BusAccessUnit +namespace Knx { - public: - BauSystemB(Platform& platform); - virtual void loop() = 0; - virtual bool configured() = 0; - virtual bool enabled() = 0; - virtual void enabled(bool value) = 0; - Platform& platform(); - ApplicationProgramObject& parameters(); - DeviceObject& deviceObject(); + class BauSystemB : protected BusAccessUnit + { + public: + BauSystemB(Platform& platform); + virtual void loop() = 0; + virtual bool configured() = 0; + virtual bool enabled() = 0; + virtual void enabled(bool value) = 0; - Memory& memory(); - void readMemory(); - void writeMemory(); - void addSaveRestore(SaveRestore* obj); + Platform& platform(); + ApplicationProgramObject& parameters(); + DeviceObject& deviceObject(); - bool restartRequest(uint16_t asap, const SecurityControl secCtrl); - uint8_t checkmasterResetValidity(EraseCode eraseCode, uint8_t channel); + Memory& memory(); + void readMemory(); + void writeMemory(); + void addSaveRestore(SaveRestore* obj); - void propertyValueRead(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, - uint8_t& numberOfElements, uint16_t startIndex, - uint8_t** data, uint32_t& length) override; - void propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, - uint8_t& numberOfElements, uint16_t startIndex, - uint8_t* data, uint32_t length) override; - void versionCheckCallback(VersionCheckCallback func); - VersionCheckCallback versionCheckCallback(); - void beforeRestartCallback(BeforeRestartCallback func); - BeforeRestartCallback beforeRestartCallback(); - void functionPropertyCallback(FunctionPropertyCallback func); - FunctionPropertyCallback functionPropertyCallback(); - void functionPropertyStateCallback(FunctionPropertyCallback func); - FunctionPropertyCallback functionPropertyStateCallback(); + bool restartRequest(uint16_t asap, const SecurityControl secCtrl); + uint8_t checkmasterResetValidity(EraseCode eraseCode, uint8_t channel); - protected: - virtual ApplicationLayer& applicationLayer() = 0; - virtual InterfaceObject* getInterfaceObject(uint8_t idx) = 0; - virtual InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance) = 0; + void propertyValueRead(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, + uint8_t& numberOfElements, uint16_t startIndex, + uint8_t** data, uint32_t& length) override; + void propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, + uint8_t& numberOfElements, uint16_t startIndex, + uint8_t* data, uint32_t length) override; + void versionCheckCallback(VersionCheckCallback func); + VersionCheckCallback versionCheckCallback(); + void beforeRestartCallback(BeforeRestartCallback func); + BeforeRestartCallback beforeRestartCallback(); + void functionPropertyCallback(FunctionPropertyCallback func); + FunctionPropertyCallback functionPropertyCallback(); + void functionPropertyStateCallback(FunctionPropertyCallback func); + FunctionPropertyCallback functionPropertyStateCallback(); - void memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data) override; - void memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress) override; - void memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data); - void memoryRouterWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data); - void memoryRouterReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data); - void memoryRoutingTableWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t* data); - void memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data); - void memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress); - // - void memoryExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress, uint8_t* data) override; - void memoryExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress) override; - void deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptorType) override; - void restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, RestartType restartType, EraseCode eraseCode, uint8_t channel) override; - void authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key) override; - void userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress) override; - void userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint32_t memoryAddress, uint8_t* memoryData) override; - void propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t propertyIndex) override; - void propertyExtDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint16_t objectType, uint16_t objectInstance, uint16_t propertyId, uint8_t descriptionType, uint16_t propertyIndex) override; - void propertyValueWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) override; - void propertyValueExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool confirmed); - void propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) override; - void propertyValueExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, - uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) override; - void functionPropertyCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t* data, uint8_t length) override; - void functionPropertyStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t* data, uint8_t length) override; - void functionPropertyExtCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, - uint8_t propertyId, uint8_t* data, uint8_t length) override; - void functionPropertyExtStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, - uint8_t propertyId, uint8_t* data, uint8_t length) override; - void individualAddressReadIndication(HopCountType hopType, const SecurityControl& secCtrl) override; - void individualAddressWriteIndication(HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress) override; - void individualAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newIndividualAddress, - uint8_t* knxSerialNumber) override; - void individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber) override; - void systemNetworkParameterReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, - uint16_t propertyId, uint8_t* testInfo, uint16_t testinfoLength) override; - void systemNetworkParameterReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, - uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength, bool status) override; - void connectConfirm(uint16_t tsap) override; + protected: + virtual ApplicationLayer& applicationLayer() = 0; + virtual InterfaceObject* getInterfaceObject(uint8_t idx) = 0; + virtual InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance) = 0; - void nextRestartState(); - virtual void doMasterReset(EraseCode eraseCode, uint8_t channel); + void memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data) override; + void memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress) override; + void memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data); + void memoryRouterWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data); + void memoryRouterReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data); + void memoryRoutingTableWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t* data); + void memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data); + void memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress); + // + void memoryExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress, uint8_t* data) override; + void memoryExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress) override; + void deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptorType) override; + void restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, RestartType restartType, EraseCode eraseCode, uint8_t channel) override; + void authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key) override; + void userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress) override; + void userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, + uint32_t memoryAddress, uint8_t* memoryData) override; + void propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t propertyIndex) override; + void propertyExtDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, + uint16_t objectType, uint16_t objectInstance, uint16_t propertyId, uint8_t descriptionType, uint16_t propertyIndex) override; + void propertyValueWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) override; + void propertyValueExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool confirmed); + void propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) override; + void propertyValueExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) override; + void functionPropertyCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t* data, uint8_t length) override; + void functionPropertyStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, + uint8_t propertyId, uint8_t* data, uint8_t length) override; + void functionPropertyExtCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, + uint8_t propertyId, uint8_t* data, uint8_t length) override; + void functionPropertyExtStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, + uint8_t propertyId, uint8_t* data, uint8_t length) override; + void individualAddressReadIndication(HopCountType hopType, const SecurityControl& secCtrl) override; + void individualAddressWriteIndication(HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress) override; + void individualAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newIndividualAddress, + uint8_t* knxSerialNumber) override; + void individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber) override; + void systemNetworkParameterReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, + uint16_t propertyId, uint8_t* testInfo, uint16_t testinfoLength) override; + void systemNetworkParameterReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType, + uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength, bool status) override; + void connectConfirm(uint16_t tsap) override; - enum RestartState - { - Idle, - Connecting, - Connected, - Restarted - }; + void nextRestartState(); + virtual void doMasterReset(EraseCode eraseCode, uint8_t channel); - Memory _memory; - DeviceObject _deviceObj; - ApplicationProgramObject _appProgram; - Platform& _platform; - RestartState _restartState = Idle; - SecurityControl _restartSecurity; - uint32_t _restartDelay = 0; - BeforeRestartCallback _beforeRestart = 0; - FunctionPropertyCallback _functionProperty = 0; - FunctionPropertyCallback _functionPropertyState = 0; -}; + enum RestartState + { + Idle, + Connecting, + Connected, + Restarted + }; + + Memory _memory; + DeviceObject _deviceObj; + ApplicationProgramObject _appProgram; + Platform& _platform; + RestartState _restartState = Idle; + SecurityControl _restartSecurity; + uint32_t _restartDelay = 0; + BeforeRestartCallback _beforeRestart = 0; + FunctionPropertyCallback _functionProperty = 0; + FunctionPropertyCallback _functionPropertyState = 0; + }; +} \ No newline at end of file diff --git a/src/knx/bau/bau_systemB_device.cpp b/src/knx/bau/bau_systemB_device.cpp index 39d029d5..a1b98405 100644 --- a/src/knx/bau/bau_systemB_device.cpp +++ b/src/knx/bau/bau_systemB_device.cpp @@ -5,259 +5,263 @@ #include #include -BauSystemBDevice::BauSystemBDevice(Platform& platform) : - BauSystemB(platform), - _addrTable(_memory), - _assocTable(_memory), _groupObjTable(_memory), +namespace Knx +{ + + BauSystemBDevice::BauSystemBDevice(Platform& platform) : + BauSystemB(platform), + _addrTable(_memory), + _assocTable(_memory), _groupObjTable(_memory), #ifdef USE_DATASECURE - _appLayer(_deviceObj, _secIfObj, *this), + _appLayer(_deviceObj, _secIfObj, *this), #else - _appLayer(*this), + _appLayer(*this), #endif - _transLayer(_appLayer), _netLayer(_deviceObj, _transLayer) -{ - _appLayer.transportLayer(_transLayer); - _appLayer.associationTableObject(_assocTable); + _transLayer(_appLayer), _netLayer(_deviceObj, _transLayer) + { + _appLayer.transportLayer(_transLayer); + _appLayer.associationTableObject(_assocTable); #ifdef USE_DATASECURE - _appLayer.groupAddressTable(_addrTable); + _appLayer.groupAddressTable(_addrTable); #endif - _transLayer.networkLayer(_netLayer); - _transLayer.groupAddressTable(_addrTable); + _transLayer.networkLayer(_netLayer); + _transLayer.groupAddressTable(_addrTable); - _memory.addSaveRestore(&_deviceObj); - _memory.addSaveRestore(&_groupObjTable); // changed order for better memory management - _memory.addSaveRestore(&_addrTable); - _memory.addSaveRestore(&_assocTable); + _memory.addSaveRestore(&_deviceObj); + _memory.addSaveRestore(&_groupObjTable); // changed order for better memory management + _memory.addSaveRestore(&_addrTable); + _memory.addSaveRestore(&_assocTable); #ifdef USE_DATASECURE - _memory.addSaveRestore(&_secIfObj); + _memory.addSaveRestore(&_secIfObj); #endif -} + } -ApplicationLayer& BauSystemBDevice::applicationLayer() -{ - return _appLayer; -} + ApplicationLayer& BauSystemBDevice::applicationLayer() + { + return _appLayer; + } -GroupObjectTableObject& BauSystemBDevice::groupObjectTable() -{ - return _groupObjTable; -} + GroupObjectTableObject& BauSystemBDevice::groupObjectTable() + { + return _groupObjTable; + } -void BauSystemBDevice::loop() -{ - _transLayer.loop(); - sendNextGroupTelegram(); - nextRestartState(); + void BauSystemBDevice::loop() + { + _transLayer.loop(); + sendNextGroupTelegram(); + nextRestartState(); #ifdef USE_DATASECURE - _appLayer.loop(); + _appLayer.loop(); #endif -} + } -void BauSystemBDevice::sendNextGroupTelegram() -{ - if (!configured()) - return; + void BauSystemBDevice::sendNextGroupTelegram() + { + if (!configured()) + return; - static uint16_t startIdx = 1; + static uint16_t startIdx = 1; - GroupObjectTableObject& table = _groupObjTable; - uint16_t objCount = table.entryCount(); + GroupObjectTableObject& table = _groupObjTable; + uint16_t objCount = table.entryCount(); - for (uint16_t asap = startIdx; asap <= objCount; asap++) - { - GroupObject& go = table.get(asap); + for (uint16_t asap = startIdx; asap <= objCount; asap++) + { + GroupObject& go = table.get(asap); - ComFlag flag = go.commFlag(); + ComFlag flag = go.commFlag(); - if (flag != ReadRequest && flag != WriteRequest) - continue; + if (flag != ReadRequest && flag != WriteRequest) + continue; - if (flag == WriteRequest) - { + if (flag == WriteRequest) + { #ifdef SMALL_GROUPOBJECT - GroupObject::processClassCallback(go); + GroupObject::processClassCallback(go); #else - GroupObjectUpdatedHandler handler = go.callback(); + GroupObjectUpdatedHandler handler = go.callback(); - if (handler) - handler(go); + if (handler) + handler(go); #endif - } + } - if (!go.communicationEnable()) - { - go.commFlag(Ok); - continue; - } + if (!go.communicationEnable()) + { + go.commFlag(Ok); + continue; + } - SecurityControl goSecurity; - goSecurity.toolAccess = false; // Secured group communication never uses the toolkey. ETS knows all keys, also the group keys. + SecurityControl goSecurity; + goSecurity.toolAccess = false; // Secured group communication never uses the toolkey. ETS knows all keys, also the group keys. #ifdef USE_DATASECURE - // Get security flags from Security Interface Object for this group object - goSecurity.dataSecurity = _secIfObj.getGroupObjectSecurity(asap); + // Get security flags from Security Interface Object for this group object + goSecurity.dataSecurity = _secIfObj.getGroupObjectSecurity(asap); #else - goSecurity.dataSecurity = DataSecurity::None; + goSecurity.dataSecurity = DataSecurity::None; #endif - if (flag == WriteRequest && go.transmitEnable()) - { - uint8_t* data = go.valueRef(); - _appLayer.groupValueWriteRequest(AckRequested, asap, go.priority(), NetworkLayerParameter, goSecurity, data, - go.sizeInTelegram()); + if (flag == WriteRequest && go.transmitEnable()) + { + uint8_t* data = go.valueRef(); + _appLayer.groupValueWriteRequest(AckRequested, asap, go.priority(), NetworkLayerParameter, goSecurity, data, + go.sizeInTelegram()); + } + else if (flag == ReadRequest) + { + _appLayer.groupValueReadRequest(AckRequested, asap, go.priority(), NetworkLayerParameter, goSecurity); + } + + go.commFlag(Transmitting); + + startIdx = asap + 1; + return; } - else if (flag == ReadRequest) - { - _appLayer.groupValueReadRequest(AckRequested, asap, go.priority(), NetworkLayerParameter, goSecurity); - } - - go.commFlag(Transmitting); - startIdx = asap + 1; - return; + startIdx = 1; } - startIdx = 1; -} - -void BauSystemBDevice::updateGroupObject(GroupObject& go, uint8_t* data, uint8_t length) -{ - uint8_t* goData = go.valueRef(); - - if (length != go.valueSize()) + void BauSystemBDevice::updateGroupObject(GroupObject& go, uint8_t* data, uint8_t length) { - go.commFlag(Error); - return; - } + uint8_t* goData = go.valueRef(); + + if (length != go.valueSize()) + { + go.commFlag(Error); + return; + } - memcpy(goData, data, length); + memcpy(goData, data, length); - if (go.commFlag() != WriteRequest) - { - go.commFlag(Updated); + if (go.commFlag() != WriteRequest) + { + go.commFlag(Updated); #ifdef SMALL_GROUPOBJECT - GroupObject::processClassCallback(go); + GroupObject::processClassCallback(go); #else - GroupObjectUpdatedHandler handler = go.callback(); + GroupObjectUpdatedHandler handler = go.callback(); - if (handler) - handler(go); + if (handler) + handler(go); #endif + } + else + { + go.commFlag(Updated); + } } - else - { - go.commFlag(Updated); - } -} -bool BauSystemBDevice::configured() -{ - // _configured is set to true initially, if the device was configured with ETS it will be set to true after restart + bool BauSystemBDevice::configured() + { + // _configured is set to true initially, if the device was configured with ETS it will be set to true after restart - if (!_configured) - return false; + if (!_configured) + return false; - _configured = _groupObjTable.loadState() == LS_LOADED - && _addrTable.loadState() == LS_LOADED - && _assocTable.loadState() == LS_LOADED - && _appProgram.loadState() == LS_LOADED; + _configured = _groupObjTable.loadState() == LS_LOADED + && _addrTable.loadState() == LS_LOADED + && _assocTable.loadState() == LS_LOADED + && _appProgram.loadState() == LS_LOADED; #ifdef USE_DATASECURE - _configured &= _secIfObj.loadState() == LS_LOADED; + _configured &= _secIfObj.loadState() == LS_LOADED; #endif - return _configured; -} + return _configured; + } -void BauSystemBDevice::doMasterReset(EraseCode eraseCode, uint8_t channel) -{ - BauSystemB::doMasterReset(eraseCode, channel); + void BauSystemBDevice::doMasterReset(EraseCode eraseCode, uint8_t channel) + { + BauSystemB::doMasterReset(eraseCode, channel); - _addrTable.masterReset(eraseCode, channel); - _assocTable.masterReset(eraseCode, channel); - _groupObjTable.masterReset(eraseCode, channel); + _addrTable.masterReset(eraseCode, channel); + _assocTable.masterReset(eraseCode, channel); + _groupObjTable.masterReset(eraseCode, channel); #ifdef USE_DATASECURE - _secIfObj.masterReset(eraseCode, channel); + _secIfObj.masterReset(eraseCode, channel); #endif -} + } -void BauSystemBDevice::groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength, bool status) -{ - GroupObject& go = _groupObjTable.get(asap); + void BauSystemBDevice::groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength, bool status) + { + GroupObject& go = _groupObjTable.get(asap); - if (status) - go.commFlag(Ok); - else - go.commFlag(Error); -} + if (status) + go.commFlag(Ok); + else + go.commFlag(Error); + } -void BauSystemBDevice::groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, bool status) -{ - GroupObject& go = _groupObjTable.get(asap); + void BauSystemBDevice::groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, bool status) + { + GroupObject& go = _groupObjTable.get(asap); - if (status) - go.commFlag(Ok); - else - go.commFlag(Error); -} + if (status) + go.commFlag(Ok); + else + go.commFlag(Error); + } -void BauSystemBDevice::groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl) -{ + void BauSystemBDevice::groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl) + { #ifdef USE_DATASECURE - DataSecurity requiredGoSecurity; + DataSecurity requiredGoSecurity; - // Get security flags from Security Interface Object for this group object - requiredGoSecurity = _secIfObj.getGroupObjectSecurity(asap); + // Get security flags from Security Interface Object for this group object + requiredGoSecurity = _secIfObj.getGroupObjectSecurity(asap); - if (secCtrl.dataSecurity != requiredGoSecurity) - { - println("GroupValueRead: access denied due to wrong security flags"); - return; - } + if (secCtrl.dataSecurity != requiredGoSecurity) + { + println("GroupValueRead: access denied due to wrong security flags"); + return; + } #endif - GroupObject& go = _groupObjTable.get(asap); + GroupObject& go = _groupObjTable.get(asap); - if (!go.communicationEnable() || !go.readEnable()) - return; + if (!go.communicationEnable() || !go.readEnable()) + return; - uint8_t* data = go.valueRef(); - _appLayer.groupValueReadResponse(AckRequested, asap, priority, hopType, secCtrl, data, go.sizeInTelegram()); -} + uint8_t* data = go.valueRef(); + _appLayer.groupValueReadResponse(AckRequested, asap, priority, hopType, secCtrl, data, go.sizeInTelegram()); + } -void BauSystemBDevice::groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, - uint8_t dataLength) -{ - GroupObject& go = _groupObjTable.get(asap); + void BauSystemBDevice::groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, + uint8_t dataLength) + { + GroupObject& go = _groupObjTable.get(asap); - if (!go.communicationEnable() || !go.responseUpdateEnable()) - return; + if (!go.communicationEnable() || !go.responseUpdateEnable()) + return; - updateGroupObject(go, data, dataLength); -} + updateGroupObject(go, data, dataLength); + } -void BauSystemBDevice::groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength) -{ + void BauSystemBDevice::groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength) + { #ifdef USE_DATASECURE - DataSecurity requiredGoSecurity; + DataSecurity requiredGoSecurity; - // Get security flags from Security Interface Object for this group object - requiredGoSecurity = _secIfObj.getGroupObjectSecurity(asap); + // Get security flags from Security Interface Object for this group object + requiredGoSecurity = _secIfObj.getGroupObjectSecurity(asap); - if (secCtrl.dataSecurity != requiredGoSecurity) - { - println("GroupValueWrite: access denied due to wrong security flags"); - return; - } + if (secCtrl.dataSecurity != requiredGoSecurity) + { + println("GroupValueWrite: access denied due to wrong security flags"); + return; + } #endif - GroupObject& go = _groupObjTable.get(asap); + GroupObject& go = _groupObjTable.get(asap); - if (!go.communicationEnable() || !go.writeEnable()) - return; + if (!go.communicationEnable() || !go.writeEnable()) + return; - updateGroupObject(go, data, dataLength); + updateGroupObject(go, data, dataLength); + } } \ No newline at end of file diff --git a/src/knx/bau/bau_systemB_device.h b/src/knx/bau/bau_systemB_device.h index 551d0ab2..6f43d784 100644 --- a/src/knx/bau/bau_systemB_device.h +++ b/src/knx/bau/bau_systemB_device.h @@ -17,42 +17,46 @@ #include "../platform/platform.h" #include "../util/memory.h" -class BauSystemBDevice : public BauSystemB +namespace Knx { - public: - BauSystemBDevice(Platform& platform); - void loop() override; - bool configured() override; - GroupObjectTableObject& groupObjectTable(); - - protected: - ApplicationLayer& applicationLayer() override; - - void groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, - uint8_t* data, uint8_t dataLength, bool status) override; - void groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, bool status) override; - void groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl) override; - void groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, + + class BauSystemBDevice : public BauSystemB + { + public: + BauSystemBDevice(Platform& platform); + void loop() override; + bool configured() override; + GroupObjectTableObject& groupObjectTable(); + + protected: + ApplicationLayer& applicationLayer() override; + + void groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, + uint8_t* data, uint8_t dataLength, bool status) override; + void groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, bool status) override; + void groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl) override; + void groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, + uint8_t* data, uint8_t dataLength) override; + void groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength) override; - void groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, - uint8_t* data, uint8_t dataLength) override; - void sendNextGroupTelegram(); - void updateGroupObject(GroupObject& go, uint8_t* data, uint8_t length); + void sendNextGroupTelegram(); + void updateGroupObject(GroupObject& go, uint8_t* data, uint8_t length); - void doMasterReset(EraseCode eraseCode, uint8_t channel) override; + void doMasterReset(EraseCode eraseCode, uint8_t channel) override; - AddressTableObject _addrTable; - AssociationTableObject _assocTable; - GroupObjectTableObject _groupObjTable; + AddressTableObject _addrTable; + AssociationTableObject _assocTable; + GroupObjectTableObject _groupObjTable; #ifdef USE_DATASECURE - SecureApplicationLayer _appLayer; - SecurityInterfaceObject _secIfObj; + SecureApplicationLayer _appLayer; + SecurityInterfaceObject _secIfObj; #else - ApplicationLayer _appLayer; + ApplicationLayer _appLayer; #endif - TransportLayer _transLayer; - NetworkLayerDevice _netLayer; + TransportLayer _transLayer; + NetworkLayerDevice _netLayer; - bool _configured = true; -}; + bool _configured = true; + }; +} \ No newline at end of file diff --git a/src/knx/bits.cpp b/src/knx/bits.cpp index 3972ee70..d96b967b 100644 --- a/src/knx/bits.cpp +++ b/src/knx/bits.cpp @@ -2,179 +2,183 @@ #include "bits.h" #include // for memcpy() -const uint8_t* popByte(uint8_t& b, const uint8_t* data) +namespace Knx { - b = *data; - data += 1; - return data; -} -#ifndef KNX_NO_PRINT + const uint8_t* popByte(uint8_t& b, const uint8_t* data) + { + b = *data; + data += 1; + return data; + } -void printHex(const char* suffix, const uint8_t* data, size_t length, bool newline) -{ - print(suffix); +#ifndef KNX_NO_PRINT - for (size_t i = 0; i < length; i++) + void printHex(const char* suffix, const uint8_t* data, size_t length, bool newline) { - if (data[i] < 0x10) + print(suffix); + + for (size_t i = 0; i < length; i++) { - print("0"); + if (data[i] < 0x10) + { + print("0"); + } + + print(data[i], HEX); + print(" "); } - print(data[i], HEX); - print(" "); + if (newline) + { + println(); + } } +#endif - if (newline) + const uint8_t* popWord(uint16_t& w, const uint8_t* data) { - println(); + w = getWord(data); + data += 2; + return data; } -} -#endif -const uint8_t* popWord(uint16_t& w, const uint8_t* data) -{ - w = getWord(data); - data += 2; - return data; -} - -const uint8_t* popInt(uint32_t& i, const uint8_t* data) -{ - i = getInt(data); - data += 4; - return data; -} - -const uint8_t* popByteArray(uint8_t* dst, uint32_t size, const uint8_t* data) -{ - for (uint32_t i = 0; i < size; i++) - dst[i] = data[i]; + const uint8_t* popInt(uint32_t& i, const uint8_t* data) + { + i = getInt(data); + data += 4; + return data; + } - data += size; - return data; -} + const uint8_t* popByteArray(uint8_t* dst, uint32_t size, const uint8_t* data) + { + for (uint32_t i = 0; i < size; i++) + dst[i] = data[i]; -uint8_t* pushByte(uint8_t b, uint8_t* data) -{ - data[0] = b; - data += 1; - return data; -} + data += size; + return data; + } -uint8_t* pushWord(uint16_t w, uint8_t* data) -{ - data[0] = ((w >> 8) & 0xff); - data[1] = (w & 0xff); - data += 2; - return data; -} + uint8_t* pushByte(uint8_t b, uint8_t* data) + { + data[0] = b; + data += 1; + return data; + } -uint8_t* pushInt(uint32_t i, uint8_t* data) -{ - data[0] = ((i >> 24) & 0xff); - data[1] = ((i >> 16) & 0xff); - data[2] = ((i >> 8) & 0xff); - data[3] = (i & 0xff); - data += 4; - return data; -} - -uint8_t* pushByteArray(const uint8_t* src, uint32_t size, uint8_t* data) -{ - for (uint32_t i = 0; i < size; i++) - data[i] = src[i]; + uint8_t* pushWord(uint16_t w, uint8_t* data) + { + data[0] = ((w >> 8) & 0xff); + data[1] = (w & 0xff); + data += 2; + return data; + } - data += size; - return data; -} + uint8_t* pushInt(uint32_t i, uint8_t* data) + { + data[0] = ((i >> 24) & 0xff); + data[1] = ((i >> 16) & 0xff); + data[2] = ((i >> 8) & 0xff); + data[3] = (i & 0xff); + data += 4; + return data; + } -uint16_t getWord(const uint8_t* data) -{ - return (data[0] << 8) + data[1]; -} + uint8_t* pushByteArray(const uint8_t* src, uint32_t size, uint8_t* data) + { + for (uint32_t i = 0; i < size; i++) + data[i] = src[i]; -uint32_t getInt(const uint8_t* data) -{ - return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]; -} + data += size; + return data; + } -void sixBytesFromUInt64(uint64_t num, uint8_t* toByteArray) -{ - toByteArray[0] = ((num >> 40) & 0xff); - toByteArray[1] = ((num >> 32) & 0xff); - toByteArray[2] = ((num >> 24) & 0xff); - toByteArray[3] = ((num >> 16) & 0xff); - toByteArray[4] = ((num >> 8) & 0xff); - toByteArray[5] = (num & 0xff); -} - -uint64_t sixBytesToUInt64(uint8_t* data) -{ - uint64_t l = 0; + uint16_t getWord(const uint8_t* data) + { + return (data[0] << 8) + data[1]; + } - for (uint8_t i = 0; i < 6; i++) + uint32_t getInt(const uint8_t* data) { - l = (l << 8) + data[i]; + return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]; } - return l; -} + void sixBytesFromUInt64(uint64_t num, uint8_t* toByteArray) + { + toByteArray[0] = ((num >> 40) & 0xff); + toByteArray[1] = ((num >> 32) & 0xff); + toByteArray[2] = ((num >> 24) & 0xff); + toByteArray[3] = ((num >> 16) & 0xff); + toByteArray[4] = ((num >> 8) & 0xff); + toByteArray[5] = (num & 0xff); + } -// The CRC of the Memory Control Block Table Property is a CRC16-CCITT with the following -// parameters: -// Width = 16 bit -// Truncated polynomial = 1021h -// Initial value = FFFFh -// Input date is NOT reflected. -// Output CRC is NOT reflected. -// No XOR is performed on the output CRC. -// EXAMPLE The correct CRC16-CCITT of the string ‘123456789’ is E5CCh. + uint64_t sixBytesToUInt64(uint8_t* data) + { + uint64_t l = 0; -uint16_t crc16Ccitt(uint8_t* input, uint16_t length) -{ - uint32_t polynom = 0x1021; + for (uint8_t i = 0; i < 6; i++) + { + l = (l << 8) + data[i]; + } - uint32_t result = 0xffff; + return l; + } - for (uint32_t i = 0; i < 8 * ((uint32_t)length + 2); i++) + // The CRC of the Memory Control Block Table Property is a CRC16-CCITT with the following + // parameters: + // Width = 16 bit + // Truncated polynomial = 1021h + // Initial value = FFFFh + // Input date is NOT reflected. + // Output CRC is NOT reflected. + // No XOR is performed on the output CRC. + // EXAMPLE The correct CRC16-CCITT of the string ‘123456789’ is E5CCh. + + uint16_t crc16Ccitt(uint8_t* input, uint16_t length) { - result <<= 1; - uint32_t nextBit; - nextBit = ((i / 8) < length) ? ((input[i / 8] >> (7 - (i % 8))) & 0x1) : 0; - result |= nextBit; + uint32_t polynom = 0x1021; - if ((result & 0x10000) != 0) - result ^= polynom; - } + uint32_t result = 0xffff; - return result & 0xffff; -} + for (uint32_t i = 0; i < 8 * ((uint32_t)length + 2); i++) + { + result <<= 1; + uint32_t nextBit; + nextBit = ((i / 8) < length) ? ((input[i / 8] >> (7 - (i % 8))) & 0x1) : 0; + result |= nextBit; -uint16_t crc16Dnp(uint8_t* input, uint16_t length) -{ - // CRC-16-DNP - // generator polynomial = 2^16 + 2^13 + 2^12 + 2^11 + 2^10 + 2^8 + 2^6 + 2^5 + 2^2 + 2^0 - uint32_t pn = 0x13d65; // 1 0011 1101 0110 0101 + if ((result & 0x10000) != 0) + result ^= polynom; + } - // for much data, using a lookup table would be a way faster CRC calculation - uint32_t crc = 0; + return result & 0xffff; + } - for (uint32_t i = 0; i < length; i++) + uint16_t crc16Dnp(uint8_t* input, uint16_t length) { - uint8_t bite = input[i] & 0xff; + // CRC-16-DNP + // generator polynomial = 2^16 + 2^13 + 2^12 + 2^11 + 2^10 + 2^8 + 2^6 + 2^5 + 2^2 + 2^0 + uint32_t pn = 0x13d65; // 1 0011 1101 0110 0101 + + // for much data, using a lookup table would be a way faster CRC calculation + uint32_t crc = 0; - for (uint8_t b = 8; b -- > 0;) + for (uint32_t i = 0; i < length; i++) { - bool bit = ((bite >> b) & 1) == 1; - bool one = (crc >> 15 & 1) == 1; - crc <<= 1; + uint8_t bite = input[i] & 0xff; - if (one ^ bit) - crc ^= pn; + for (uint8_t b = 8; b -- > 0;) + { + bool bit = ((bite >> b) & 1) == 1; + bool one = (crc >> 15 & 1) == 1; + crc <<= 1; + + if (one ^ bit) + crc ^= pn; + } } - } - return (~crc) & 0xffff; -} + return (~crc) & 0xffff; + } +} \ No newline at end of file diff --git a/src/knx/bits.h b/src/knx/bits.h index 074dea37..5e347833 100644 --- a/src/knx/bits.h +++ b/src/knx/bits.h @@ -4,19 +4,19 @@ #include #if defined(__linux__) - #include +#include #elif defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_STM32) || defined (DeviceFamily_CC13X0) - #define htons(x) ( ((x)<< 8 & 0xFF00) | \ +#define htons(x) ( ((x)<< 8 & 0xFF00) | \ ((x)>> 8 & 0x00FF) ) - #define ntohs(x) htons(x) +#define ntohs(x) htons(x) - #define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ +#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ ((x)<< 8 & 0x00FF0000UL) | \ ((x)>> 8 & 0x0000FF00UL) | \ ((x)>>24 & 0x000000FFUL) ) - #define ntohl(x) htonl(x) - #define ntohs(x) htons(x) - #define ntohl(x) htonl(x) +#define ntohl(x) htonl(x) +#define ntohs(x) htons(x) +#define ntohl(x) htonl(x) #endif #ifndef MIN @@ -68,7 +68,8 @@ typedef void (*voidFuncPtr)(void); void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode); #endif - +namespace Knx +{ #ifndef KNX_NO_PRINT void print(const char[]); void print(char); @@ -112,22 +113,22 @@ #define KNX_ACTIVITYCALLBACK_NET 0x04 #endif -const uint8_t* popByte(uint8_t& b, const uint8_t* data); -const uint8_t* popWord(uint16_t& w, const uint8_t* data); -const uint8_t* popInt(uint32_t& i, const uint8_t* data); -const uint8_t* popByteArray(uint8_t* dst, uint32_t size, const uint8_t* data); -uint8_t* pushByte(uint8_t b, uint8_t* data); -uint8_t* pushWord(uint16_t w, uint8_t* data); -uint8_t* pushInt(uint32_t i, uint8_t* data); -uint8_t* pushByteArray(const uint8_t* src, uint32_t size, uint8_t* data); -uint16_t getWord(const uint8_t* data); -uint32_t getInt(const uint8_t* data); + const uint8_t* popByte(uint8_t& b, const uint8_t* data); + const uint8_t* popWord(uint16_t& w, const uint8_t* data); + const uint8_t* popInt(uint32_t& i, const uint8_t* data); + const uint8_t* popByteArray(uint8_t* dst, uint32_t size, const uint8_t* data); + uint8_t* pushByte(uint8_t b, uint8_t* data); + uint8_t* pushWord(uint16_t w, uint8_t* data); + uint8_t* pushInt(uint32_t i, uint8_t* data); + uint8_t* pushByteArray(const uint8_t* src, uint32_t size, uint8_t* data); + uint16_t getWord(const uint8_t* data); + uint32_t getInt(const uint8_t* data); -void sixBytesFromUInt64(uint64_t num, uint8_t* toByteArray); -uint64_t sixBytesToUInt64(uint8_t* data); + void sixBytesFromUInt64(uint64_t num, uint8_t* toByteArray); + uint64_t sixBytesToUInt64(uint8_t* data); -uint16_t crc16Ccitt(uint8_t* input, uint16_t length); -uint16_t crc16Dnp(uint8_t* input, uint16_t length); + uint16_t crc16Ccitt(uint8_t* input, uint16_t length); + uint16_t crc16Dnp(uint8_t* input, uint16_t length); #if defined(ARDUINO_ARCH_SAMD) // temporary undef until framework-arduino-samd > 1.8.9 is released. See https://github.com/arduino/ArduinoCore-samd/pull/399 for a PR should will probably address this @@ -135,3 +136,4 @@ uint16_t crc16Dnp(uint8_t* input, uint16_t length); #undef min // end of temporary undef #endif +} \ No newline at end of file diff --git a/src/knx/cemi_server/cemi_server.cpp b/src/knx/cemi_server/cemi_server.cpp index ae01680a..aa333e25 100644 --- a/src/knx/cemi_server/cemi_server.cpp +++ b/src/knx/cemi_server/cemi_server.cpp @@ -9,421 +9,425 @@ #include #include -CemiServer::CemiServer(BauSystemB& bau) - : _bau(bau) +namespace Knx +{ + + CemiServer::CemiServer(BauSystemB& bau) + : _bau(bau) #ifdef USE_USB - , - _usbTunnelInterface(*this, - _bau.deviceObject().maskVersion(), - _bau.deviceObject().manufacturerId()) + , + _usbTunnelInterface(*this, + _bau.deviceObject().maskVersion(), + _bau.deviceObject().manufacturerId()) #endif -{ - // The cEMI server will hand out the device address + 1 to the cEMI client (e.g. ETS), - // so that the device and the cEMI client/server connection(tunnel) can operate simultaneously. - _clientAddress = _bau.deviceObject().individualAddress() + 1; -} + { + // The cEMI server will hand out the device address + 1 to the cEMI client (e.g. ETS), + // so that the device and the cEMI client/server connection(tunnel) can operate simultaneously. + _clientAddress = _bau.deviceObject().individualAddress() + 1; + } -void CemiServer::dataLinkLayer(DataLinkLayer& layer) -{ - _dataLinkLayer = &layer; -} + void CemiServer::dataLinkLayer(DataLinkLayer& layer) + { + _dataLinkLayer = &layer; + } #ifdef KNX_TUNNELING -void CemiServer::dataLinkLayerPrimary(DataLinkLayer& layer) -{ - _dataLinkLayerPrimary = &layer; -} + void CemiServer::dataLinkLayerPrimary(DataLinkLayer& layer) + { + _dataLinkLayerPrimary = &layer; + } #endif -uint16_t CemiServer::clientAddress() const -{ - return _clientAddress; -} + uint16_t CemiServer::clientAddress() const + { + return _clientAddress; + } -void CemiServer::clientAddress(uint16_t value) -{ - _clientAddress = value; -} + void CemiServer::clientAddress(uint16_t value) + { + _clientAddress = value; + } -void CemiServer::dataConfirmationToTunnel(CemiFrame& frame) -{ - MessageCode backupMsgCode = frame.messageCode(); + void CemiServer::dataConfirmationToTunnel(CemiFrame& frame) + { + MessageCode backupMsgCode = frame.messageCode(); - frame.messageCode(L_data_con); + frame.messageCode(L_data_con); #ifdef KNX_LOG_TUNNELING - print("L_data_con: src: "); - print(frame.sourceAddress(), HEX); - print(" dst: "); - print(frame.destinationAddress(), HEX); + print("L_data_con: src: "); + print(frame.sourceAddress(), HEX); + print(" dst: "); + print(frame.destinationAddress(), HEX); - printHex(" frame: ", frame.data(), frame.dataLength()); + printHex(" frame: ", frame.data(), frame.dataLength()); #endif #ifdef USE_USB - _usbTunnelInterface.sendCemiFrame(frame); + _usbTunnelInterface.sendCemiFrame(frame); #elif defined(KNX_TUNNELING) - _dataLinkLayerPrimary->dataConfirmationToTunnel(frame); + _dataLinkLayerPrimary->dataConfirmationToTunnel(frame); #endif - frame.messageCode(backupMsgCode); -} - -void CemiServer::dataIndicationToTunnel(CemiFrame& frame) -{ - bool isRf = _dataLinkLayer->mediumType() == DptMedium::KNX_RF; - uint8_t data[frame.dataLength() + (isRf ? 10 : 0)]; - - if (isRf) - { - data[0] = L_data_ind; // Message Code - data[1] = 0x0A; // Total additional info length - data[2] = 0x02; // RF add. info: type - data[3] = 0x08; // RF add. info: length - data[4] = frame.rfInfo(); // RF add. info: info field (batt ok, bidir) - pushByteArray(frame.rfSerialOrDoA(), 6, &data[5]); // RF add. info:Serial or Domain Address - data[11] = frame.rfLfn(); // RF add. info: link layer frame number - memcpy(&data[12], &((frame.data())[2]), frame.dataLength() - 2); + frame.messageCode(backupMsgCode); } - else + + void CemiServer::dataIndicationToTunnel(CemiFrame& frame) { - memcpy(&data[0], frame.data(), frame.dataLength()); - } + bool isRf = _dataLinkLayer->mediumType() == DptMedium::KNX_RF; + uint8_t data[frame.dataLength() + (isRf ? 10 : 0)]; - CemiFrame tmpFrame(data, sizeof(data)); + if (isRf) + { + data[0] = L_data_ind; // Message Code + data[1] = 0x0A; // Total additional info length + data[2] = 0x02; // RF add. info: type + data[3] = 0x08; // RF add. info: length + data[4] = frame.rfInfo(); // RF add. info: info field (batt ok, bidir) + pushByteArray(frame.rfSerialOrDoA(), 6, &data[5]); // RF add. info:Serial or Domain Address + data[11] = frame.rfLfn(); // RF add. info: link layer frame number + memcpy(&data[12], &((frame.data())[2]), frame.dataLength() - 2); + } + else + { + memcpy(&data[0], frame.data(), frame.dataLength()); + } + + CemiFrame tmpFrame(data, sizeof(data)); #ifdef KNX_LOG_TUNNELING - print("ToTunnel "); - print("L_data_ind: src: "); - print(tmpFrame.sourceAddress(), HEX); - print(" dst: "); - print(tmpFrame.destinationAddress(), HEX); + print("ToTunnel "); + print("L_data_ind: src: "); + print(tmpFrame.sourceAddress(), HEX); + print(" dst: "); + print(tmpFrame.destinationAddress(), HEX); - printHex(" frame: ", tmpFrame.data(), tmpFrame.dataLength()); + printHex(" frame: ", tmpFrame.data(), tmpFrame.dataLength()); #endif - tmpFrame.apdu().type(); + tmpFrame.apdu().type(); #ifdef USE_USB - _usbTunnelInterface.sendCemiFrame(tmpFrame); + _usbTunnelInterface.sendCemiFrame(tmpFrame); #elif defined(KNX_TUNNELING) - _dataLinkLayerPrimary->dataIndicationToTunnel(frame); + _dataLinkLayerPrimary->dataIndicationToTunnel(frame); #endif -} + } -void CemiServer::frameReceived(CemiFrame& frame) -{ - switch (frame.messageCode()) + void CemiServer::frameReceived(CemiFrame& frame) { - case L_data_req: + switch (frame.messageCode()) { - handleLData(frame); - break; - } + case L_data_req: + { + handleLData(frame); + break; + } - case M_PropRead_req: - { - handleMPropRead(frame); - break; - } + case M_PropRead_req: + { + handleMPropRead(frame); + break; + } - case M_PropWrite_req: - { - handleMPropWrite(frame); - break; - } + case M_PropWrite_req: + { + handleMPropWrite(frame); + break; + } - case M_FuncPropCommand_req: - { - println("M_FuncPropCommand_req not implemented"); - break; - } + case M_FuncPropCommand_req: + { + println("M_FuncPropCommand_req not implemented"); + break; + } - case M_FuncPropStateRead_req: - { - println("M_FuncPropStateRead_req not implemented"); - break; - } + case M_FuncPropStateRead_req: + { + println("M_FuncPropStateRead_req not implemented"); + break; + } - case M_Reset_req: - { - handleMReset(frame); - break; + case M_Reset_req: + { + handleMReset(frame); + break; + } + + // we should never receive these: server -> client + case L_data_con: + case L_data_ind: + case M_PropInfo_ind: + case M_PropRead_con: + case M_PropWrite_con: + case M_FuncPropCommand_con: + + //case M_FuncPropStateRead_con: // same value as M_FuncPropCommand_con + case M_Reset_ind: + default: + break; } - - // we should never receive these: server -> client - case L_data_con: - case L_data_ind: - case M_PropInfo_ind: - case M_PropRead_con: - case M_PropWrite_con: - case M_FuncPropCommand_con: - - //case M_FuncPropStateRead_con: // same value as M_FuncPropCommand_con - case M_Reset_ind: - default: - break; } -} -void CemiServer::handleLData(CemiFrame& frame) -{ - // Fill in the cEMI client address if the client sets - // source address to 0. -#ifndef KNX_TUNNELING - //We already set the correct IA - if (frame.sourceAddress() == 0x0000) + void CemiServer::handleLData(CemiFrame& frame) { - frame.sourceAddress(_clientAddress); - } + // Fill in the cEMI client address if the client sets + // source address to 0. +#ifndef KNX_TUNNELING + //We already set the correct IA + if (frame.sourceAddress() == 0x0000) + { + frame.sourceAddress(_clientAddress); + } #endif - if (_dataLinkLayer->mediumType() == DptMedium::KNX_RF) - { - // Check if we have additional info for RF - if (((frame.data())[1] == 0x0A) && // Additional info total length: we only handle one additional info of type RF - ((frame.data())[2] == 0x02) && // Additional info type: RF - ((frame.data())[3] == 0x08) ) // Additional info length of type RF: 8 bytes (fixed) + if (_dataLinkLayer->mediumType() == DptMedium::KNX_RF) { - frame.rfInfo((frame.data())[4]); - - // Use the values provided in the RF additonal info - if ( ((frame.data())[5] != 0x00) || ((frame.data())[6] != 0x00) || ((frame.data())[7] != 0x00) || - ((frame.data())[8] != 0x00) || ((frame.data())[9] != 0x00) || ((frame.data())[10] != 0x00) ) + // Check if we have additional info for RF + if (((frame.data())[1] == 0x0A) && // Additional info total length: we only handle one additional info of type RF + ((frame.data())[2] == 0x02) && // Additional info type: RF + ((frame.data())[3] == 0x08) ) // Additional info length of type RF: 8 bytes (fixed) { - frame.rfSerialOrDoA(&((frame.data())[5])); - } // else leave the nullptr as it is - - frame.rfLfn((frame.data())[11]); - } - - // If the cEMI client does not provide a link layer frame number (LFN), - // we use our own counter. - // Note: There is another link layer frame number counter inside the RF data link layer class! - // That counter is solely for the local application! - // If we set a LFN here, the data link layer counter is NOT used! - if (frame.rfLfn() == 0xFF) - { - // Set Data Link Layer Frame Number - frame.rfLfn(_frameNumber); - // Link Layer frame number counts 0..7 - _frameNumber = (_frameNumber + 1) & 0x7; + frame.rfInfo((frame.data())[4]); + + // Use the values provided in the RF additonal info + if ( ((frame.data())[5] != 0x00) || ((frame.data())[6] != 0x00) || ((frame.data())[7] != 0x00) || + ((frame.data())[8] != 0x00) || ((frame.data())[9] != 0x00) || ((frame.data())[10] != 0x00) ) + { + frame.rfSerialOrDoA(&((frame.data())[5])); + } // else leave the nullptr as it is + + frame.rfLfn((frame.data())[11]); + } + + // If the cEMI client does not provide a link layer frame number (LFN), + // we use our own counter. + // Note: There is another link layer frame number counter inside the RF data link layer class! + // That counter is solely for the local application! + // If we set a LFN here, the data link layer counter is NOT used! + if (frame.rfLfn() == 0xFF) + { + // Set Data Link Layer Frame Number + frame.rfLfn(_frameNumber); + // Link Layer frame number counts 0..7 + _frameNumber = (_frameNumber + 1) & 0x7; + } } - } #ifdef KNX_LOG_TUNNELING - print("L_data_req: src: "); - print(frame.sourceAddress(), HEX); - print(" dst: "); - print(frame.destinationAddress(), HEX); - printHex(" frame: ", frame.data(), frame.dataLength()); + print("L_data_req: src: "); + print(frame.sourceAddress(), HEX); + print(" dst: "); + print(frame.destinationAddress(), HEX); + printHex(" frame: ", frame.data(), frame.dataLength()); #endif #ifdef KNX_TUNNELING - _dataLinkLayer->dataRequestFromTunnel(frame); + _dataLinkLayer->dataRequestFromTunnel(frame); #endif -} + } -void CemiServer::handleMPropRead(CemiFrame& frame) -{ + void CemiServer::handleMPropRead(CemiFrame& frame) + { #ifdef KNX_LOG_TUNNELING - print("M_PropRead_req: "); + print("M_PropRead_req: "); #endif - uint16_t objectType; - popWord(objectType, &frame.data()[1]); - uint8_t objectInstance = frame.data()[3]; - uint8_t propertyId = frame.data()[4]; - uint8_t numberOfElements = frame.data()[5] >> 4; - uint16_t startIndex = frame.data()[6] | ((frame.data()[5] & 0x0F) << 8); - uint8_t* data = nullptr; - uint32_t dataSize = 0; + uint16_t objectType; + popWord(objectType, &frame.data()[1]); + uint8_t objectInstance = frame.data()[3]; + uint8_t propertyId = frame.data()[4]; + uint8_t numberOfElements = frame.data()[5] >> 4; + uint16_t startIndex = frame.data()[6] | ((frame.data()[5] & 0x0F) << 8); + uint8_t* data = nullptr; + uint32_t dataSize = 0; #ifdef KNX_LOG_TUNNELING - print("ObjType: "); - print(objectType, DEC); - print(" ObjInst: "); - print(objectInstance, DEC); - print(" PropId: "); - print(propertyId, DEC); - print(" NoE: "); - print(numberOfElements, DEC); - print(" startIdx: "); - print(startIndex, DEC); + print("ObjType: "); + print(objectType, DEC); + print(" ObjInst: "); + print(objectInstance, DEC); + print(" PropId: "); + print(propertyId, DEC); + print(" NoE: "); + print(numberOfElements, DEC); + print(" startIdx: "); + print(startIndex, DEC); #endif - // propertyValueRead() allocates memory for the data! Needs to be deleted again! - _bau.propertyValueRead((ObjectType)objectType, objectInstance, propertyId, numberOfElements, startIndex, &data, dataSize); - - // Patch result for device address in device object - // The cEMI server will hand out the device address + 1 to the cEMI client (e.g. ETS), - // so that the device and the cEMI client/server connection(tunnel) can operate simultaneously. - // KNX IP Interfaces which offer multiple simultaneous tunnel connections seem to operate the same way. - // Each tunnel has its own cEMI client address which is based on the main device address. - if (((ObjectType) objectType == OT_DEVICE) && - (propertyId == PID_DEVICE_ADDR) && - (numberOfElements == 1)) - { - data[0] = (uint8_t) (_clientAddress & 0xFF); - } - else if (((ObjectType) objectType == OT_DEVICE) && - (propertyId == PID_SUBNET_ADDR) && - (numberOfElements == 1)) - { - data[0] = (uint8_t) ((_clientAddress >> 8) & 0xFF); - } + // propertyValueRead() allocates memory for the data! Needs to be deleted again! + _bau.propertyValueRead((ObjectType)objectType, objectInstance, propertyId, numberOfElements, startIndex, &data, dataSize); + + // Patch result for device address in device object + // The cEMI server will hand out the device address + 1 to the cEMI client (e.g. ETS), + // so that the device and the cEMI client/server connection(tunnel) can operate simultaneously. + // KNX IP Interfaces which offer multiple simultaneous tunnel connections seem to operate the same way. + // Each tunnel has its own cEMI client address which is based on the main device address. + if (((ObjectType) objectType == OT_DEVICE) && + (propertyId == PID_DEVICE_ADDR) && + (numberOfElements == 1)) + { + data[0] = (uint8_t) (_clientAddress & 0xFF); + } + else if (((ObjectType) objectType == OT_DEVICE) && + (propertyId == PID_SUBNET_ADDR) && + (numberOfElements == 1)) + { + data[0] = (uint8_t) ((_clientAddress >> 8) & 0xFF); + } - if (data && dataSize && numberOfElements) - { + if (data && dataSize && numberOfElements) + { #ifdef KNX_LOG_TUNNELING - printHex(" <- data: ", data, dataSize); + printHex(" <- data: ", data, dataSize); #endif - // Prepare positive response - uint8_t responseData[7 + dataSize]; - memcpy(responseData, frame.data(), 7); - memcpy(&responseData[7], data, dataSize); + // Prepare positive response + uint8_t responseData[7 + dataSize]; + memcpy(responseData, frame.data(), 7); + memcpy(&responseData[7], data, dataSize); - CemiFrame responseFrame(responseData, sizeof(responseData)); - responseFrame.messageCode(M_PropRead_con); + CemiFrame responseFrame(responseData, sizeof(responseData)); + responseFrame.messageCode(M_PropRead_con); #ifdef USE_USB - _usbTunnelInterface.sendCemiFrame(responseFrame); + _usbTunnelInterface.sendCemiFrame(responseFrame); #elif defined(KNX_TUNNELING) - _dataLinkLayerPrimary->dataRequestToTunnel(responseFrame); + _dataLinkLayerPrimary->dataRequestToTunnel(responseFrame); #endif - delete[] data; - } - else - { - // Prepare negative response - uint8_t responseData[7 + 1]; - memcpy(responseData, frame.data(), sizeof(responseData)); - responseData[7] = Void_DP; // Set cEMI error code - responseData[5] = 0; // Set Number of elements to zero + delete[] data; + } + else + { + // Prepare negative response + uint8_t responseData[7 + 1]; + memcpy(responseData, frame.data(), sizeof(responseData)); + responseData[7] = Void_DP; // Set cEMI error code + responseData[5] = 0; // Set Number of elements to zero - printHex(" <- error: ", &responseData[7], 1); - println(""); + printHex(" <- error: ", &responseData[7], 1); + println(""); - CemiFrame responseFrame(responseData, sizeof(responseData)); - responseFrame.messageCode(M_PropRead_con); + CemiFrame responseFrame(responseData, sizeof(responseData)); + responseFrame.messageCode(M_PropRead_con); #ifdef USE_USB - _usbTunnelInterface.sendCemiFrame(responseFrame); + _usbTunnelInterface.sendCemiFrame(responseFrame); #elif defined(KNX_TUNNELING) - _dataLinkLayerPrimary->dataRequestToTunnel(responseFrame); + _dataLinkLayerPrimary->dataRequestToTunnel(responseFrame); #endif + } } -} -void CemiServer::handleMPropWrite(CemiFrame& frame) -{ - print("M_PropWrite_req: "); - - uint16_t objectType; - popWord(objectType, &frame.data()[1]); - uint8_t objectInstance = frame.data()[3]; - uint8_t propertyId = frame.data()[4]; - uint8_t numberOfElements = frame.data()[5] >> 4; - uint16_t startIndex = frame.data()[6] | ((frame.data()[5] & 0x0F) << 8); - uint8_t* requestData = &frame.data()[7]; - uint32_t requestDataSize = frame.dataLength() - 7; - - print("ObjType: "); - print(objectType, DEC); - print(" ObjInst: "); - print(objectInstance, DEC); - print(" PropId: "); - print(propertyId, DEC); - print(" NoE: "); - print(numberOfElements, DEC); - print(" startIdx: "); - print(startIndex, DEC); - - printHex(" -> data: ", requestData, requestDataSize); - - // Patch request for device address in device object - if (((ObjectType) objectType == OT_DEVICE) && - (propertyId == PID_DEVICE_ADDR) && - (numberOfElements == 1)) - { - // Temporarily store new cEMI client address in memory - // We also be sent back if the client requests it again - _clientAddress = (_clientAddress & 0xFF00) | requestData[0]; - print("cEMI client address: "); - println(_clientAddress, HEX); - } - else if (((ObjectType) objectType == OT_DEVICE) && - (propertyId == PID_SUBNET_ADDR) && - (numberOfElements == 1)) - { - // Temporarily store new cEMI client address in memory - // We also be sent back if the client requests it again - _clientAddress = (_clientAddress & 0x00FF) | (requestData[0] << 8); - print("cEMI client address: "); - println(_clientAddress, HEX); - } - else + void CemiServer::handleMPropWrite(CemiFrame& frame) { - _bau.propertyValueWrite((ObjectType)objectType, objectInstance, propertyId, numberOfElements, startIndex, requestData, requestDataSize); - } + print("M_PropWrite_req: "); + + uint16_t objectType; + popWord(objectType, &frame.data()[1]); + uint8_t objectInstance = frame.data()[3]; + uint8_t propertyId = frame.data()[4]; + uint8_t numberOfElements = frame.data()[5] >> 4; + uint16_t startIndex = frame.data()[6] | ((frame.data()[5] & 0x0F) << 8); + uint8_t* requestData = &frame.data()[7]; + uint32_t requestDataSize = frame.dataLength() - 7; + + print("ObjType: "); + print(objectType, DEC); + print(" ObjInst: "); + print(objectInstance, DEC); + print(" PropId: "); + print(propertyId, DEC); + print(" NoE: "); + print(numberOfElements, DEC); + print(" startIdx: "); + print(startIndex, DEC); + + printHex(" -> data: ", requestData, requestDataSize); + + // Patch request for device address in device object + if (((ObjectType) objectType == OT_DEVICE) && + (propertyId == PID_DEVICE_ADDR) && + (numberOfElements == 1)) + { + // Temporarily store new cEMI client address in memory + // We also be sent back if the client requests it again + _clientAddress = (_clientAddress & 0xFF00) | requestData[0]; + print("cEMI client address: "); + println(_clientAddress, HEX); + } + else if (((ObjectType) objectType == OT_DEVICE) && + (propertyId == PID_SUBNET_ADDR) && + (numberOfElements == 1)) + { + // Temporarily store new cEMI client address in memory + // We also be sent back if the client requests it again + _clientAddress = (_clientAddress & 0x00FF) | (requestData[0] << 8); + print("cEMI client address: "); + println(_clientAddress, HEX); + } + else + { + _bau.propertyValueWrite((ObjectType)objectType, objectInstance, propertyId, numberOfElements, startIndex, requestData, requestDataSize); + } - if (numberOfElements) - { - // Prepare positive response - uint8_t responseData[7]; - memcpy(responseData, frame.data(), sizeof(responseData)); + if (numberOfElements) + { + // Prepare positive response + uint8_t responseData[7]; + memcpy(responseData, frame.data(), sizeof(responseData)); - println(" <- no error"); + println(" <- no error"); - CemiFrame responseFrame(responseData, sizeof(responseData)); - responseFrame.messageCode(M_PropWrite_con); + CemiFrame responseFrame(responseData, sizeof(responseData)); + responseFrame.messageCode(M_PropWrite_con); #ifdef USE_USB - _usbTunnelInterface.sendCemiFrame(responseFrame); + _usbTunnelInterface.sendCemiFrame(responseFrame); #elif defined(KNX_TUNNELING) - _dataLinkLayerPrimary->dataRequestToTunnel(responseFrame); + _dataLinkLayerPrimary->dataRequestToTunnel(responseFrame); #endif - } - else - { - // Prepare negative response - uint8_t responseData[7 + 1]; - memcpy(responseData, frame.data(), sizeof(responseData)); - responseData[7] = Illegal_Command; // Set cEMI error code - responseData[5] = 0; // Set Number of elements to zero + } + else + { + // Prepare negative response + uint8_t responseData[7 + 1]; + memcpy(responseData, frame.data(), sizeof(responseData)); + responseData[7] = Illegal_Command; // Set cEMI error code + responseData[5] = 0; // Set Number of elements to zero - printHex(" <- error: ", &responseData[7], 1); - println(""); + printHex(" <- error: ", &responseData[7], 1); + println(""); - CemiFrame responseFrame(responseData, sizeof(responseData)); - responseFrame.messageCode(M_PropWrite_con); + CemiFrame responseFrame(responseData, sizeof(responseData)); + responseFrame.messageCode(M_PropWrite_con); #ifdef USE_USB - _usbTunnelInterface.sendCemiFrame(responseFrame); + _usbTunnelInterface.sendCemiFrame(responseFrame); #elif defined(KNX_TUNNELING) - _dataLinkLayerPrimary->dataRequestToTunnel(responseFrame); + _dataLinkLayerPrimary->dataRequestToTunnel(responseFrame); #endif + } } -} -void CemiServer::handleMReset(CemiFrame& frame) -{ - println("M_Reset_req: sending M_Reset_ind"); - // A real device reset does not work for USB or KNXNET/IP. - // Thus, M_Reset_ind is NOT mandatory for USB and KNXNET/IP. - // We just save all data to the EEPROM - _bau.writeMemory(); - // Prepare response - uint8_t responseData[1]; - CemiFrame responseFrame(responseData, sizeof(responseData)); - responseFrame.messageCode(M_Reset_ind); + void CemiServer::handleMReset(CemiFrame& frame) + { + println("M_Reset_req: sending M_Reset_ind"); + // A real device reset does not work for USB or KNXNET/IP. + // Thus, M_Reset_ind is NOT mandatory for USB and KNXNET/IP. + // We just save all data to the EEPROM + _bau.writeMemory(); + // Prepare response + uint8_t responseData[1]; + CemiFrame responseFrame(responseData, sizeof(responseData)); + responseFrame.messageCode(M_Reset_ind); #ifdef USE_USB - _usbTunnelInterface.sendCemiFrame(responseFrame); + _usbTunnelInterface.sendCemiFrame(responseFrame); #elif defined(KNX_TUNNELING) - _dataLinkLayerPrimary->dataRequestToTunnel(responseFrame); + _dataLinkLayerPrimary->dataRequestToTunnel(responseFrame); #endif -} + } -void CemiServer::loop() -{ + void CemiServer::loop() + { #ifdef USE_USB - _usbTunnelInterface.loop(); + _usbTunnelInterface.loop(); #endif -} + } +} \ No newline at end of file diff --git a/src/knx/cemi_server/cemi_server.h b/src/knx/cemi_server/cemi_server.h index 4551b1ce..a53286e3 100644 --- a/src/knx/cemi_server/cemi_server.h +++ b/src/knx/cemi_server/cemi_server.h @@ -4,56 +4,59 @@ #include "../knx_types.h" #include -class BauSystemB; -class DataLinkLayer; -class CemiFrame; - -/** - * This is an implementation of the cEMI server as specified in @cite knx:3/6/3. - * Overview on page 57. - * It provides methods for the BusAccessUnit to do different things and translates this - * call to an cEMI frame and calls the correct method of the data link layer. - * It also takes calls from data link layer, decodes the submitted cEMI frames and calls the corresponding - * methods of the BusAccessUnit class. - */ -class CemiServer +namespace Knx { - public: - /** - * The constructor. - * @param bau methods are called here depending of the content of the APDU - */ - CemiServer(BauSystemB& bau); - - void dataLinkLayer(DataLinkLayer& layer); - void dataLinkLayerPrimary(DataLinkLayer& layer); - - // from data link layer - // Only L_Data service - void dataIndicationToTunnel(CemiFrame& frame); - void dataConfirmationToTunnel(CemiFrame& frame); - - // From tunnel interface - void frameReceived(CemiFrame& frame); - - uint16_t clientAddress() const; - void clientAddress(uint16_t value); - - void loop(); - - private: - uint16_t _clientAddress = 0; - uint8_t _frameNumber = 0; - - void handleLData(CemiFrame& frame); - void handleMPropRead(CemiFrame& frame); - void handleMPropWrite(CemiFrame& frame); - void handleMReset(CemiFrame& frame); - - DataLinkLayer* _dataLinkLayer = nullptr; - DataLinkLayer* _dataLinkLayerPrimary = nullptr; - BauSystemB& _bau; -#ifdef USE_USB - UsbTunnelInterface _usbTunnelInterface; + class BauSystemB; + class DataLinkLayer; + class CemiFrame; + + /** + * This is an implementation of the cEMI server as specified in @cite knx:3/6/3. + * Overview on page 57. + * It provides methods for the BusAccessUnit to do different things and translates this + * call to an cEMI frame and calls the correct method of the data link layer. + * It also takes calls from data link layer, decodes the submitted cEMI frames and calls the corresponding + * methods of the BusAccessUnit class. + */ + class CemiServer + { + public: + /** + * The constructor. + * @param bau methods are called here depending of the content of the APDU + */ + CemiServer(BauSystemB& bau); + + void dataLinkLayer(DataLinkLayer& layer); + void dataLinkLayerPrimary(DataLinkLayer& layer); + + // from data link layer + // Only L_Data service + void dataIndicationToTunnel(CemiFrame& frame); + void dataConfirmationToTunnel(CemiFrame& frame); + + // From tunnel interface + void frameReceived(CemiFrame& frame); + + uint16_t clientAddress() const; + void clientAddress(uint16_t value); + + void loop(); + + private: + uint16_t _clientAddress = 0; + uint8_t _frameNumber = 0; + + void handleLData(CemiFrame& frame); + void handleMPropRead(CemiFrame& frame); + void handleMPropWrite(CemiFrame& frame); + void handleMReset(CemiFrame& frame); + + DataLinkLayer* _dataLinkLayer = nullptr; + DataLinkLayer* _dataLinkLayerPrimary = nullptr; + BauSystemB& _bau; +#ifdef USE_USB + UsbTunnelInterface _usbTunnelInterface; #endif -}; + }; +} \ No newline at end of file diff --git a/src/knx/cemi_server/cemi_server_object.cpp b/src/knx/cemi_server/cemi_server_object.cpp index e513e590..298b67c9 100644 --- a/src/knx/cemi_server/cemi_server_object.cpp +++ b/src/knx/cemi_server/cemi_server_object.cpp @@ -4,53 +4,56 @@ #include -CemiServerObject::CemiServerObject() +namespace Knx { - Property* properties[] = + CemiServerObject::CemiServerObject() { - new DataProperty( PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_CEMI_SERVER ), - new DataProperty( PID_MEDIUM_TYPE, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0, (uint16_t)0), - new DataProperty( PID_COMM_MODE, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint16_t)0), - new DataProperty( PID_COMM_MODES_SUPPORTED, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0, (uint16_t)0x100), - new DataProperty( PID_MEDIUM_AVAILABILITY, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0, (uint16_t)0), - // cEMI additional info types supported by this cEMI server: only 0x02 (RF Control Octet and Serial Number or DoA) - new DataProperty( PID_ADD_INFO_TYPES, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint8_t)0x02) - }; - initializeProperties(sizeof(properties), properties); -} - -void CemiServerObject::setMediumTypeAsSupported(DptMedium dptMedium) -{ - uint16_t mediaTypesSupported; - property(PID_MEDIUM_TYPE)->read(mediaTypesSupported); + Property* properties[] = + { + new DataProperty( PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_CEMI_SERVER ), + new DataProperty( PID_MEDIUM_TYPE, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0, (uint16_t)0), + new DataProperty( PID_COMM_MODE, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint16_t)0), + new DataProperty( PID_COMM_MODES_SUPPORTED, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0, (uint16_t)0x100), + new DataProperty( PID_MEDIUM_AVAILABILITY, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0, (uint16_t)0), + // cEMI additional info types supported by this cEMI server: only 0x02 (RF Control Octet and Serial Number or DoA) + new DataProperty( PID_ADD_INFO_TYPES, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint8_t)0x02) + }; + initializeProperties(sizeof(properties), properties); + } - switch (dptMedium) + void CemiServerObject::setMediumTypeAsSupported(DptMedium dptMedium) { - case DptMedium::KNX_IP: - mediaTypesSupported |= 1 << 1; - break; - - case DptMedium::KNX_RF: - mediaTypesSupported |= 1 << 4; - break; - - case DptMedium::KNX_TP1: - mediaTypesSupported |= 1 << 5; - break; - - case DptMedium::KNX_PL110: - mediaTypesSupported |= 1 << 2; - break; + uint16_t mediaTypesSupported; + property(PID_MEDIUM_TYPE)->read(mediaTypesSupported); + + switch (dptMedium) + { + case DptMedium::KNX_IP: + mediaTypesSupported |= 1 << 1; + break; + + case DptMedium::KNX_RF: + mediaTypesSupported |= 1 << 4; + break; + + case DptMedium::KNX_TP1: + mediaTypesSupported |= 1 << 5; + break; + + case DptMedium::KNX_PL110: + mediaTypesSupported |= 1 << 2; + break; + } + + property(PID_MEDIUM_TYPE)->write(mediaTypesSupported); + // We also set the medium as available too + property(PID_MEDIUM_AVAILABILITY)->write(mediaTypesSupported); } - property(PID_MEDIUM_TYPE)->write(mediaTypesSupported); - // We also set the medium as available too - property(PID_MEDIUM_AVAILABILITY)->write(mediaTypesSupported); -} - -void CemiServerObject::clearSupportedMediaTypes() -{ - property(PID_MEDIUM_TYPE)->write((uint16_t) 0); - // We also set the medium as not available too - property(PID_MEDIUM_AVAILABILITY)->write((uint16_t) 0); -} + void CemiServerObject::clearSupportedMediaTypes() + { + property(PID_MEDIUM_TYPE)->write((uint16_t) 0); + // We also set the medium as not available too + property(PID_MEDIUM_AVAILABILITY)->write((uint16_t) 0); + } +} \ No newline at end of file diff --git a/src/knx/cemi_server/cemi_server_object.h b/src/knx/cemi_server/cemi_server_object.h index 8049d0a2..e65836dc 100644 --- a/src/knx/cemi_server/cemi_server_object.h +++ b/src/knx/cemi_server/cemi_server_object.h @@ -2,11 +2,14 @@ #include "../interface_object/interface_object.h" -class CemiServerObject: public InterfaceObject +namespace Knx { - public: - CemiServerObject(); + class CemiServerObject: public InterfaceObject + { + public: + CemiServerObject(); - void setMediumTypeAsSupported(DptMedium dptMedium); - void clearSupportedMediaTypes(); -}; + void setMediumTypeAsSupported(DptMedium dptMedium); + void clearSupportedMediaTypes(); + }; +} \ No newline at end of file diff --git a/src/knx/cemi_server/usb_tunnel_interface.cpp b/src/knx/cemi_server/usb_tunnel_interface.cpp index dc004a38..08850fc4 100644 --- a/src/knx/cemi_server/usb_tunnel_interface.cpp +++ b/src/knx/cemi_server/usb_tunnel_interface.cpp @@ -27,6 +27,8 @@ extern bool sendHidReport(uint8_t* data, uint16_t length); extern bool isSendHidReportPossible(); +namespace Knx +{ // class UsbTunnelInterface @@ -557,3 +559,4 @@ uint16_t UsbTunnelInterface::getHidReportDescriptorLength() { return sizeof(descHidReport); } +} \ No newline at end of file diff --git a/src/knx/cemi_server/usb_tunnel_interface.h b/src/knx/cemi_server/usb_tunnel_interface.h index a8919dba..9047e2e9 100644 --- a/src/knx/cemi_server/usb_tunnel_interface.h +++ b/src/knx/cemi_server/usb_tunnel_interface.h @@ -2,92 +2,96 @@ #include -class CemiServer; -class CemiFrame; - -enum ProtocolIdType -{ - KnxTunneling = 0x01, - BusAccessServer = 0x0f -}; - -enum EmiIdType +namespace Knx { - EmiIdNotUsed = 0x00, - EMI1 = 0x01, - EMI2 = 0x02, - CEMI = 0x03 -}; -enum ServiceIdType -{ - ServiceIdNotUsed = 0x00, - DeviceFeatureGet = 0x01, - DeviceFeatureResponse = 0x02, - DeviceFeatureSet = 0x03, - DeviceFeatureInfo = 0x04, - DeviceFeatureEscape = 0xFF -}; - -enum FeatureIdType -{ - SupportedEmiType = 0x01, - HostDeviceDescriptorType0 = 0x02, - BusConnectionStatus = 0x03, - KnxManufacturerCode = 0x04, - ActiveEmiType = 0x05 -}; - -class UsbTunnelInterface -{ - public: - UsbTunnelInterface(CemiServer& cemiServer, uint16_t manufacturerId, uint16_t maskVersion); - - void loop(); - - // from cEMI server - void sendCemiFrame(CemiFrame& frame); - - static const uint8_t* getKnxHidReportDescriptor(); - static uint16_t getHidReportDescriptorLength(); - static void receiveHidReport(uint8_t const* data, uint16_t bufSize); - - private: - struct _queue_buffer_t - { - uint8_t* data; - uint16_t length; - _queue_buffer_t* next; - }; - - struct _queue_t - { - _queue_buffer_t* front = nullptr; - _queue_buffer_t* back = nullptr; - }; - - static const uint8_t descHidReport[]; - - CemiServer& _cemiServer; - - uint16_t _manufacturerId; - uint16_t _maskVersion; - - // USB TX queue - _queue_t _tx_queue; - void addBufferTxQueue(uint8_t* data, uint16_t length); - bool isTxQueueEmpty(); - void loadNextTxFrame(uint8_t** sendBuffer, uint16_t* sendBufferLength); - - // USB RX queue - static _queue_t _rx_queue; - static void addBufferRxQueue(const uint8_t* data, uint16_t length); - bool isRxQueueEmpty(); - void loadNextRxBuffer(uint8_t** receiveBuffer, uint16_t* receiveBufferLength); - static bool rxHaveCompletePacket; - - void handleTransferProtocolPacket(uint8_t* data, uint16_t length); - void handleHidReportRxQueue(); - void handleBusAccessServerProtocol(ServiceIdType servId, const uint8_t* requestData, uint16_t packetLength); - void sendKnxHidReport(ProtocolIdType protId, ServiceIdType servId, uint8_t* data, uint16_t length); -}; + class CemiServer; + class CemiFrame; + + enum ProtocolIdType + { + KnxTunneling = 0x01, + BusAccessServer = 0x0f + }; + + enum EmiIdType + { + EmiIdNotUsed = 0x00, + EMI1 = 0x01, + EMI2 = 0x02, + CEMI = 0x03 + }; + + enum ServiceIdType + { + ServiceIdNotUsed = 0x00, + DeviceFeatureGet = 0x01, + DeviceFeatureResponse = 0x02, + DeviceFeatureSet = 0x03, + DeviceFeatureInfo = 0x04, + DeviceFeatureEscape = 0xFF + }; + + enum FeatureIdType + { + SupportedEmiType = 0x01, + HostDeviceDescriptorType0 = 0x02, + BusConnectionStatus = 0x03, + KnxManufacturerCode = 0x04, + ActiveEmiType = 0x05 + }; + + class UsbTunnelInterface + { + public: + UsbTunnelInterface(CemiServer& cemiServer, uint16_t manufacturerId, uint16_t maskVersion); + + void loop(); + + // from cEMI server + void sendCemiFrame(CemiFrame& frame); + + static const uint8_t* getKnxHidReportDescriptor(); + static uint16_t getHidReportDescriptorLength(); + static void receiveHidReport(uint8_t const* data, uint16_t bufSize); + + private: + struct _queue_buffer_t + { + uint8_t* data; + uint16_t length; + _queue_buffer_t* next; + }; + + struct _queue_t + { + _queue_buffer_t* front = nullptr; + _queue_buffer_t* back = nullptr; + }; + + static const uint8_t descHidReport[]; + + CemiServer& _cemiServer; + + uint16_t _manufacturerId; + uint16_t _maskVersion; + + // USB TX queue + _queue_t _tx_queue; + void addBufferTxQueue(uint8_t* data, uint16_t length); + bool isTxQueueEmpty(); + void loadNextTxFrame(uint8_t** sendBuffer, uint16_t* sendBufferLength); + + // USB RX queue + static _queue_t _rx_queue; + static void addBufferRxQueue(const uint8_t* data, uint16_t length); + bool isRxQueueEmpty(); + void loadNextRxBuffer(uint8_t** receiveBuffer, uint16_t* receiveBufferLength); + static bool rxHaveCompletePacket; + + void handleTransferProtocolPacket(uint8_t* data, uint16_t length); + void handleHidReportRxQueue(); + void handleBusAccessServerProtocol(ServiceIdType servId, const uint8_t* requestData, uint16_t packetLength); + void sendKnxHidReport(ProtocolIdType protId, ServiceIdType servId, uint8_t* data, uint16_t length); + }; +} \ No newline at end of file diff --git a/src/knx/coupler/bau091A.cpp b/src/knx/coupler/bau091A.cpp index 15f1614b..59f168a7 100644 --- a/src/knx/coupler/bau091A.cpp +++ b/src/knx/coupler/bau091A.cpp @@ -11,244 +11,247 @@ Announce the line status of sec side 03_05_01 4.4.3 implement PID_COUPLER_SERVICES_CONTROL 03_05_01 4.4.7 */ -Bau091A::Bau091A(Platform& platform) - : BauSystemBCoupler(platform), DataLinkLayerCallbacks(), - _routerObj(memory(), 0x200, 0x2000), // the Filtertable of 0x091A IP Routers is fixed at 0x200 and 0x2000 long - _ipParameters(_deviceObj, platform), - _dlLayerPrimary(_deviceObj, _ipParameters, _netLayer.getPrimaryInterface(), _platform, (DataLinkLayerCallbacks*) this), - _dlLayerSecondary(_deviceObj, _netLayer.getSecondaryInterface(), platform, (ITpUartCallBacks&) * this, (DataLinkLayerCallbacks*) this) +namespace Knx +{ + Bau091A::Bau091A(Platform& platform) + : BauSystemBCoupler(platform), DataLinkLayerCallbacks(), + _routerObj(memory(), 0x200, 0x2000), // the Filtertable of 0x091A IP Routers is fixed at 0x200 and 0x2000 long + _ipParameters(_deviceObj, platform), + _dlLayerPrimary(_deviceObj, _ipParameters, _netLayer.getPrimaryInterface(), _platform, (DataLinkLayerCallbacks*) this), + _dlLayerSecondary(_deviceObj, _netLayer.getSecondaryInterface(), platform, (ITpUartCallBacks&) * this, (DataLinkLayerCallbacks*) this) #ifdef USE_CEMI_SERVER - , _cemiServer(*this) + , _cemiServer(*this) #endif -{ - // Before accessing anything of the router object they have to be initialized according to the used medium - // Coupler model 1.x - _routerObj.initialize1x(DptMedium::KNX_IP, 220); + { + // Before accessing anything of the router object they have to be initialized according to the used medium + // Coupler model 1.x + _routerObj.initialize1x(DptMedium::KNX_IP, 220); - // Mask 091A uses older coupler model 1.x which only uses one router object - _netLayer.rtObj(_routerObj); + // Mask 091A uses older coupler model 1.x which only uses one router object + _netLayer.rtObj(_routerObj); - _netLayer.getPrimaryInterface().dataLinkLayer(_dlLayerPrimary); - _netLayer.getSecondaryInterface().dataLinkLayer(_dlLayerSecondary); + _netLayer.getPrimaryInterface().dataLinkLayer(_dlLayerPrimary); + _netLayer.getSecondaryInterface().dataLinkLayer(_dlLayerSecondary); #ifdef USE_CEMI_SERVER - _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_IP); - _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_TP1); - _cemiServer.dataLinkLayerPrimary(_dlLayerPrimary); - _cemiServer.dataLinkLayer(_dlLayerSecondary); // Secondary I/F is the important one! - _dlLayerPrimary.cemiServer(_cemiServer); - _dlLayerSecondary.cemiServer(_cemiServer); - _memory.addSaveRestore(&_cemiServerObject); - uint8_t count = 1; - uint16_t suppCommModes = 0x0100; - _cemiServerObject.writeProperty(PID_COMM_MODES_SUPPORTED, 1, (uint8_t*)&suppCommModes, count); // set the properties Bit 0 to 1 meaning "LinkLayer supported" + _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_IP); + _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_TP1); + _cemiServer.dataLinkLayerPrimary(_dlLayerPrimary); + _cemiServer.dataLinkLayer(_dlLayerSecondary); // Secondary I/F is the important one! + _dlLayerPrimary.cemiServer(_cemiServer); + _dlLayerSecondary.cemiServer(_cemiServer); + _memory.addSaveRestore(&_cemiServerObject); + uint8_t count = 1; + uint16_t suppCommModes = 0x0100; + _cemiServerObject.writeProperty(PID_COMM_MODES_SUPPORTED, 1, (uint8_t*)&suppCommModes, count); // set the properties Bit 0 to 1 meaning "LinkLayer supported" #endif - _memory.addSaveRestore(&_routerObj); + _memory.addSaveRestore(&_routerObj); - _memory.addSaveRestore(&_ipParameters); + _memory.addSaveRestore(&_ipParameters); - // Set Mask Version in Device Object depending on the BAU - _deviceObj.maskVersion(0x091A); + // Set Mask Version in Device Object depending on the BAU + _deviceObj.maskVersion(0x091A); - // Set which interface objects are available in the device object - // This differs from BAU to BAU with different medium types. - // See PID_IO_LIST - Property* prop = _deviceObj.property(PID_IO_LIST); - prop->write(1, (uint16_t) OT_DEVICE); - prop->write(2, (uint16_t) OT_ROUTER); - prop->write(3, (uint16_t) OT_APPLICATION_PROG); - prop->write(4, (uint16_t) OT_IP_PARAMETER); + // Set which interface objects are available in the device object + // This differs from BAU to BAU with different medium types. + // See PID_IO_LIST + Property* prop = _deviceObj.property(PID_IO_LIST); + prop->write(1, (uint16_t) OT_DEVICE); + prop->write(2, (uint16_t) OT_ROUTER); + prop->write(3, (uint16_t) OT_APPLICATION_PROG); + prop->write(4, (uint16_t) OT_IP_PARAMETER); #if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER) - prop->write(5, (uint16_t) OT_SECURITY); - prop->write(6, (uint16_t) OT_CEMI_SERVER); + prop->write(5, (uint16_t) OT_SECURITY); + prop->write(6, (uint16_t) OT_CEMI_SERVER); #elif defined(USE_DATASECURE) - prop->write(5, (uint16_t) OT_SECURITY); + prop->write(5, (uint16_t) OT_SECURITY); #elif defined(USE_CEMI_SERVER) - prop->write(5, (uint16_t) OT_CEMI_SERVER); + prop->write(5, (uint16_t) OT_CEMI_SERVER); #endif -} + } -InterfaceObject* Bau091A::getInterfaceObject(uint8_t idx) -{ - switch (idx) + InterfaceObject* Bau091A::getInterfaceObject(uint8_t idx) { - case 0: - return &_deviceObj; + switch (idx) + { + case 0: + return &_deviceObj; - case 1: - return &_routerObj; + case 1: + return &_routerObj; - case 2: - return &_appProgram; + case 2: + return &_appProgram; - case 3: - return &_ipParameters; + case 3: + return &_ipParameters; #if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER) - case 4: - return &_secIfObj; + case 4: + return &_secIfObj; - case 5: - return &_cemiServerObject; + case 5: + return &_cemiServerObject; #elif defined(USE_CEMI_SERVER) - case 4: - return &_cemiServerObject; + case 4: + return &_cemiServerObject; #elif defined(USE_DATASECURE) - case 4: - return &_secIfObj; + case 4: + return &_secIfObj; #endif - default: - return nullptr; + default: + return nullptr; + } } -} - -InterfaceObject* Bau091A::getInterfaceObject(ObjectType objectType, uint16_t objectInstance) -{ - // We do not use it right now. - // Required for coupler mode as there are multiple router objects for example - (void) objectInstance; - switch (objectType) + InterfaceObject* Bau091A::getInterfaceObject(ObjectType objectType, uint16_t objectInstance) { - case OT_DEVICE: - return &_deviceObj; + // We do not use it right now. + // Required for coupler mode as there are multiple router objects for example + (void) objectInstance; + + switch (objectType) + { + case OT_DEVICE: + return &_deviceObj; - case OT_ROUTER: - return &_routerObj; + case OT_ROUTER: + return &_routerObj; - case OT_APPLICATION_PROG: - return &_appProgram; + case OT_APPLICATION_PROG: + return &_appProgram; - case OT_IP_PARAMETER: - return &_ipParameters; + case OT_IP_PARAMETER: + return &_ipParameters; #ifdef USE_DATASECURE - case OT_SECURITY: - return &_secIfObj; + case OT_SECURITY: + return &_secIfObj; #endif #ifdef USE_CEMI_SERVER - case OT_CEMI_SERVER: - return &_cemiServerObject; + case OT_CEMI_SERVER: + return &_cemiServerObject; #endif - default: - return nullptr; + default: + return nullptr; + } } -} -void Bau091A::doMasterReset(EraseCode eraseCode, uint8_t channel) -{ - // Common SystemB objects - BauSystemBCoupler::doMasterReset(eraseCode, channel); + void Bau091A::doMasterReset(EraseCode eraseCode, uint8_t channel) + { + // Common SystemB objects + BauSystemBCoupler::doMasterReset(eraseCode, channel); - _ipParameters.masterReset(eraseCode, channel); - _routerObj.masterReset(eraseCode, channel); -} + _ipParameters.masterReset(eraseCode, channel); + _routerObj.masterReset(eraseCode, channel); + } -bool Bau091A::enabled() -{ - return _dlLayerPrimary.enabled() && _dlLayerSecondary.enabled(); -} + bool Bau091A::enabled() + { + return _dlLayerPrimary.enabled() && _dlLayerSecondary.enabled(); + } -void Bau091A::enabled(bool value) -{ - _dlLayerPrimary.enabled(value); - _dlLayerSecondary.enabled(value); + void Bau091A::enabled(bool value) + { + _dlLayerPrimary.enabled(value); + _dlLayerSecondary.enabled(value); - // ToDo change frame repitition in the TP layer - but default is ok. - //_dlLayerSecondary.setFrameRepetition(3,3); -} + // ToDo change frame repitition in the TP layer - but default is ok. + //_dlLayerSecondary.setFrameRepetition(3,3); + } -void Bau091A::loop() -{ - _dlLayerPrimary.loop(); - _dlLayerSecondary.loop(); - BauSystemBCoupler::loop(); -} + void Bau091A::loop() + { + _dlLayerPrimary.loop(); + _dlLayerSecondary.loop(); + BauSystemBCoupler::loop(); + } -TPAckType Bau091A::isAckRequired(uint16_t address, bool isGrpAddr) -{ - //only called from TpUartDataLinkLayer - TPAckType ack = TPAckType::AckReqNone; + TPAckType Bau091A::isAckRequired(uint16_t address, bool isGrpAddr) + { + //only called from TpUartDataLinkLayer + TPAckType ack = TPAckType::AckReqNone; - uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible. - Property* prop_lcconfig = _routerObj.property(PID_SUB_LCCONFIG); + uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible. + Property* prop_lcconfig = _routerObj.property(PID_SUB_LCCONFIG); - if (lcconfig) - prop_lcconfig->read(lcconfig); + if (lcconfig) + prop_lcconfig->read(lcconfig); - if (isGrpAddr) - { - // ACK for broadcasts - if (address == 0) - ack = TPAckType::AckReqAck; + if (isGrpAddr) + { + // ACK for broadcasts + if (address == 0) + ack = TPAckType::AckReqAck; - if (lcconfig & LCCONFIG::GROUP_IACK_ROUT) + if (lcconfig & LCCONFIG::GROUP_IACK_ROUT) - // is group address in filter table? ACK if yes, No if not - if (_netLayer.isRoutedGroupAddress(address, 1)) - ack = TPAckType::AckReqAck; + // is group address in filter table? ACK if yes, No if not + if (_netLayer.isRoutedGroupAddress(address, 1)) + ack = TPAckType::AckReqAck; + else + ack = TPAckType::AckReqNone; else - ack = TPAckType::AckReqNone; - else - // all are ACKED - ack = TPAckType::AckReqAck; + // all are ACKED + ack = TPAckType::AckReqAck; #ifdef KNX_TUNNELING - if (_dlLayerPrimary.isSentToTunnel(address, isGrpAddr)) - ack = TPAckType::AckReqAck; + if (_dlLayerPrimary.isSentToTunnel(address, isGrpAddr)) + ack = TPAckType::AckReqAck; #endif - } - else - { - if ((lcconfig & LCCONFIG::PHYS_IACK) == LCCONFIG::PHYS_IACK_ALL) - ack = TPAckType::AckReqAck; - else if ((lcconfig & LCCONFIG::PHYS_IACK) == LCCONFIG::PHYS_IACK_NACK) - ack = TPAckType::AckReqNack; - else if (_netLayer.isRoutedIndividualAddress(address, 1) || address == _deviceObj.individualAddress()) // Also ACK for our own individual address - ack = TPAckType::AckReqAck; + } else - ack = TPAckType::AckReqNone; + { + if ((lcconfig & LCCONFIG::PHYS_IACK) == LCCONFIG::PHYS_IACK_ALL) + ack = TPAckType::AckReqAck; + else if ((lcconfig & LCCONFIG::PHYS_IACK) == LCCONFIG::PHYS_IACK_NACK) + ack = TPAckType::AckReqNack; + else if (_netLayer.isRoutedIndividualAddress(address, 1) || address == _deviceObj.individualAddress()) // Also ACK for our own individual address + ack = TPAckType::AckReqAck; + else + ack = TPAckType::AckReqNone; #ifdef KNX_TUNNELING - if (_dlLayerPrimary.isSentToTunnel(address, isGrpAddr)) - ack = TPAckType::AckReqAck; + if (_dlLayerPrimary.isSentToTunnel(address, isGrpAddr)) + ack = TPAckType::AckReqAck; #endif - } + } - return ack; -} + return ack; + } -bool Bau091A::configured() -{ - // _configured is set to true initially, if the device was configured with ETS it will be set to true after restart + bool Bau091A::configured() + { + // _configured is set to true initially, if the device was configured with ETS it will be set to true after restart - if (!_configured) - return false; + if (!_configured) + return false; - _configured = _routerObj.loadState() == LS_LOADED; + _configured = _routerObj.loadState() == LS_LOADED; #ifdef USE_DATASECURE - _configured &= _secIfObj.loadState() == LS_LOADED; + _configured &= _secIfObj.loadState() == LS_LOADED; #endif - return _configured; -} + return _configured; + } -IpDataLinkLayer* Bau091A::getPrimaryDataLinkLayer() -{ - return (IpDataLinkLayer*)&_dlLayerPrimary; -} + IpDataLinkLayer* Bau091A::getPrimaryDataLinkLayer() + { + return (IpDataLinkLayer*)&_dlLayerPrimary; + } -TpUartDataLinkLayer* Bau091A::getSecondaryDataLinkLayer() -{ - return (TpUartDataLinkLayer*)&_dlLayerSecondary; + TpUartDataLinkLayer* Bau091A::getSecondaryDataLinkLayer() + { + return (TpUartDataLinkLayer*)&_dlLayerSecondary; + } } \ No newline at end of file diff --git a/src/knx/coupler/bau091A.h b/src/knx/coupler/bau091A.h index c9ddc0d4..975872d3 100644 --- a/src/knx/coupler/bau091A.h +++ b/src/knx/coupler/bau091A.h @@ -8,32 +8,36 @@ #include "../tp/tpuart_data_link_layer.h" #include "../cemi_server/cemi_server_object.h" -class Bau091A : public BauSystemBCoupler, public ITpUartCallBacks, public DataLinkLayerCallbacks + +namespace Knx { - public: - Bau091A(Platform& platform); - void loop() override; - bool enabled() override; - void enabled(bool value) override; - bool configured() override; + class Bau091A : public BauSystemBCoupler, public ITpUartCallBacks, public DataLinkLayerCallbacks + { + public: + Bau091A(Platform& platform); + void loop() override; + bool enabled() override; + void enabled(bool value) override; + bool configured() override; - IpDataLinkLayer* getPrimaryDataLinkLayer(); - TpUartDataLinkLayer* getSecondaryDataLinkLayer(); - protected: - InterfaceObject* getInterfaceObject(uint8_t idx); - InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance); + IpDataLinkLayer* getPrimaryDataLinkLayer(); + TpUartDataLinkLayer* getSecondaryDataLinkLayer(); + protected: + InterfaceObject* getInterfaceObject(uint8_t idx); + InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance); - // For TP1 only - TPAckType isAckRequired(uint16_t address, bool isGrpAddr) override; + // For TP1 only + TPAckType isAckRequired(uint16_t address, bool isGrpAddr) override; - void doMasterReset(EraseCode eraseCode, uint8_t channel) override; - private: - RouterObject _routerObj; - IpParameterObject _ipParameters; - IpDataLinkLayer _dlLayerPrimary; - TpUartDataLinkLayer _dlLayerSecondary; + void doMasterReset(EraseCode eraseCode, uint8_t channel) override; + private: + RouterObject _routerObj; + IpParameterObject _ipParameters; + IpDataLinkLayer _dlLayerPrimary; + TpUartDataLinkLayer _dlLayerSecondary; #ifdef USE_CEMI_SERVER - CemiServer _cemiServer; - CemiServerObject _cemiServerObject; + CemiServer _cemiServer; + CemiServerObject _cemiServerObject; #endif -}; + }; +} \ No newline at end of file diff --git a/src/knx/coupler/bau2920.cpp b/src/knx/coupler/bau2920.cpp index 0a3b2a68..e15fb86d 100644 --- a/src/knx/coupler/bau2920.cpp +++ b/src/knx/coupler/bau2920.cpp @@ -7,173 +7,176 @@ using namespace std; -// Mask 0x2920 uses coupler model 2.0 -Bau2920::Bau2920(Platform& platform) - : BauSystemBCoupler(platform), - _rtObjPrimary(memory()), - _rtObjSecondary(memory()), - _rfMediumObject(), - _dlLayerPrimary(_deviceObj, _netLayer.getPrimaryInterface(), _platform, (ITpUartCallBacks&) * this), - _dlLayerSecondary(_deviceObj, _rfMediumObject, _netLayer.getSecondaryInterface(), platform) +namespace Knx +{ + // Mask 0x2920 uses coupler model 2.0 + Bau2920::Bau2920(Platform& platform) + : BauSystemBCoupler(platform), + _rtObjPrimary(memory()), + _rtObjSecondary(memory()), + _rfMediumObject(), + _dlLayerPrimary(_deviceObj, _netLayer.getPrimaryInterface(), _platform, (ITpUartCallBacks&) * this), + _dlLayerSecondary(_deviceObj, _rfMediumObject, _netLayer.getSecondaryInterface(), platform) #ifdef USE_CEMI_SERVER - , - _cemiServer(*this) + , + _cemiServer(*this) #endif -{ - // Before accessing anything of the two router objects they have to be initialized according to the used media combination - // Coupler model 2.0 - _rtObjPrimary.initialize20(1, DptMedium::KNX_TP1, RouterObjectType::Primary, 201); - _rtObjSecondary.initialize20(2, DptMedium::KNX_RF, RouterObjectType::Secondary, 201); + { + // Before accessing anything of the two router objects they have to be initialized according to the used media combination + // Coupler model 2.0 + _rtObjPrimary.initialize20(1, DptMedium::KNX_TP1, RouterObjectType::Primary, 201); + _rtObjSecondary.initialize20(2, DptMedium::KNX_RF, RouterObjectType::Secondary, 201); - _netLayer.rtObjPrimary(_rtObjPrimary); - _netLayer.rtObjSecondary(_rtObjSecondary); - _netLayer.getPrimaryInterface().dataLinkLayer(_dlLayerPrimary); - _netLayer.getSecondaryInterface().dataLinkLayer(_dlLayerSecondary); + _netLayer.rtObjPrimary(_rtObjPrimary); + _netLayer.rtObjSecondary(_rtObjSecondary); + _netLayer.getPrimaryInterface().dataLinkLayer(_dlLayerPrimary); + _netLayer.getSecondaryInterface().dataLinkLayer(_dlLayerSecondary); #ifdef USE_CEMI_SERVER - _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_TP1); - _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_RF); - _cemiServer.dataLinkLayer(_dlLayerSecondary); // Secondary I/F is the important one! - _dlLayerSecondary.cemiServer(_cemiServer); - _memory.addSaveRestore(&_cemiServerObject); + _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_TP1); + _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_RF); + _cemiServer.dataLinkLayer(_dlLayerSecondary); // Secondary I/F is the important one! + _dlLayerSecondary.cemiServer(_cemiServer); + _memory.addSaveRestore(&_cemiServerObject); #endif - _memory.addSaveRestore(&_rtObjPrimary); - _memory.addSaveRestore(&_rtObjSecondary); + _memory.addSaveRestore(&_rtObjPrimary); + _memory.addSaveRestore(&_rtObjSecondary); - _memory.addSaveRestore(&_rfMediumObject); + _memory.addSaveRestore(&_rfMediumObject); - // Set Mask Version in Device Object depending on the BAU - _deviceObj.maskVersion(0x2920); + // Set Mask Version in Device Object depending on the BAU + _deviceObj.maskVersion(0x2920); - // Set which interface objects are available in the device object - // This differs from BAU to BAU with different medium types. - // See PID_IO_LIST - Property* prop = _deviceObj.property(PID_IO_LIST); - prop->write(1, (uint16_t) OT_DEVICE); - prop->write(2, (uint16_t) OT_ROUTER); - prop->write(3, (uint16_t) OT_ROUTER); - prop->write(4, (uint16_t) OT_APPLICATION_PROG); - prop->write(5, (uint16_t) OT_RF_MEDIUM); + // Set which interface objects are available in the device object + // This differs from BAU to BAU with different medium types. + // See PID_IO_LIST + Property* prop = _deviceObj.property(PID_IO_LIST); + prop->write(1, (uint16_t) OT_DEVICE); + prop->write(2, (uint16_t) OT_ROUTER); + prop->write(3, (uint16_t) OT_ROUTER); + prop->write(4, (uint16_t) OT_APPLICATION_PROG); + prop->write(5, (uint16_t) OT_RF_MEDIUM); #if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER) - prop->write(6, (uint16_t) OT_SECURITY); - prop->write(7, (uint16_t) OT_CEMI_SERVER); + prop->write(6, (uint16_t) OT_SECURITY); + prop->write(7, (uint16_t) OT_CEMI_SERVER); #elif defined(USE_DATASECURE) - prop->write(6, (uint16_t) OT_SECURITY); + prop->write(6, (uint16_t) OT_SECURITY); #elif defined(USE_CEMI_SERVER) - prop->write(6, (uint16_t) OT_CEMI_SERVER); + prop->write(6, (uint16_t) OT_CEMI_SERVER); #endif -} + } -InterfaceObject* Bau2920::getInterfaceObject(uint8_t idx) -{ - switch (idx) + InterfaceObject* Bau2920::getInterfaceObject(uint8_t idx) { - case 0: - return &_deviceObj; + switch (idx) + { + case 0: + return &_deviceObj; - case 1: - return &_rtObjPrimary; + case 1: + return &_rtObjPrimary; - case 2: - return &_rtObjSecondary; + case 2: + return &_rtObjSecondary; - case 3: - return &_appProgram; + case 3: + return &_appProgram; - case 4: - return &_rfMediumObject; + case 4: + return &_rfMediumObject; #if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER) - case 5: - return &_secIfObj; + case 5: + return &_secIfObj; - case 6: - return &_cemiServerObject; + case 6: + return &_cemiServerObject; #elif defined(USE_CEMI_SERVER) - case 5: - return &_cemiServerObject; + case 5: + return &_cemiServerObject; #elif defined(USE_DATASECURE) - case 5: - return &_secIfObj; + case 5: + return &_secIfObj; #endif - default: - return nullptr; + default: + return nullptr; + } } -} - -InterfaceObject* Bau2920::getInterfaceObject(ObjectType objectType, uint16_t objectInstance) -{ - // We do not use it right now. - // Required for coupler mode as there are multiple router objects for example - (void) objectInstance; - switch (objectType) + InterfaceObject* Bau2920::getInterfaceObject(ObjectType objectType, uint16_t objectInstance) { - case OT_DEVICE: - return &_deviceObj; + // We do not use it right now. + // Required for coupler mode as there are multiple router objects for example + (void) objectInstance; - case OT_ROUTER: - return objectInstance == 0 ? &_rtObjPrimary : &_rtObjSecondary; + switch (objectType) + { + case OT_DEVICE: + return &_deviceObj; - case OT_APPLICATION_PROG: - return &_appProgram; + case OT_ROUTER: + return objectInstance == 0 ? &_rtObjPrimary : &_rtObjSecondary; - case OT_RF_MEDIUM: - return &_rfMediumObject; + case OT_APPLICATION_PROG: + return &_appProgram; + + case OT_RF_MEDIUM: + return &_rfMediumObject; #ifdef USE_DATASECURE - case OT_SECURITY: - return &_secIfObj; + case OT_SECURITY: + return &_secIfObj; #endif #ifdef USE_CEMI_SERVER - case OT_CEMI_SERVER: - return &_cemiServerObject; + case OT_CEMI_SERVER: + return &_cemiServerObject; #endif - default: - return nullptr; + default: + return nullptr; + } } -} -void Bau2920::doMasterReset(EraseCode eraseCode, uint8_t channel) -{ - // Common SystemB objects - BauSystemBCoupler::doMasterReset(eraseCode, channel); + void Bau2920::doMasterReset(EraseCode eraseCode, uint8_t channel) + { + // Common SystemB objects + BauSystemBCoupler::doMasterReset(eraseCode, channel); - _rfMediumObject.masterReset(eraseCode, channel); - _rtObjPrimary.masterReset(eraseCode, channel); - _rtObjSecondary.masterReset(eraseCode, channel); -} + _rfMediumObject.masterReset(eraseCode, channel); + _rtObjPrimary.masterReset(eraseCode, channel); + _rtObjSecondary.masterReset(eraseCode, channel); + } -bool Bau2920::enabled() -{ - return _dlLayerPrimary.enabled() && _dlLayerSecondary.enabled(); -} + bool Bau2920::enabled() + { + return _dlLayerPrimary.enabled() && _dlLayerSecondary.enabled(); + } -void Bau2920::enabled(bool value) -{ - _dlLayerPrimary.enabled(value); - _dlLayerSecondary.enabled(value); -} + void Bau2920::enabled(bool value) + { + _dlLayerPrimary.enabled(value); + _dlLayerSecondary.enabled(value); + } -void Bau2920::loop() -{ - _dlLayerPrimary.loop(); - _dlLayerSecondary.loop(); - BauSystemBCoupler::loop(); -} + void Bau2920::loop() + { + _dlLayerPrimary.loop(); + _dlLayerSecondary.loop(); + BauSystemBCoupler::loop(); + } -TpUartDataLinkLayer* Bau2920::getPrimaryDataLinkLayer() -{ - return (TpUartDataLinkLayer*)&_dlLayerPrimary; -} + TpUartDataLinkLayer* Bau2920::getPrimaryDataLinkLayer() + { + return (TpUartDataLinkLayer*)&_dlLayerPrimary; + } -RfDataLinkLayer* Bau2920::getSecondaryDataLinkLayer() -{ - return (RfDataLinkLayer*)&_dlLayerSecondary; + RfDataLinkLayer* Bau2920::getSecondaryDataLinkLayer() + { + return (RfDataLinkLayer*)&_dlLayerSecondary; + } } \ No newline at end of file diff --git a/src/knx/coupler/bau2920.h b/src/knx/coupler/bau2920.h index 15c3bc42..844deac3 100644 --- a/src/knx/coupler/bau2920.h +++ b/src/knx/coupler/bau2920.h @@ -13,29 +13,32 @@ #include "../rf/rf_medium_object.h" #include "../cemi_server/cemi_server_object.h" -class Bau2920 : public BauSystemBCoupler +namespace Knx { - public: - Bau2920(Platform& platform); - void loop() override; - bool enabled() override; - void enabled(bool value) override; + class Bau2920 : public BauSystemBCoupler + { + public: + Bau2920(Platform& platform); + void loop() override; + bool enabled() override; + void enabled(bool value) override; - TpUartDataLinkLayer* getPrimaryDataLinkLayer(); - RfDataLinkLayer* getSecondaryDataLinkLayer(); - protected: - InterfaceObject* getInterfaceObject(uint8_t idx); - InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance); + TpUartDataLinkLayer* getPrimaryDataLinkLayer(); + RfDataLinkLayer* getSecondaryDataLinkLayer(); + protected: + InterfaceObject* getInterfaceObject(uint8_t idx); + InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance); - void doMasterReset(EraseCode eraseCode, uint8_t channel) override; - private: - RouterObject _rtObjPrimary; - RouterObject _rtObjSecondary; - RfMediumObject _rfMediumObject; - TpUartDataLinkLayer _dlLayerPrimary; - RfDataLinkLayer _dlLayerSecondary; + void doMasterReset(EraseCode eraseCode, uint8_t channel) override; + private: + RouterObject _rtObjPrimary; + RouterObject _rtObjSecondary; + RfMediumObject _rfMediumObject; + TpUartDataLinkLayer _dlLayerPrimary; + RfDataLinkLayer _dlLayerSecondary; #ifdef USE_CEMI_SERVER - CemiServer _cemiServer; - CemiServerObject _cemiServerObject; + CemiServer _cemiServer; + CemiServerObject _cemiServerObject; #endif -}; + }; +} \ No newline at end of file diff --git a/src/knx/coupler/bau_systemB_coupler.cpp b/src/knx/coupler/bau_systemB_coupler.cpp index b06ca2fa..9a4c3b4b 100644 --- a/src/knx/coupler/bau_systemB_coupler.cpp +++ b/src/knx/coupler/bau_systemB_coupler.cpp @@ -5,58 +5,61 @@ #include #include -BauSystemBCoupler::BauSystemBCoupler(Platform& platform) : - BauSystemB(platform), - _platform(platform), +namespace Knx +{ + BauSystemBCoupler::BauSystemBCoupler(Platform& platform) : + BauSystemB(platform), + _platform(platform), #ifdef USE_DATASECURE - _appLayer(_deviceObj, _secIfObj, *this), + _appLayer(_deviceObj, _secIfObj, *this), #else - _appLayer(*this), + _appLayer(*this), #endif - _transLayer(_appLayer), - _netLayer(_deviceObj, _transLayer) -{ - _appLayer.transportLayer(_transLayer); - _transLayer.networkLayer(_netLayer); - _memory.addSaveRestore(&_deviceObj); + _transLayer(_appLayer), + _netLayer(_deviceObj, _transLayer) + { + _appLayer.transportLayer(_transLayer); + _transLayer.networkLayer(_netLayer); + _memory.addSaveRestore(&_deviceObj); #ifdef USE_DATASECURE - _memory.addSaveRestore(&_secIfObj); + _memory.addSaveRestore(&_secIfObj); #endif -} + } -ApplicationLayer& BauSystemBCoupler::applicationLayer() -{ - return _appLayer; -} + ApplicationLayer& BauSystemBCoupler::applicationLayer() + { + return _appLayer; + } -void BauSystemBCoupler::loop() -{ - _transLayer.loop(); + void BauSystemBCoupler::loop() + { + _transLayer.loop(); #ifdef USE_DATASECURE - _appLayer.loop(); + _appLayer.loop(); #endif -} + } -bool BauSystemBCoupler::configured() -{ - // _configured is set to true initially, if the device was configured with ETS it will be set to true after restart + bool BauSystemBCoupler::configured() + { + // _configured is set to true initially, if the device was configured with ETS it will be set to true after restart - if (!_configured) - return false; + if (!_configured) + return false; - _configured = _appProgram.loadState() == LS_LOADED; + _configured = _appProgram.loadState() == LS_LOADED; #ifdef USE_DATASECURE - _configured &= _secIfObj.loadState() == LS_LOADED; + _configured &= _secIfObj.loadState() == LS_LOADED; #endif - return _configured; -} + return _configured; + } -void BauSystemBCoupler::doMasterReset(EraseCode eraseCode, uint8_t channel) -{ - BauSystemB::doMasterReset(eraseCode, channel); + void BauSystemBCoupler::doMasterReset(EraseCode eraseCode, uint8_t channel) + { + BauSystemB::doMasterReset(eraseCode, channel); #ifdef USE_DATASECURE - _secIfObj.masterReset(eraseCode, channel); + _secIfObj.masterReset(eraseCode, channel); #endif -} + } +} \ No newline at end of file diff --git a/src/knx/coupler/bau_systemB_coupler.h b/src/knx/coupler/bau_systemB_coupler.h index 0aa68aa7..497d4b35 100644 --- a/src/knx/coupler/bau_systemB_coupler.h +++ b/src/knx/coupler/bau_systemB_coupler.h @@ -15,27 +15,30 @@ #include "../platform/platform.h" #include "../util/memory.h" -class BauSystemBCoupler : public BauSystemB +namespace Knx { - public: - BauSystemBCoupler(Platform& platform); - void loop() override; - bool configured() override; + class BauSystemBCoupler : public BauSystemB + { + public: + BauSystemBCoupler(Platform& platform); + void loop() override; + bool configured() override; - protected: - ApplicationLayer& applicationLayer() override; + protected: + ApplicationLayer& applicationLayer() override; - void doMasterReset(EraseCode eraseCode, uint8_t channel) override; + void doMasterReset(EraseCode eraseCode, uint8_t channel) override; - Platform& _platform; + Platform& _platform; #ifdef USE_DATASECURE - SecureApplicationLayer _appLayer; - SecurityInterfaceObject _secIfObj; + SecureApplicationLayer _appLayer; + SecurityInterfaceObject _secIfObj; #else - ApplicationLayer _appLayer; + ApplicationLayer _appLayer; #endif - TransportLayer _transLayer; - NetworkLayerCoupler _netLayer; - bool _configured = true; -}; + TransportLayer _transLayer; + NetworkLayerCoupler _netLayer; + bool _configured = true; + }; +} \ No newline at end of file diff --git a/src/knx/coupler/network_layer_coupler.cpp b/src/knx/coupler/network_layer_coupler.cpp index 743d4b7b..6ed4b23d 100644 --- a/src/knx/coupler/network_layer_coupler.cpp +++ b/src/knx/coupler/network_layer_coupler.cpp @@ -6,651 +6,654 @@ #include "../datalink_layer/data_link_layer.h" #include "../bits.h" -NetworkLayerCoupler::NetworkLayerCoupler(DeviceObject& deviceObj, - TransportLayer& layer) : - NetworkLayer(deviceObj, layer), - _netLayerEntities { {*this, kPrimaryIfIndex}, {*this, kSecondaryIfIndex} } +namespace Knx { - _currentAddress = deviceObj.individualAddress(); - evaluateCouplerType(); -} + NetworkLayerCoupler::NetworkLayerCoupler(DeviceObject& deviceObj, + TransportLayer& layer) : + NetworkLayer(deviceObj, layer), + _netLayerEntities { {*this, kPrimaryIfIndex}, {*this, kSecondaryIfIndex} } + { + _currentAddress = deviceObj.individualAddress(); + evaluateCouplerType(); + } -NetworkLayerEntity& NetworkLayerCoupler::getPrimaryInterface() -{ - return _netLayerEntities[0]; -} + NetworkLayerEntity& NetworkLayerCoupler::getPrimaryInterface() + { + return _netLayerEntities[0]; + } -NetworkLayerEntity& NetworkLayerCoupler::getSecondaryInterface() -{ - return _netLayerEntities[1]; -} + NetworkLayerEntity& NetworkLayerCoupler::getSecondaryInterface() + { + return _netLayerEntities[1]; + } -void NetworkLayerCoupler::rtObj(RouterObject& rtObj) -{ - _rtObjPrimary = &rtObj; - _rtObjSecondary = nullptr; -} + void NetworkLayerCoupler::rtObj(RouterObject& rtObj) + { + _rtObjPrimary = &rtObj; + _rtObjSecondary = nullptr; + } -void NetworkLayerCoupler::rtObjPrimary(RouterObject& rtObjPrimary) -{ - _rtObjPrimary = &rtObjPrimary; -} + void NetworkLayerCoupler::rtObjPrimary(RouterObject& rtObjPrimary) + { + _rtObjPrimary = &rtObjPrimary; + } -void NetworkLayerCoupler::rtObjSecondary(RouterObject& rtObjSecondary) -{ - _rtObjSecondary = &rtObjSecondary; -} + void NetworkLayerCoupler::rtObjSecondary(RouterObject& rtObjSecondary) + { + _rtObjSecondary = &rtObjSecondary; + } -void NetworkLayerCoupler::evaluateCouplerType() -{ - // Check coupler mode - if ((_deviceObj.individualAddress() & 0x00FF) == 0x00) + void NetworkLayerCoupler::evaluateCouplerType() { - // Device is a router - // Check if line coupler or backbone coupler - if ((_deviceObj.individualAddress() & 0x0F00) == 0x0) + // Check coupler mode + if ((_deviceObj.individualAddress() & 0x00FF) == 0x00) { - // Device is a backbone coupler -> individual address: x.0.0 - _couplerType = BackboneCoupler; + // Device is a router + // Check if line coupler or backbone coupler + if ((_deviceObj.individualAddress() & 0x0F00) == 0x0) + { + // Device is a backbone coupler -> individual address: x.0.0 + _couplerType = BackboneCoupler; + } + else + { + // Device is a line coupler -> individual address: x.y.0 + _couplerType = LineCoupler; + } } else { - // Device is a line coupler -> individual address: x.y.0 - _couplerType = LineCoupler; + // Device is not a router, check if TP1 bridge or TP1 repeater + /* + if (PID_L2_COUPLER_TYPE.BIT0 == 0) + { + //then Device is TP1 Bridge + couplerType = TP1Bridge; + } + else + { + // Device is TP1 Repeater + couplerType = TP1Repeater; + } + */ } } - else - { - // Device is not a router, check if TP1 bridge or TP1 repeater - /* - if (PID_L2_COUPLER_TYPE.BIT0 == 0) - { - //then Device is TP1 Bridge - couplerType = TP1Bridge; - } - else - { - // Device is TP1 Repeater - couplerType = TP1Repeater; - } - */ - } -} -bool NetworkLayerCoupler::isGroupAddressInFilterTable(uint16_t groupAddress) -{ - if (_rtObjSecondary == nullptr) - return (_rtObjPrimary != nullptr) ? _rtObjPrimary->isGroupAddressInFilterTable(groupAddress) : false; - else + bool NetworkLayerCoupler::isGroupAddressInFilterTable(uint16_t groupAddress) { - return _rtObjSecondary->isGroupAddressInFilterTable(groupAddress); + if (_rtObjSecondary == nullptr) + return (_rtObjPrimary != nullptr) ? _rtObjPrimary->isGroupAddressInFilterTable(groupAddress) : false; + else + { + return _rtObjSecondary->isGroupAddressInFilterTable(groupAddress); + } } -} -bool NetworkLayerCoupler::isRoutedGroupAddress(uint16_t groupAddress, uint8_t sourceInterfaceIndex) -{ - uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible. - uint8_t lcgrpconfig = LCGRPCONFIG::GROUP_6FFFROUTE | LCGRPCONFIG::GROUP_7000UNLOCK | LCGRPCONFIG::GROUP_REPEAT; // default value from spec. in case prop is not availible. - Property* prop_lcgrpconfig; - Property* prop_lcconfig; - - if (sourceInterfaceIndex == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP) - { - prop_lcgrpconfig = _rtObjPrimary->property(PID_MAIN_LCGRPCONFIG); - prop_lcconfig = _rtObjPrimary->property(PID_MAIN_LCCONFIG); - } - else // direction Sec -> Prim ( e.g. TP -> IP) + bool NetworkLayerCoupler::isRoutedGroupAddress(uint16_t groupAddress, uint8_t sourceInterfaceIndex) { - prop_lcgrpconfig = _rtObjPrimary->property(PID_SUB_LCGRPCONFIG); - prop_lcconfig = _rtObjPrimary->property(PID_SUB_LCCONFIG); - } + uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible. + uint8_t lcgrpconfig = LCGRPCONFIG::GROUP_6FFFROUTE | LCGRPCONFIG::GROUP_7000UNLOCK | LCGRPCONFIG::GROUP_REPEAT; // default value from spec. in case prop is not availible. + Property* prop_lcgrpconfig; + Property* prop_lcconfig; + + if (sourceInterfaceIndex == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP) + { + prop_lcgrpconfig = _rtObjPrimary->property(PID_MAIN_LCGRPCONFIG); + prop_lcconfig = _rtObjPrimary->property(PID_MAIN_LCCONFIG); + } + else // direction Sec -> Prim ( e.g. TP -> IP) + { + prop_lcgrpconfig = _rtObjPrimary->property(PID_SUB_LCGRPCONFIG); + prop_lcconfig = _rtObjPrimary->property(PID_SUB_LCCONFIG); + } - if (prop_lcgrpconfig) - prop_lcgrpconfig->read(lcgrpconfig); + if (prop_lcgrpconfig) + prop_lcgrpconfig->read(lcgrpconfig); - if (prop_lcconfig) - prop_lcconfig->read(lcconfig); + if (prop_lcconfig) + prop_lcconfig->read(lcconfig); - if (groupAddress < 0x7000) // Main group 0-13 - { - // PID_SUB_LCGRPCONFIG Bit 0-1 - switch (lcgrpconfig & LCGRPCONFIG::GROUP_6FFF) + if (groupAddress < 0x7000) // Main group 0-13 { - case LCGRPCONFIG::GROUP_6FFFLOCK: - //printHex("1drop frame to 0x", (uint8_t*)destination, 2); - return false;//drop - break; - - case LCGRPCONFIG::GROUP_6FFFROUTE: - if (isGroupAddressInFilterTable(groupAddress)) - ;//send - else - { - //printHex("2drop frame to 0x", (uint8_t*)destination, 2); + // PID_SUB_LCGRPCONFIG Bit 0-1 + switch (lcgrpconfig & LCGRPCONFIG::GROUP_6FFF) + { + case LCGRPCONFIG::GROUP_6FFFLOCK: + //printHex("1drop frame to 0x", (uint8_t*)destination, 2); return false;//drop - } + break; - break; + case LCGRPCONFIG::GROUP_6FFFROUTE: + if (isGroupAddressInFilterTable(groupAddress)) + ;//send + else + { + //printHex("2drop frame to 0x", (uint8_t*)destination, 2); + return false;//drop + } - default: // LCGRPCONFIG::GROUP_6FFFUNLOCK - ;//send - } - } - else // Main group 14-31 - { - // PID_SUB_LCGRPCONFIG Bit 2-3 LCGRPCONFIG::GROUP_7000 - switch (lcgrpconfig & LCGRPCONFIG::GROUP_7000) - { - case LCGRPCONFIG::GROUP_7000LOCK: - //printHex("3drop frame to 0x", (uint8_t*)destination, 2); - return false;//drop - break; + break; - case LCGRPCONFIG::GROUP_7000ROUTE: - if (isGroupAddressInFilterTable(groupAddress)) + default: // LCGRPCONFIG::GROUP_6FFFUNLOCK ;//send - else - { - //printHex("4drop frame to 0x", (uint8_t*)destination, 2); + } + } + else // Main group 14-31 + { + // PID_SUB_LCGRPCONFIG Bit 2-3 LCGRPCONFIG::GROUP_7000 + switch (lcgrpconfig & LCGRPCONFIG::GROUP_7000) + { + case LCGRPCONFIG::GROUP_7000LOCK: + //printHex("3drop frame to 0x", (uint8_t*)destination, 2); return false;//drop - } + break; - break; + case LCGRPCONFIG::GROUP_7000ROUTE: + if (isGroupAddressInFilterTable(groupAddress)) + ;//send + else + { + //printHex("4drop frame to 0x", (uint8_t*)destination, 2); + return false;//drop + } - default: // LCGRPCONFIG::GROUP_7000UNLOCK - ;//send - } - } + break; - return true; -} + default: // LCGRPCONFIG::GROUP_7000UNLOCK + ;//send + } + } -bool NetworkLayerCoupler::isRoutedIndividualAddress(uint16_t individualAddress, uint8_t srcIfIndex) -{ - // TODO: improve: we have to be notified about anything that might affect routing decision - // Ugly: we could ALWAYS evaluate coupler type for every received frame - if (_currentAddress != _deviceObj.individualAddress()) - { - evaluateCouplerType(); + return true; } - // See KNX spec.: Network Layer (03/03/03) and AN161 (Coupler model 2.0) - /* - * C hop count value contained in the N-protocol header - * D low order octet of the Destination Address, i.e. Device Address part - * G Group Address - * SD low nibble of high order octet plus low order octet, i.e. Line Address + Device Address - * Z high nibble of high order octet of the Destination Address, i.e. Area Address - * ZS high order octet of the Destination Address, i.e. hierarchy information part: Area Address + Line Address - */ - uint16_t ownSNA = _deviceObj.individualAddress() & 0xFF00; // Own subnetwork address (area + line) - uint16_t ownAA = _deviceObj.individualAddress() & 0xF000; // Own area address - uint16_t ZS = individualAddress & 0xFF00; // destination subnetwork address (area + line) - uint16_t Z = individualAddress & 0xF000; // destination area address - - - if (_couplerType == LineCoupler) + bool NetworkLayerCoupler::isRoutedIndividualAddress(uint16_t individualAddress, uint8_t srcIfIndex) { - // Main line to sub line routing - if (srcIfIndex == kPrimaryIfIndex) + // TODO: improve: we have to be notified about anything that might affect routing decision + // Ugly: we could ALWAYS evaluate coupler type for every received frame + if (_currentAddress != _deviceObj.individualAddress()) { - if (ZS != ownSNA) - { - // IGNORE_TOTALLY - return false; - } - - return true; + evaluateCouplerType(); } - else if (srcIfIndex == kSecondaryIfIndex) // Sub line to main line routing + + // See KNX spec.: Network Layer (03/03/03) and AN161 (Coupler model 2.0) + /* + * C hop count value contained in the N-protocol header + * D low order octet of the Destination Address, i.e. Device Address part + * G Group Address + * SD low nibble of high order octet plus low order octet, i.e. Line Address + Device Address + * Z high nibble of high order octet of the Destination Address, i.e. Area Address + * ZS high order octet of the Destination Address, i.e. hierarchy information part: Area Address + Line Address + */ + uint16_t ownSNA = _deviceObj.individualAddress() & 0xFF00; // Own subnetwork address (area + line) + uint16_t ownAA = _deviceObj.individualAddress() & 0xF000; // Own area address + uint16_t ZS = individualAddress & 0xFF00; // destination subnetwork address (area + line) + uint16_t Z = individualAddress & 0xF000; // destination area address + + + if (_couplerType == LineCoupler) { - if (ZS != ownSNA) + // Main line to sub line routing + if (srcIfIndex == kPrimaryIfIndex) { - // ROUTE_XXX + if (ZS != ownSNA) + { + // IGNORE_TOTALLY + return false; + } + return true; } - else + else if (srcIfIndex == kSecondaryIfIndex) // Sub line to main line routing { - return false; + if (ZS != ownSNA) + { + // ROUTE_XXX + return true; + } + else + { + return false; + } } - } - else - { - //not from primiary not from sec if, should not happen - return false; - } - } - else if (_couplerType == BackboneCoupler) - { - // Backbone line to main line routing - if (srcIfIndex == kPrimaryIfIndex) - { - if (Z != ownAA) + else { + //not from primiary not from sec if, should not happen return false; } - - return true; } - else if (srcIfIndex == kSecondaryIfIndex) // Main line to backbone line routing + else if (_couplerType == BackboneCoupler) { - if (Z != ownAA) + // Backbone line to main line routing + if (srcIfIndex == kPrimaryIfIndex) { + if (Z != ownAA) + { + return false; + } + return true; } + else if (srcIfIndex == kSecondaryIfIndex) // Main line to backbone line routing + { + if (Z != ownAA) + { + return true; + } + else + { + return false; + } + } else { + //not from primiary not from sec if, should not happen return false; } } else { - //not from primiary not from sec if, should not happen + //unknown coupler type, should not happen return false; } } - else - { - //unknown coupler type, should not happen - return false; - } -} - -void NetworkLayerCoupler::sendMsgHopCount(AckType ack, AddressType addrType, uint16_t destination, NPDU& npdu, Priority priority, - SystemBroadcast broadcastType, uint8_t sourceInterfaceIndex, uint16_t source) -{ - uint8_t interfaceIndex = (sourceInterfaceIndex == kSecondaryIfIndex) ? kPrimaryIfIndex : kSecondaryIfIndex; - - uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible. - uint8_t lcgrpconfig = LCGRPCONFIG::GROUP_6FFFROUTE | LCGRPCONFIG::GROUP_7000UNLOCK | LCGRPCONFIG::GROUP_REPEAT; // default value from spec. in case prop is not availible. - Property* prop_lcgrpconfig; - Property* prop_lcconfig; - if (sourceInterfaceIndex == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP) + void NetworkLayerCoupler::sendMsgHopCount(AckType ack, AddressType addrType, uint16_t destination, NPDU& npdu, Priority priority, + SystemBroadcast broadcastType, uint8_t sourceInterfaceIndex, uint16_t source) { - prop_lcgrpconfig = _rtObjPrimary->property(PID_MAIN_LCGRPCONFIG); - prop_lcconfig = _rtObjPrimary->property(PID_MAIN_LCCONFIG); - } - else // direction Sec -> Prim ( e.g. TP -> IP) - { - prop_lcgrpconfig = _rtObjPrimary->property(PID_SUB_LCGRPCONFIG); - prop_lcconfig = _rtObjPrimary->property(PID_SUB_LCCONFIG); - } + uint8_t interfaceIndex = (sourceInterfaceIndex == kSecondaryIfIndex) ? kPrimaryIfIndex : kSecondaryIfIndex; - if (prop_lcgrpconfig) - prop_lcgrpconfig->read(lcgrpconfig); + uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible. + uint8_t lcgrpconfig = LCGRPCONFIG::GROUP_6FFFROUTE | LCGRPCONFIG::GROUP_7000UNLOCK | LCGRPCONFIG::GROUP_REPEAT; // default value from spec. in case prop is not availible. + Property* prop_lcgrpconfig; + Property* prop_lcconfig; - if (prop_lcconfig) - prop_lcconfig->read(lcconfig); + if (sourceInterfaceIndex == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP) + { + prop_lcgrpconfig = _rtObjPrimary->property(PID_MAIN_LCGRPCONFIG); + prop_lcconfig = _rtObjPrimary->property(PID_MAIN_LCCONFIG); + } + else // direction Sec -> Prim ( e.g. TP -> IP) + { + prop_lcgrpconfig = _rtObjPrimary->property(PID_SUB_LCGRPCONFIG); + prop_lcconfig = _rtObjPrimary->property(PID_SUB_LCCONFIG); + } + if (prop_lcgrpconfig) + prop_lcgrpconfig->read(lcgrpconfig); - if (addrType == AddressType::GroupAddress && destination != 0) // destination == 0 means broadcast and must not be filtered with the GroupAddresses - { - if (!isRoutedGroupAddress(destination, sourceInterfaceIndex)) - return; // drop; - } + if (prop_lcconfig) + prop_lcconfig->read(lcconfig); - // If we have a frame from open medium on secondary side (e.g. RF) to primary side, then shall use the hop count of the primary router object - if ((_rtObjPrimary != nullptr) && (_rtObjSecondary != nullptr) && (sourceInterfaceIndex == kSecondaryIfIndex)) - { - DptMedium mediumType = getSecondaryInterface().mediumType(); + if (addrType == AddressType::GroupAddress && destination != 0) // destination == 0 means broadcast and must not be filtered with the GroupAddresses + { + if (!isRoutedGroupAddress(destination, sourceInterfaceIndex)) + return; // drop; + } - if (mediumType == DptMedium::KNX_RF) // Probably also KNX_PL110, but this is not specified, PL110 is also an open medium + + // If we have a frame from open medium on secondary side (e.g. RF) to primary side, then shall use the hop count of the primary router object + if ((_rtObjPrimary != nullptr) && (_rtObjSecondary != nullptr) && (sourceInterfaceIndex == kSecondaryIfIndex)) { - uint16_t hopCount = 0; + DptMedium mediumType = getSecondaryInterface().mediumType(); - if (_rtObjPrimary->property(PID_HOP_COUNT)->read(hopCount) == 1) + if (mediumType == DptMedium::KNX_RF) // Probably also KNX_PL110, but this is not specified, PL110 is also an open medium { - npdu.hopCount(hopCount); + uint16_t hopCount = 0; + + if (_rtObjPrimary->property(PID_HOP_COUNT)->read(hopCount) == 1) + { + npdu.hopCount(hopCount); + } } } - } - else // Normal hopCount between main and sub line and vice versa - { - if (npdu.hopCount() == 0) + else // Normal hopCount between main and sub line and vice versa { - // IGNORE_ACKED - return; - } + if (npdu.hopCount() == 0) + { + // IGNORE_ACKED + return; + } - if (npdu.hopCount() < 7) - { - // ROUTE_DECREMENTED - npdu.hopCount(npdu.hopCount() - 1); - } - else if (npdu.hopCount() == 7) - { - // ROUTE_UNMODIFIED + if (npdu.hopCount() < 7) + { + // ROUTE_DECREMENTED + npdu.hopCount(npdu.hopCount() - 1); + } + else if (npdu.hopCount() == 7) + { + // ROUTE_UNMODIFIED + } } - } - // Use other interface + // Use other interface #ifdef KNX_LOG_COUPLER - if (sourceInterfaceIndex == 0) - print("Routing from P->S: "); - else - print("Routing from S->P: "); + if (sourceInterfaceIndex == 0) + print("Routing from P->S: "); + else + print("Routing from S->P: "); - print(source, HEX); - print(" -> "); - print(destination, HEX); - print(" - "); - npdu.frame().apdu().printPDU(); + print(source, HEX); + print(" -> "); + print(destination, HEX); + print(" - "); + npdu.frame().apdu().printPDU(); #endif - //evaluiate PHYS_REPEAT, BROADCAST_REPEAT and GROUP_REPEAT - bool doNotRepeat = false; - - if ((addrType == AddressType::GroupAddress && !(lcgrpconfig & LCGRPCONFIG::GROUP_REPEAT)) || - (addrType == AddressType::IndividualAddress && !(lcconfig & LCCONFIG::PHYS_REPEAT)) || - (addrType == AddressType::GroupAddress && destination == 0 && !(lcconfig & LCCONFIG::BROADCAST_REPEAT))) - doNotRepeat = true; + //evaluiate PHYS_REPEAT, BROADCAST_REPEAT and GROUP_REPEAT + bool doNotRepeat = false; - _netLayerEntities[interfaceIndex].sendDataRequest(npdu, ack, destination, source, priority, addrType, broadcastType, doNotRepeat); -} + if ((addrType == AddressType::GroupAddress && !(lcgrpconfig & LCGRPCONFIG::GROUP_REPEAT)) || + (addrType == AddressType::IndividualAddress && !(lcconfig & LCCONFIG::PHYS_REPEAT)) || + (addrType == AddressType::GroupAddress && destination == 0 && !(lcconfig & LCCONFIG::BROADCAST_REPEAT))) + doNotRepeat = true; -// TODO: for later: improve by putting routing algorithms in its own class/functions and only instantiate required algorithm (line vs. coupler) -// TODO: we could also do the sanity checks here, i.e. check if sourceAddress is really coming in from correct srcIfIdx, etc. (see PID_COUPL_SERV_CONTROL: EN_SNA_INCONSISTENCY_CHECK) -void NetworkLayerCoupler::routeDataIndividual(AckType ack, uint16_t destination, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIndex) -{ - //print("NetworkLayerCoupler::routeDataIndividual dest 0x"); - //print(destination, HEX); - //print(" own addr 0x"); - //println(_deviceObj.individualAddress(), HEX); - - if (destination == _deviceObj.individualAddress()) - { - // FORWARD_LOCALLY - //println("NetworkLayerCoupler::routeDataIndividual locally"); - HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; - _transportLayer.dataIndividualIndication(destination, hopType, priority, source, npdu.tpdu()); - return; + _netLayerEntities[interfaceIndex].sendDataRequest(npdu, ack, destination, source, priority, addrType, broadcastType, doNotRepeat); } - // Local to main or sub line - if (srcIfIndex == kLocalIfIndex) + // TODO: for later: improve by putting routing algorithms in its own class/functions and only instantiate required algorithm (line vs. coupler) + // TODO: we could also do the sanity checks here, i.e. check if sourceAddress is really coming in from correct srcIfIdx, etc. (see PID_COUPL_SERV_CONTROL: EN_SNA_INCONSISTENCY_CHECK) + void NetworkLayerCoupler::routeDataIndividual(AckType ack, uint16_t destination, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIndex) { - uint16_t netaddr; - uint16_t Z; + //print("NetworkLayerCoupler::routeDataIndividual dest 0x"); + //print(destination, HEX); + //print(" own addr 0x"); + //println(_deviceObj.individualAddress(), HEX); - if (_couplerType == CouplerType::BackboneCoupler) - { - netaddr = _deviceObj.individualAddress() & 0xF000; - Z = destination & 0xF000; - } - else if (_couplerType == CouplerType::LineCoupler) + if (destination == _deviceObj.individualAddress()) { - netaddr = _deviceObj.individualAddress() & 0xFF00; - Z = destination & 0xFF00; + // FORWARD_LOCALLY + //println("NetworkLayerCoupler::routeDataIndividual locally"); + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + _transportLayer.dataIndividualIndication(destination, hopType, priority, source, npdu.tpdu()); + return; } - else + + // Local to main or sub line + if (srcIfIndex == kLocalIfIndex) { - //unknown coupler type, should not happen - return ; - } + uint16_t netaddr; + uint16_t Z; + + if (_couplerType == CouplerType::BackboneCoupler) + { + netaddr = _deviceObj.individualAddress() & 0xF000; + Z = destination & 0xF000; + } + else if (_couplerType == CouplerType::LineCoupler) + { + netaddr = _deviceObj.individualAddress() & 0xFF00; + Z = destination & 0xFF00; + } + else + { + //unknown coupler type, should not happen + return ; + } - // if destination is not within our scope then send via primary interface, else via secondary interface - uint8_t destIfidx = (Z != netaddr) ? kPrimaryIfIndex : kSecondaryIfIndex; + // if destination is not within our scope then send via primary interface, else via secondary interface + uint8_t destIfidx = (Z != netaddr) ? kPrimaryIfIndex : kSecondaryIfIndex; #ifdef KNX_TUNNELING - if (destIfidx == kPrimaryIfIndex) - if (isTunnelAddress(destination)) - destIfidx = kSecondaryIfIndex; + if (destIfidx == kPrimaryIfIndex) + if (isTunnelAddress(destination)) + destIfidx = kSecondaryIfIndex; #endif - //print("NetworkLayerCoupler::routeDataIndividual local to s or p: "); - //println(destIfidx); - _netLayerEntities[destIfidx].sendDataRequest(npdu, ack, destination, source, priority, AddressType::IndividualAddress, Broadcast); - return; - } + //print("NetworkLayerCoupler::routeDataIndividual local to s or p: "); + //println(destIfidx); + _netLayerEntities[destIfidx].sendDataRequest(npdu, ack, destination, source, priority, AddressType::IndividualAddress, Broadcast); + return; + } - uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible. - Property* prop_lcconfig; + uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible. + Property* prop_lcconfig; - if (srcIfIndex == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP) - prop_lcconfig = _rtObjPrimary->property(PID_MAIN_LCCONFIG); - else // direction Sec -> Prim ( e.g. TP -> IP) - prop_lcconfig = _rtObjPrimary->property(PID_SUB_LCCONFIG); + if (srcIfIndex == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP) + prop_lcconfig = _rtObjPrimary->property(PID_MAIN_LCCONFIG); + else // direction Sec -> Prim ( e.g. TP -> IP) + prop_lcconfig = _rtObjPrimary->property(PID_SUB_LCCONFIG); - if (prop_lcconfig) - prop_lcconfig->read(lcconfig); + if (prop_lcconfig) + prop_lcconfig->read(lcconfig); - if ((lcconfig & LCCONFIG::PHYS_FRAME) == LCCONFIG::PHYS_FRAME_LOCK) - { - // IGNORE_TOTALLY - //println("NetworkLayerCoupler::routeDataIndividual locked"); - return; - } - else if ((lcconfig & LCCONFIG::PHYS_FRAME) == LCCONFIG::PHYS_FRAME_UNLOCK) - { - // ROUTE_XXX - //println("NetworkLayerCoupler::routeDataIndividual unlocked"); - sendMsgHopCount(ack, AddressType::IndividualAddress, destination, npdu, priority, Broadcast, srcIfIndex, source); - return; - } - else // LCCONFIG::PHYS_FRAME_ROUTE or 0 - { - if (isRoutedIndividualAddress(destination, srcIfIndex)) + if ((lcconfig & LCCONFIG::PHYS_FRAME) == LCCONFIG::PHYS_FRAME_LOCK) { - //println("NetworkLayerCoupler::routeDataIndividual routed"); - sendMsgHopCount(ack, AddressType::IndividualAddress, destination, npdu, priority, Broadcast, srcIfIndex, source); // ROUTE_XXX + // IGNORE_TOTALLY + //println("NetworkLayerCoupler::routeDataIndividual locked"); + return; } - else + else if ((lcconfig & LCCONFIG::PHYS_FRAME) == LCCONFIG::PHYS_FRAME_UNLOCK) { - //println("NetworkLayerCoupler::routeDataIndividual not routed"); - ; // IGNORE_TOTALLY + // ROUTE_XXX + //println("NetworkLayerCoupler::routeDataIndividual unlocked"); + sendMsgHopCount(ack, AddressType::IndividualAddress, destination, npdu, priority, Broadcast, srcIfIndex, source); + return; + } + else // LCCONFIG::PHYS_FRAME_ROUTE or 0 + { + if (isRoutedIndividualAddress(destination, srcIfIndex)) + { + //println("NetworkLayerCoupler::routeDataIndividual routed"); + sendMsgHopCount(ack, AddressType::IndividualAddress, destination, npdu, priority, Broadcast, srcIfIndex, source); // ROUTE_XXX + } + else + { + //println("NetworkLayerCoupler::routeDataIndividual not routed"); + ; // IGNORE_TOTALLY + } } } -} - -void NetworkLayerCoupler::dataIndication(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) -{ - // routing for individual addresses - if (addrType == IndividualAddress) - { - //printHex("NetworkLayerCoupler::dataIndication to IA ", (uint8_t*)&destination, 2); - //npdu.frame().valid(); - routeDataIndividual(ack, destination, npdu, priority, source, srcIfIdx); - return; - } - - //printHex("NetworkLayerCoupler::dataIndication to GA ", (uint8_t*)&destination, 2); - // routing for group addresses - // TODO: check new AN189 - // "AN189 only makes that group messages with hop count 7 cannot bypass the Filter Table unfiltered, - // what made the Security Proxy(AN192) useless; now, hc 7 Telegrams are filtered as any other and the value is decremented. - // ROUTE_XXX - sendMsgHopCount(ack, addrType, destination, npdu, priority, Broadcast, srcIfIdx, source); - return; -} - -void NetworkLayerCoupler::dataConfirm(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) -{ - //println("NetworkLayerCoupler::dataConfirm"); - HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; - - // Check if received frame is an echo from our sent frame, we are a normal device in this case - if (source == _deviceObj.individualAddress()) + void NetworkLayerCoupler::dataIndication(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) { + // routing for individual addresses if (addrType == IndividualAddress) { - _transportLayer.dataIndividualConfirm(ack, destination, hopType, priority, npdu.tpdu(), status); + //printHex("NetworkLayerCoupler::dataIndication to IA ", (uint8_t*)&destination, 2); + //npdu.frame().valid(); + routeDataIndividual(ack, destination, npdu, priority, source, srcIfIdx); return; } - // else: we do not have any local group communication, so do not handle this - } + //printHex("NetworkLayerCoupler::dataIndication to GA ", (uint8_t*)&destination, 2); + // routing for group addresses + // TODO: check new AN189 + // "AN189 only makes that group messages with hop count 7 cannot bypass the Filter Table unfiltered, + // what made the Security Proxy(AN192) useless; now, hc 7 Telegrams are filtered as any other and the value is decremented. - // Do not process the frame any further if it was a routed frame sent from network layer -} + // ROUTE_XXX + sendMsgHopCount(ack, addrType, destination, npdu, priority, Broadcast, srcIfIdx, source); + return; + } -void NetworkLayerCoupler::broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) -{ - // Send it to our local stack first + void NetworkLayerCoupler::dataConfirm(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) { + //println("NetworkLayerCoupler::dataConfirm"); HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; - DptMedium mediumType = _netLayerEntities[srcIfIdx].mediumType(); - // for closed media like TP1 and IP - if ( ((mediumType == DptMedium::KNX_TP1) || (mediumType == DptMedium::KNX_IP)) && - isApciSystemBroadcast(npdu.tpdu().apdu())) + // Check if received frame is an echo from our sent frame, we are a normal device in this case + if (source == _deviceObj.individualAddress()) { - npdu.frame().systemBroadcast(SysBroadcast); - _transportLayer.dataSystemBroadcastIndication(hopType, priority, source, npdu.tpdu()); - return; + if (addrType == IndividualAddress) + { + _transportLayer.dataIndividualConfirm(ack, destination, hopType, priority, npdu.tpdu(), status); + return; + } + + // else: we do not have any local group communication, so do not handle this } - _transportLayer.dataBroadcastIndication(hopType, priority, source, npdu.tpdu()); + // Do not process the frame any further if it was a routed frame sent from network layer } - uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible. - Property* prop_lcconfig; + void NetworkLayerCoupler::broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) + { + // Send it to our local stack first + { + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + DptMedium mediumType = _netLayerEntities[srcIfIdx].mediumType(); + + // for closed media like TP1 and IP + if ( ((mediumType == DptMedium::KNX_TP1) || (mediumType == DptMedium::KNX_IP)) && + isApciSystemBroadcast(npdu.tpdu().apdu())) + { + npdu.frame().systemBroadcast(SysBroadcast); + _transportLayer.dataSystemBroadcastIndication(hopType, priority, source, npdu.tpdu()); + return; + } - if (srcIfIdx == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP) - prop_lcconfig = _rtObjPrimary->property(PID_MAIN_LCCONFIG); - else // direction Sec -> Prim ( e.g. TP -> IP) - prop_lcconfig = _rtObjPrimary->property(PID_SUB_LCCONFIG); + _transportLayer.dataBroadcastIndication(hopType, priority, source, npdu.tpdu()); + } - if (prop_lcconfig) - prop_lcconfig->read(lcconfig); + uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible. + Property* prop_lcconfig; - // Route to other interface - if (!(lcconfig & LCCONFIG::BROADCAST_LOCK)) - sendMsgHopCount(ack, GroupAddress, 0, npdu, priority, Broadcast, srcIfIdx, source); -} + if (srcIfIdx == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP) + prop_lcconfig = _rtObjPrimary->property(PID_MAIN_LCCONFIG); + else // direction Sec -> Prim ( e.g. TP -> IP) + prop_lcconfig = _rtObjPrimary->property(PID_SUB_LCCONFIG); -void NetworkLayerCoupler::broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) -{ - HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + if (prop_lcconfig) + prop_lcconfig->read(lcconfig); - // Check if received frame is an echo from our sent frame, we are a normal device in this case - if (source == _deviceObj.individualAddress()) - { - _transportLayer.dataBroadcastConfirm(ack, hopType, priority, npdu.tpdu(), status); + // Route to other interface + if (!(lcconfig & LCCONFIG::BROADCAST_LOCK)) + sendMsgHopCount(ack, GroupAddress, 0, npdu, priority, Broadcast, srcIfIdx, source); } - // Do not process the frame any further -} - -void NetworkLayerCoupler::systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) -{ - // Send it to our local stack first + void NetworkLayerCoupler::broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) { HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; - _transportLayer.dataSystemBroadcastIndication(hopType, priority, source, npdu.tpdu()); + + // Check if received frame is an echo from our sent frame, we are a normal device in this case + if (source == _deviceObj.individualAddress()) + { + _transportLayer.dataBroadcastConfirm(ack, hopType, priority, npdu.tpdu(), status); + } + + // Do not process the frame any further } - uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible. - Property* prop_lcconfig; + void NetworkLayerCoupler::systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) + { + // Send it to our local stack first + { + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + _transportLayer.dataSystemBroadcastIndication(hopType, priority, source, npdu.tpdu()); + } + + uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible. + Property* prop_lcconfig; - if (srcIfIdx == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP) - prop_lcconfig = _rtObjPrimary->property(PID_MAIN_LCCONFIG); - else // direction Sec -> Prim ( e.g. TP -> IP) - prop_lcconfig = _rtObjPrimary->property(PID_SUB_LCCONFIG); + if (srcIfIdx == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP) + prop_lcconfig = _rtObjPrimary->property(PID_MAIN_LCCONFIG); + else // direction Sec -> Prim ( e.g. TP -> IP) + prop_lcconfig = _rtObjPrimary->property(PID_SUB_LCCONFIG); - if (prop_lcconfig) - prop_lcconfig->read(lcconfig); + if (prop_lcconfig) + prop_lcconfig->read(lcconfig); - // Route to other interface - if (!(lcconfig & LCCONFIG::BROADCAST_LOCK)) - sendMsgHopCount(ack, GroupAddress, 0, npdu, priority, SysBroadcast, srcIfIdx, source); -} + // Route to other interface + if (!(lcconfig & LCCONFIG::BROADCAST_LOCK)) + sendMsgHopCount(ack, GroupAddress, 0, npdu, priority, SysBroadcast, srcIfIdx, source); + } -void NetworkLayerCoupler::systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) -{ - // Check if received frame is an echo from our sent frame, we are a normal device in this case - if (source == _deviceObj.individualAddress()) + void NetworkLayerCoupler::systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) { - HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; - _transportLayer.dataSystemBroadcastConfirm(ack, hopType, npdu.tpdu(), priority, status); - } + // Check if received frame is an echo from our sent frame, we are a normal device in this case + if (source == _deviceObj.individualAddress()) + { + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + _transportLayer.dataSystemBroadcastConfirm(ack, hopType, npdu.tpdu(), priority, status); + } - // Do not process the frame any further -} + // Do not process the frame any further + } -void NetworkLayerCoupler::dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) -{ - NPDU& npdu = tpdu.frame().npdu(); - - if (hopType == UnlimitedRouting) - npdu.hopCount(7); - else - npdu.hopCount(hopCount()); - - //if (tpdu.apdu().length() > 0) - //{ - // print.print("-> NL "); - // tpdu.apdu().printPDU(); - //} - routeDataIndividual(ack, destination, npdu, priority, _deviceObj.individualAddress(), kLocalIfIndex); -} - -void NetworkLayerCoupler::dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) -{ - NPDU& npdu = tpdu.frame().npdu(); + void NetworkLayerCoupler::dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) + { + NPDU& npdu = tpdu.frame().npdu(); - if (hopType == UnlimitedRouting) - npdu.hopCount(7); - else - npdu.hopCount(hopCount()); + if (hopType == UnlimitedRouting) + npdu.hopCount(7); + else + npdu.hopCount(hopCount()); + + //if (tpdu.apdu().length() > 0) + //{ + // print.print("-> NL "); + // tpdu.apdu().printPDU(); + //} + routeDataIndividual(ack, destination, npdu, priority, _deviceObj.individualAddress(), kLocalIfIndex); + } - // If the group address is in the filter table, then we route it to the primary side too - if (isGroupAddressInFilterTable(destination)) + void NetworkLayerCoupler::dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) { - _netLayerEntities[kPrimaryIfIndex].sendDataRequest(npdu, ack, destination, _deviceObj.individualAddress(), priority, GroupAddress, Broadcast); - } + NPDU& npdu = tpdu.frame().npdu(); - // We send it to our sub line in any case - _netLayerEntities[kSecondaryIfIndex].sendDataRequest(npdu, ack, destination, _deviceObj.individualAddress(), priority, GroupAddress, Broadcast); -} + if (hopType == UnlimitedRouting) + npdu.hopCount(7); + else + npdu.hopCount(hopCount()); -void NetworkLayerCoupler::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) -{ - NPDU& npdu = tpdu.frame().npdu(); + // If the group address is in the filter table, then we route it to the primary side too + if (isGroupAddressInFilterTable(destination)) + { + _netLayerEntities[kPrimaryIfIndex].sendDataRequest(npdu, ack, destination, _deviceObj.individualAddress(), priority, GroupAddress, Broadcast); + } + + // We send it to our sub line in any case + _netLayerEntities[kSecondaryIfIndex].sendDataRequest(npdu, ack, destination, _deviceObj.individualAddress(), priority, GroupAddress, Broadcast); + } - if (hopType == UnlimitedRouting) - npdu.hopCount(7); - else - npdu.hopCount(hopCount()); + void NetworkLayerCoupler::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) + { + NPDU& npdu = tpdu.frame().npdu(); - CemiFrame tmpFrame(tpdu.frame()); + if (hopType == UnlimitedRouting) + npdu.hopCount(7); + else + npdu.hopCount(hopCount()); - _netLayerEntities[kPrimaryIfIndex].sendDataRequest(npdu, ack, 0, _deviceObj.individualAddress(), priority, GroupAddress, Broadcast); - _netLayerEntities[kSecondaryIfIndex].sendDataRequest(tmpFrame.npdu(), ack, 0, _deviceObj.individualAddress(), priority, GroupAddress, Broadcast); -} + CemiFrame tmpFrame(tpdu.frame()); -void NetworkLayerCoupler::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) -{ - NPDU& npdu = tpdu.frame().npdu(); + _netLayerEntities[kPrimaryIfIndex].sendDataRequest(npdu, ack, 0, _deviceObj.individualAddress(), priority, GroupAddress, Broadcast); + _netLayerEntities[kSecondaryIfIndex].sendDataRequest(tmpFrame.npdu(), ack, 0, _deviceObj.individualAddress(), priority, GroupAddress, Broadcast); + } - if (hopType == UnlimitedRouting) - npdu.hopCount(7); - else - npdu.hopCount(hopCount()); + void NetworkLayerCoupler::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) + { + NPDU& npdu = tpdu.frame().npdu(); + if (hopType == UnlimitedRouting) + npdu.hopCount(7); + else + npdu.hopCount(hopCount()); - CemiFrame tmpFrame(tpdu.frame()); - // for closed media like TP1 and IP - bool isClosedMedium = (_netLayerEntities[kPrimaryIfIndex].mediumType() == DptMedium::KNX_TP1) || (_netLayerEntities[kPrimaryIfIndex].mediumType() == DptMedium::KNX_IP); - SystemBroadcast broadcastType = (isClosedMedium && isApciSystemBroadcast(tpdu.apdu()) ? Broadcast : SysBroadcast); - _netLayerEntities[kPrimaryIfIndex].sendDataRequest(npdu, ack, 0, _deviceObj.individualAddress(), priority, GroupAddress, broadcastType); + CemiFrame tmpFrame(tpdu.frame()); - isClosedMedium = (_netLayerEntities[kSecondaryIfIndex].mediumType() == DptMedium::KNX_TP1) || (_netLayerEntities[kSecondaryIfIndex].mediumType() == DptMedium::KNX_IP); - broadcastType = (isClosedMedium && isApciSystemBroadcast(tmpFrame.apdu()) ? Broadcast : SysBroadcast); - println(broadcastType); - _netLayerEntities[kSecondaryIfIndex].sendDataRequest(tmpFrame.npdu(), ack, 0, _deviceObj.individualAddress(), priority, GroupAddress, broadcastType); -} + // for closed media like TP1 and IP + bool isClosedMedium = (_netLayerEntities[kPrimaryIfIndex].mediumType() == DptMedium::KNX_TP1) || (_netLayerEntities[kPrimaryIfIndex].mediumType() == DptMedium::KNX_IP); + SystemBroadcast broadcastType = (isClosedMedium && isApciSystemBroadcast(tpdu.apdu()) ? Broadcast : SysBroadcast); + _netLayerEntities[kPrimaryIfIndex].sendDataRequest(npdu, ack, 0, _deviceObj.individualAddress(), priority, GroupAddress, broadcastType); + + isClosedMedium = (_netLayerEntities[kSecondaryIfIndex].mediumType() == DptMedium::KNX_TP1) || (_netLayerEntities[kSecondaryIfIndex].mediumType() == DptMedium::KNX_IP); + broadcastType = (isClosedMedium && isApciSystemBroadcast(tmpFrame.apdu()) ? Broadcast : SysBroadcast); + println(broadcastType); + _netLayerEntities[kSecondaryIfIndex].sendDataRequest(tmpFrame.npdu(), ack, 0, _deviceObj.individualAddress(), priority, GroupAddress, broadcastType); + } #ifdef KNX_TUNNELING -bool NetworkLayerCoupler::isTunnelAddress(uint16_t destination) -{ - // tunnels are managed within the IpDataLinkLayer - kPrimaryIfIndex - return _netLayerEntities[kPrimaryIfIndex].dataLinkLayer().isTunnelAddress(destination); -} -#endif \ No newline at end of file + bool NetworkLayerCoupler::isTunnelAddress(uint16_t destination) + { + // tunnels are managed within the IpDataLinkLayer - kPrimaryIfIndex + return _netLayerEntities[kPrimaryIfIndex].dataLinkLayer().isTunnelAddress(destination); + } +#endif +} \ No newline at end of file diff --git a/src/knx/coupler/network_layer_coupler.h b/src/knx/coupler/network_layer_coupler.h index 1475822e..81d8f614 100644 --- a/src/knx/coupler/network_layer_coupler.h +++ b/src/knx/coupler/network_layer_coupler.h @@ -6,74 +6,77 @@ #include -class DeviceObject; -class RouterObject; - -class NetworkLayerCoupler : public NetworkLayer +namespace Knx { - friend class NetworkLayerEntity; - - public: - NetworkLayerCoupler(DeviceObject& deviceObj, TransportLayer& layer); - - NetworkLayerEntity& getPrimaryInterface(); - NetworkLayerEntity& getSecondaryInterface(); - - bool isRoutedIndividualAddress(uint16_t individualAddress, uint8_t srcIfIndex); - - bool isRoutedGroupAddress(uint16_t groupAddress, uint8_t sourceInterfaceIndex); - - void rtObjPrimary(RouterObject& rtObjPrimary); // Coupler model 2.0 - void rtObjSecondary(RouterObject& rtObjSecondary); // Coupler model 2.0 - void rtObj(RouterObject& rtObj); // Coupler model 1.x - - // from transport layer - void dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override; - void dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override; - void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override; - void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override; - - private: - enum CouplerType - { - LineCoupler, - BackboneCoupler, - TP1Bridge, - TP1Repeater - }; - - static constexpr uint8_t kPrimaryIfIndex = 0; - static constexpr uint8_t kSecondaryIfIndex = 1; - static constexpr uint8_t kLocalIfIndex = 99; - - // from entities - void dataIndication(AckType ack, AddressType addType, uint16_t destination, FrameFormat format, NPDU& npdu, - Priority priority, uint16_t source, uint8_t srcIfIdx) override; - void dataConfirm(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, Priority priority, - uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override; - void broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, - Priority priority, uint16_t source, uint8_t srcIfIdx) override; - void broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override; - void systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, - Priority priority, uint16_t source, uint8_t srcIfIdx) override; - void systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override; - - void routeDataIndividual(AckType ack, uint16_t destination, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIndex); - void sendMsgHopCount(AckType ack, AddressType addrType, uint16_t destination, NPDU& npdu, Priority priority, - SystemBroadcast broadcastType, uint8_t sourceInterfaceIndex, uint16_t source); - - void evaluateCouplerType(); - bool isGroupAddressInFilterTable(uint16_t groupAddress); + class DeviceObject; + class RouterObject; + + class NetworkLayerCoupler : public NetworkLayer + { + friend class NetworkLayerEntity; + + public: + NetworkLayerCoupler(DeviceObject& deviceObj, TransportLayer& layer); + + NetworkLayerEntity& getPrimaryInterface(); + NetworkLayerEntity& getSecondaryInterface(); + + bool isRoutedIndividualAddress(uint16_t individualAddress, uint8_t srcIfIndex); + + bool isRoutedGroupAddress(uint16_t groupAddress, uint8_t sourceInterfaceIndex); + + void rtObjPrimary(RouterObject& rtObjPrimary); // Coupler model 2.0 + void rtObjSecondary(RouterObject& rtObjSecondary); // Coupler model 2.0 + void rtObj(RouterObject& rtObj); // Coupler model 1.x + + // from transport layer + void dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override; + void dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override; + void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override; + void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override; + + private: + enum CouplerType + { + LineCoupler, + BackboneCoupler, + TP1Bridge, + TP1Repeater + }; + + static constexpr uint8_t kPrimaryIfIndex = 0; + static constexpr uint8_t kSecondaryIfIndex = 1; + static constexpr uint8_t kLocalIfIndex = 99; + + // from entities + void dataIndication(AckType ack, AddressType addType, uint16_t destination, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source, uint8_t srcIfIdx) override; + void dataConfirm(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, Priority priority, + uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override; + void broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source, uint8_t srcIfIdx) override; + void broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override; + void systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source, uint8_t srcIfIdx) override; + void systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override; + + void routeDataIndividual(AckType ack, uint16_t destination, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIndex); + void sendMsgHopCount(AckType ack, AddressType addrType, uint16_t destination, NPDU& npdu, Priority priority, + SystemBroadcast broadcastType, uint8_t sourceInterfaceIndex, uint16_t source); + + void evaluateCouplerType(); + bool isGroupAddressInFilterTable(uint16_t groupAddress); #ifdef KNX_TUNNELING - bool isTunnelAddress(uint16_t destination); + bool isTunnelAddress(uint16_t destination); #endif - // Support a maximum of two physical interfaces for couplers - NetworkLayerEntity _netLayerEntities[2]; + // Support a maximum of two physical interfaces for couplers + NetworkLayerEntity _netLayerEntities[2]; - RouterObject* _rtObjPrimary {nullptr}; - RouterObject* _rtObjSecondary {nullptr}; + RouterObject* _rtObjPrimary {nullptr}; + RouterObject* _rtObjSecondary {nullptr}; - CouplerType _couplerType; - uint16_t _currentAddress; -}; + CouplerType _couplerType; + uint16_t _currentAddress; + }; +} \ No newline at end of file diff --git a/src/knx/coupler/router_object.cpp b/src/knx/coupler/router_object.cpp index a5c1ffac..74faff3c 100644 --- a/src/knx/coupler/router_object.cpp +++ b/src/knx/coupler/router_object.cpp @@ -6,595 +6,599 @@ #include -// Filter Table Realization Type 3 -// The Filter Table Realisation Type 3 shall be organised as a memory mapped bit-field of -// 65536 bits and thus 8 192 octets. Each bit shall uniquely correspond to one Group Address. -// The full 16 bit KNX GA encoding range shall be supported. -// -// octet_address = GA_value div 8 -// bit_position = GA_value mod 8 -static constexpr uint16_t kFilterTableSize = 65536 / 8; // Each group address is represented by one bit - -enum RouteTableServices -{ - ClearRoutingTable = 0x01, // no info bytes - SetRoutingTable = 0x02, // no info bytes - ClearGroupAddress = 0x03, // 4 bytes: start address and end address - SetGroupAddress = 0x04, // 4 bytes: start address and end address -}; - -RouterObject::RouterObject(Memory& memory, uint32_t staticTableAdr, uint32_t staticTableSize) - : TableObject(memory, staticTableAdr, staticTableSize) -{ -} - -void RouterObject::initialize1x(DptMedium mediumType, uint16_t maxApduSize) -{ - // Object index property is not included for coupler model 1.x, so value is "don't care". - initialize(CouplerModel::Model_1x, 200, mediumType, RouterObjectType::Single, maxApduSize); -} -void RouterObject::initialize20(uint8_t objIndex, DptMedium mediumType, RouterObjectType rtType, uint16_t maxApduSize) +namespace Knx { - initialize(CouplerModel::Model_20, objIndex, mediumType, rtType, maxApduSize); -} - -void RouterObject::initialize(CouplerModel model, uint8_t objIndex, DptMedium mediumType, RouterObjectType rtType, uint16_t maxApduSize) -{ - bool useHopCount = false; - bool useTable = true; - _model = model; - - if (model == CouplerModel::Model_20) + // Filter Table Realization Type 3 + // The Filter Table Realisation Type 3 shall be organised as a memory mapped bit-field of + // 65536 bits and thus 8 192 octets. Each bit shall uniquely correspond to one Group Address. + // The full 16 bit KNX GA encoding range shall be supported. + // + // octet_address = GA_value div 8 + // bit_position = GA_value mod 8 + static constexpr uint16_t kFilterTableSize = 65536 / 8; // Each group address is represented by one bit + + enum RouteTableServices { - useHopCount = (rtType == RouterObjectType::Primary); - useTable = (rtType == RouterObjectType::Secondary); - } - - // These properties are always present - Property* fixedProperties[] = - { - new DataProperty( PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t) OT_ROUTER ), - new DataProperty( PID_MEDIUM_STATUS, false, PDT_GENERIC_01, 1, ReadLv3 | WriteLv0, (uint16_t) 0 ), // 0 means communication is possible, could be set by datalink layer or bau to 1 (comm impossible) - new DataProperty( PID_MAX_APDU_LENGTH_ROUTER, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, maxApduSize ), + ClearRoutingTable = 0x01, // no info bytes + SetRoutingTable = 0x02, // no info bytes + ClearGroupAddress = 0x03, // 4 bytes: start address and end address + SetGroupAddress = 0x04, // 4 bytes: start address and end address }; - uint8_t fixedPropertiesCount = sizeof(fixedProperties) / sizeof(Property*); - // Only present if coupler model is 1.x - Property* model1xProperties[] = + RouterObject::RouterObject(Memory& memory, uint32_t staticTableAdr, uint32_t staticTableSize) + : TableObject(memory, staticTableAdr, staticTableSize) { - // default values from Spec, see 03_05_01 4.4.4 and 4.4.5 - new DataProperty( PID_MAIN_LCCONFIG, true, PDT_BITSET8, 1, ReadLv3 | WriteLv0, (uint8_t) (LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL) ), // Primary: data individual (connless and connorient) + broadcast - new DataProperty( PID_SUB_LCCONFIG, true, PDT_BITSET8, 1, ReadLv3 | WriteLv0, (uint8_t) (LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL) ), // Secondary: data individual (connless and connorient) + broadcast - new DataProperty( PID_MAIN_LCGRPCONFIG, true, PDT_BITSET8, 1, ReadLv3 | WriteLv0, (uint8_t) (LCGRPCONFIG::GROUP_6FFFROUTE | LCGRPCONFIG::GROUP_7000UNLOCK | LCGRPCONFIG::GROUP_REPEAT)), // Primary: data group - new DataProperty( PID_SUB_LCGRPCONFIG, true, PDT_BITSET8, 1, ReadLv3 | WriteLv0, (uint8_t) (LCGRPCONFIG::GROUP_6FFFROUTE | LCGRPCONFIG::GROUP_7000UNLOCK | LCGRPCONFIG::GROUP_REPEAT)), // Secondary: data group - }; - uint8_t model1xPropertiesCount = sizeof(model1xProperties) / sizeof(Property*); + } - // Only present if coupler model is 2.0 - // One router object per interface, currently only TP1/RF coupler specified - Property* model20Properties[] = + void RouterObject::initialize1x(DptMedium mediumType, uint16_t maxApduSize) { - new DataProperty( PID_OBJECT_INDEX, false, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv0, objIndex ), // Must be set by concrete BAUxxxx! - new DataProperty( PID_MEDIUM, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint8_t) mediumType ), - }; - uint8_t model20PropertiesCount = sizeof(model20Properties) / sizeof(Property*); + // Object index property is not included for coupler model 1.x, so value is "don't care". + initialize(CouplerModel::Model_1x, 200, mediumType, RouterObjectType::Single, maxApduSize); + } - Property* tableProperties[] = + void RouterObject::initialize20(uint8_t objIndex, DptMedium mediumType, RouterObjectType rtType, uint16_t maxApduSize) { - new FunctionProperty(this, PID_ROUTETABLE_CONTROL, - // Command Callback of PID_ROUTETABLE_CONTROL - [](RouterObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void { - obj->functionRouteTableControl(true, data, length, resultData, resultLength); - }, - // State Callback of PID_ROUTETABLE_CONTROL - [](RouterObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void { - obj->functionRouteTableControl(false, data, length, resultData, resultLength); - }) - }; + initialize(CouplerModel::Model_20, objIndex, mediumType, rtType, maxApduSize); + } - Property* tableProperties20[] = + void RouterObject::initialize(CouplerModel model, uint8_t objIndex, DptMedium mediumType, RouterObjectType rtType, uint16_t maxApduSize) { - new DataProperty( PID_COUPLER_SERVICES_CONTROL, true, PDT_GENERIC_01, 1, ReadLv3 | WriteLv0, (uint8_t) 0), // written by ETS TODO: implement - new DataProperty( PID_FILTER_TABLE_USE, true, PDT_BINARY_INFORMATION, 1, ReadLv3 | WriteLv0, (uint16_t) 0 ) // default: invalid filter table, do not use, written by ETS - }; + bool useHopCount = false; + bool useTable = true; + _model = model; - uint8_t tablePropertiesCount = sizeof(tableProperties) / sizeof(Property*); - uint8_t tableProperties20Count = sizeof(tableProperties20) / sizeof(Property*); + if (model == CouplerModel::Model_20) + { + useHopCount = (rtType == RouterObjectType::Primary); + useTable = (rtType == RouterObjectType::Secondary); + } - size_t allPropertiesCount = fixedPropertiesCount; - allPropertiesCount += (model == CouplerModel::Model_1x) ? model1xPropertiesCount : model20PropertiesCount; - allPropertiesCount += useHopCount ? 1 : 0; - allPropertiesCount += useTable ? tablePropertiesCount : 0; - allPropertiesCount += useTable && (model == CouplerModel::Model_20) ? tableProperties20Count : 0; - allPropertiesCount += ((mediumType == DptMedium::KNX_RF) || (mediumType == DptMedium::KNX_IP)) ? 1 : 0; // PID_RF_ENABLE_SBC and PID_IP_ENABLE_SBC + // These properties are always present + Property* fixedProperties[] = + { + new DataProperty( PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t) OT_ROUTER ), + new DataProperty( PID_MEDIUM_STATUS, false, PDT_GENERIC_01, 1, ReadLv3 | WriteLv0, (uint16_t) 0 ), // 0 means communication is possible, could be set by datalink layer or bau to 1 (comm impossible) + new DataProperty( PID_MAX_APDU_LENGTH_ROUTER, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, maxApduSize ), + }; + uint8_t fixedPropertiesCount = sizeof(fixedProperties) / sizeof(Property*); + + // Only present if coupler model is 1.x + Property* model1xProperties[] = + { + // default values from Spec, see 03_05_01 4.4.4 and 4.4.5 + new DataProperty( PID_MAIN_LCCONFIG, true, PDT_BITSET8, 1, ReadLv3 | WriteLv0, (uint8_t) (LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL) ), // Primary: data individual (connless and connorient) + broadcast + new DataProperty( PID_SUB_LCCONFIG, true, PDT_BITSET8, 1, ReadLv3 | WriteLv0, (uint8_t) (LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL) ), // Secondary: data individual (connless and connorient) + broadcast + new DataProperty( PID_MAIN_LCGRPCONFIG, true, PDT_BITSET8, 1, ReadLv3 | WriteLv0, (uint8_t) (LCGRPCONFIG::GROUP_6FFFROUTE | LCGRPCONFIG::GROUP_7000UNLOCK | LCGRPCONFIG::GROUP_REPEAT)), // Primary: data group + new DataProperty( PID_SUB_LCGRPCONFIG, true, PDT_BITSET8, 1, ReadLv3 | WriteLv0, (uint8_t) (LCGRPCONFIG::GROUP_6FFFROUTE | LCGRPCONFIG::GROUP_7000UNLOCK | LCGRPCONFIG::GROUP_REPEAT)), // Secondary: data group + }; + uint8_t model1xPropertiesCount = sizeof(model1xProperties) / sizeof(Property*); + + // Only present if coupler model is 2.0 + // One router object per interface, currently only TP1/RF coupler specified + Property* model20Properties[] = + { + new DataProperty( PID_OBJECT_INDEX, false, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv0, objIndex ), // Must be set by concrete BAUxxxx! + new DataProperty( PID_MEDIUM, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint8_t) mediumType ), + }; + uint8_t model20PropertiesCount = sizeof(model20Properties) / sizeof(Property*); - Property* allProperties[allPropertiesCount]; + Property* tableProperties[] = + { + new FunctionProperty(this, PID_ROUTETABLE_CONTROL, + // Command Callback of PID_ROUTETABLE_CONTROL + [](RouterObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void { + obj->functionRouteTableControl(true, data, length, resultData, resultLength); + }, + // State Callback of PID_ROUTETABLE_CONTROL + [](RouterObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void { + obj->functionRouteTableControl(false, data, length, resultData, resultLength); + }) + }; + + Property* tableProperties20[] = + { + new DataProperty( PID_COUPLER_SERVICES_CONTROL, true, PDT_GENERIC_01, 1, ReadLv3 | WriteLv0, (uint8_t) 0), // written by ETS TODO: implement + new DataProperty( PID_FILTER_TABLE_USE, true, PDT_BINARY_INFORMATION, 1, ReadLv3 | WriteLv0, (uint16_t) 0 ) // default: invalid filter table, do not use, written by ETS + }; - memcpy(&allProperties[0], &fixedProperties[0], sizeof(fixedProperties)); + uint8_t tablePropertiesCount = sizeof(tableProperties) / sizeof(Property*); + uint8_t tableProperties20Count = sizeof(tableProperties20) / sizeof(Property*); - uint8_t i = fixedPropertiesCount; + size_t allPropertiesCount = fixedPropertiesCount; + allPropertiesCount += (model == CouplerModel::Model_1x) ? model1xPropertiesCount : model20PropertiesCount; + allPropertiesCount += useHopCount ? 1 : 0; + allPropertiesCount += useTable ? tablePropertiesCount : 0; + allPropertiesCount += useTable && (model == CouplerModel::Model_20) ? tableProperties20Count : 0; + allPropertiesCount += ((mediumType == DptMedium::KNX_RF) || (mediumType == DptMedium::KNX_IP)) ? 1 : 0; // PID_RF_ENABLE_SBC and PID_IP_ENABLE_SBC - if (model == CouplerModel::Model_1x) - { - memcpy(&allProperties[i], model1xProperties, sizeof(model1xProperties)); - i += model1xPropertiesCount; - } - else - { - memcpy(&allProperties[i], model20Properties, sizeof(model20Properties)); - i += model20PropertiesCount; - } + Property* allProperties[allPropertiesCount]; - if (useHopCount) - { - // TODO: Primary side: 5 for line coupler, 4 for backbone coupler, only exists if secondary is open medium without hop count - // Do we need to set a default value here or is it written by ETS? - allProperties[i++] = new DataProperty( PID_HOP_COUNT, true, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t) 5); - } + memcpy(&allProperties[0], &fixedProperties[0], sizeof(fixedProperties)); - if (useTable) - { - memcpy(&allProperties[i], tableProperties, sizeof(tableProperties)); - i += tablePropertiesCount; + uint8_t i = fixedPropertiesCount; - if ((model == CouplerModel::Model_20)) + if (model == CouplerModel::Model_1x) { - memcpy(&allProperties[i], tableProperties20, sizeof(tableProperties20)); - i += tableProperties20Count; + memcpy(&allProperties[i], model1xProperties, sizeof(model1xProperties)); + i += model1xPropertiesCount; } - } - - if (mediumType == DptMedium::KNX_RF) - { - allProperties[i++] = new FunctionProperty(this, PID_RF_ENABLE_SBC, - // Command Callback of PID_RF_ENABLE_SBC - [](RouterObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void - { - obj->functionRfEnableSbc(true, data, length, resultData, resultLength); - }, - // State Callback of PID_RF_ENABLE_SBC - [](RouterObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void + else { - obj->functionRfEnableSbc(false, data, length, resultData, resultLength); - }); - } - else if (mediumType == DptMedium::KNX_IP) - { - allProperties[i++] = new FunctionProperty(this, PID_IP_ENABLE_SBC, - // Command Callback of PID_IP_ENABLE_SBC - [](RouterObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void + memcpy(&allProperties[i], model20Properties, sizeof(model20Properties)); + i += model20PropertiesCount; + } + + if (useHopCount) { - obj->functionIpEnableSbc(true, data, length, resultData, resultLength); - }, - // State Callback of PID_IP_ENABLE_SBC - [](RouterObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void + // TODO: Primary side: 5 for line coupler, 4 for backbone coupler, only exists if secondary is open medium without hop count + // Do we need to set a default value here or is it written by ETS? + allProperties[i++] = new DataProperty( PID_HOP_COUNT, true, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t) 5); + } + + if (useTable) { - obj->functionIpEnableSbc(false, data, length, resultData, resultLength); - }); - } + memcpy(&allProperties[i], tableProperties, sizeof(tableProperties)); + i += tablePropertiesCount; - if (useTable) - TableObject::initializeProperties(sizeof(allProperties), allProperties); - else - InterfaceObject::initializeProperties(sizeof(allProperties), allProperties); -} + if ((model == CouplerModel::Model_20)) + { + memcpy(&allProperties[i], tableProperties20, sizeof(tableProperties20)); + i += tableProperties20Count; + } + } -const uint8_t* RouterObject::restore(const uint8_t* buffer) -{ - return TableObject::restore(buffer); -} + if (mediumType == DptMedium::KNX_RF) + { + allProperties[i++] = new FunctionProperty(this, PID_RF_ENABLE_SBC, + // Command Callback of PID_RF_ENABLE_SBC + [](RouterObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void + { + obj->functionRfEnableSbc(true, data, length, resultData, resultLength); + }, + // State Callback of PID_RF_ENABLE_SBC + [](RouterObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void + { + obj->functionRfEnableSbc(false, data, length, resultData, resultLength); + }); + } + else if (mediumType == DptMedium::KNX_IP) + { + allProperties[i++] = new FunctionProperty(this, PID_IP_ENABLE_SBC, + // Command Callback of PID_IP_ENABLE_SBC + [](RouterObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void + { + obj->functionIpEnableSbc(true, data, length, resultData, resultLength); + }, + // State Callback of PID_IP_ENABLE_SBC + [](RouterObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void + { + obj->functionIpEnableSbc(false, data, length, resultData, resultLength); + }); + } -void RouterObject::commandClearSetRoutingTable(bool bitIsSet) -{ - uint8_t fillbyte = bitIsSet ? 0xFF : 0x00; - uint32_t relptr = _memory.toRelative(data()); -#ifdef KNX_LOG_COUPLER - print("RouterObject::commandClearSetRoutingTable "); - println(bitIsSet); - println(relptr); - println((uint32_t)data()); -#endif + if (useTable) + TableObject::initializeProperties(sizeof(allProperties), allProperties); + else + InterfaceObject::initializeProperties(sizeof(allProperties), allProperties); + } - for (uint16_t i = 0; i < kFilterTableSize; i++) + const uint8_t* RouterObject::restore(const uint8_t* buffer) { - _memory.writeMemory(relptr + i, 1, &fillbyte); + return TableObject::restore(buffer); } -} -bool RouterObject::statusClearSetRoutingTable(bool bitIsSet) -{ + void RouterObject::commandClearSetRoutingTable(bool bitIsSet) + { + uint8_t fillbyte = bitIsSet ? 0xFF : 0x00; + uint32_t relptr = _memory.toRelative(data()); #ifdef KNX_LOG_COUPLER - print("RouterObject::statusClearSetRoutingTable "); - println(bitIsSet); + print("RouterObject::commandClearSetRoutingTable "); + println(bitIsSet); + println(relptr); + println((uint32_t)data()); #endif - for (uint16_t i = 0; i < kFilterTableSize; i++) - { - if (data()[i] != (bitIsSet ? 0xFF : 0x00)) - return false; + for (uint16_t i = 0; i < kFilterTableSize; i++) + { + _memory.writeMemory(relptr + i, 1, &fillbyte); + } } - return true; -} - -void RouterObject::commandClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet) -{ + bool RouterObject::statusClearSetRoutingTable(bool bitIsSet) + { #ifdef KNX_LOG_COUPLER - print("RouterObject::commandClearSetGroupAddress "); - print(startAddress); - print(" "); - print(endAddress); - print(" "); - println(bitIsSet); + print("RouterObject::statusClearSetRoutingTable "); + println(bitIsSet); #endif - uint16_t startOctet = startAddress / 8; - uint8_t startBitPosition = startAddress % 8; - uint16_t endOctet = endAddress / 8; - uint8_t endBitPosition = endAddress % 8; - - if (startOctet == endOctet) - { - uint32_t relptr = _memory.toRelative(data()) + startOctet; - uint8_t octetData = 0; // = data()[startOctet]; - _memory.readMemory(relptr, 1, &octetData); - - for (uint8_t bitPos = startBitPosition; bitPos <= endBitPosition; bitPos++) + for (uint16_t i = 0; i < kFilterTableSize; i++) { - if (bitIsSet) - octetData |= 1 << bitPos; - else - octetData &= ~(1 << bitPos); + if (data()[i] != (bitIsSet ? 0xFF : 0x00)) + return false; } - _memory.writeMemory(relptr, 1, &octetData); - return; + return true; } - for (uint16_t i = startOctet; i <= endOctet; i++) + void RouterObject::commandClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet) { - uint32_t relptr = _memory.toRelative(data()) + i; - uint8_t octetData = 0; - _memory.readMemory(relptr, 1, &octetData); +#ifdef KNX_LOG_COUPLER + print("RouterObject::commandClearSetGroupAddress "); + print(startAddress); + print(" "); + print(endAddress); + print(" "); + println(bitIsSet); +#endif + + uint16_t startOctet = startAddress / 8; + uint8_t startBitPosition = startAddress % 8; + uint16_t endOctet = endAddress / 8; + uint8_t endBitPosition = endAddress % 8; - if (i == startOctet) + if (startOctet == endOctet) { - for (uint8_t bitPos = startBitPosition; bitPos <= 7; bitPos++) + uint32_t relptr = _memory.toRelative(data()) + startOctet; + uint8_t octetData = 0; // = data()[startOctet]; + _memory.readMemory(relptr, 1, &octetData); + + for (uint8_t bitPos = startBitPosition; bitPos <= endBitPosition; bitPos++) { if (bitIsSet) octetData |= 1 << bitPos; else octetData &= ~(1 << bitPos); } + + _memory.writeMemory(relptr, 1, &octetData); + return; } - else if (i == endOctet) + + for (uint16_t i = startOctet; i <= endOctet; i++) { - for (uint8_t bitPos = 0; bitPos <= endBitPosition; bitPos++) + uint32_t relptr = _memory.toRelative(data()) + i; + uint8_t octetData = 0; + _memory.readMemory(relptr, 1, &octetData); + + if (i == startOctet) { - if (bitIsSet) - octetData |= 1 << bitPos; - else - octetData &= ~(1 << bitPos); + for (uint8_t bitPos = startBitPosition; bitPos <= 7; bitPos++) + { + if (bitIsSet) + octetData |= 1 << bitPos; + else + octetData &= ~(1 << bitPos); + } } - } - else - { - if (bitIsSet) - octetData = 0xFF; - else - octetData = 0x00; - } - - _memory.writeMemory(relptr, 1, &octetData); - } -} - -bool RouterObject::statusClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet) -{ -#ifdef KNX_LOG_COUPLER - print("RouterObject::statusClearSetGroupAddress "); - print(startAddress); - print(" "); - print(endAddress); - print(" "); - println(bitIsSet); -#endif - - uint16_t startOctet = startAddress / 8; - uint8_t startBitPosition = startAddress % 8; - uint16_t endOctet = endAddress / 8; - uint8_t endBitPosition = endAddress % 8; - - if (startOctet == endOctet) - { - for (uint8_t bitPos = startBitPosition; bitPos <= endBitPosition; bitPos++) - { - if (bitIsSet) + else if (i == endOctet) { - if ((data()[startOctet] & (1 << bitPos)) == 0) - return false; + for (uint8_t bitPos = 0; bitPos <= endBitPosition; bitPos++) + { + if (bitIsSet) + octetData |= 1 << bitPos; + else + octetData &= ~(1 << bitPos); + } } else { - if ((data()[startOctet] & (1 << bitPos)) != 0) - return false; + if (bitIsSet) + octetData = 0xFF; + else + octetData = 0x00; } - } - return true; + _memory.writeMemory(relptr, 1, &octetData); + } } - for (uint16_t i = startOctet; i <= endOctet; i++) + bool RouterObject::statusClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet) { - if (i == startOctet) +#ifdef KNX_LOG_COUPLER + print("RouterObject::statusClearSetGroupAddress "); + print(startAddress); + print(" "); + print(endAddress); + print(" "); + println(bitIsSet); +#endif + + uint16_t startOctet = startAddress / 8; + uint8_t startBitPosition = startAddress % 8; + uint16_t endOctet = endAddress / 8; + uint8_t endBitPosition = endAddress % 8; + + if (startOctet == endOctet) { - for (uint8_t bitPos = startBitPosition; bitPos <= 7; bitPos++) + for (uint8_t bitPos = startBitPosition; bitPos <= endBitPosition; bitPos++) { if (bitIsSet) { - if ((data()[i] & (1 << bitPos)) == 0) + if ((data()[startOctet] & (1 << bitPos)) == 0) return false; } else { - if ((data()[i] & (1 << bitPos)) != 0) + if ((data()[startOctet] & (1 << bitPos)) != 0) return false; } } + + return true; } - else if (i == endOctet) + + for (uint16_t i = startOctet; i <= endOctet; i++) { - for (uint8_t bitPos = 0; bitPos <= endBitPosition; bitPos++) + if (i == startOctet) { - if (bitIsSet) + for (uint8_t bitPos = startBitPosition; bitPos <= 7; bitPos++) { - if ((data()[i] & (1 << bitPos)) == 0) - return false; + if (bitIsSet) + { + if ((data()[i] & (1 << bitPos)) == 0) + return false; + } + else + { + if ((data()[i] & (1 << bitPos)) != 0) + return false; + } } - else + } + else if (i == endOctet) + { + for (uint8_t bitPos = 0; bitPos <= endBitPosition; bitPos++) { - if ((data()[i] & (1 << bitPos)) != 0) - return false; + if (bitIsSet) + { + if ((data()[i] & (1 << bitPos)) == 0) + return false; + } + else + { + if ((data()[i] & (1 << bitPos)) != 0) + return false; + } } } + else + { + if (data()[i] != (bitIsSet ? 0xFF : 0x00)) + return false; + } } - else - { - if (data()[i] != (bitIsSet ? 0xFF : 0x00)) - return false; - } - } - return true; -} + return true; + } -void RouterObject::functionRouteTableControl(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -{ + void RouterObject::functionRouteTableControl(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) + { #ifdef KNX_LOG_COUPLER - print("RouterObject::functionRouteTableControl "); - print(isCommand); - print(" "); - printHex("", data, length); + print("RouterObject::functionRouteTableControl "); + print(isCommand); + print(" "); + printHex("", data, length); #endif - RouteTableServices srvId = (RouteTableServices) data[1]; + RouteTableServices srvId = (RouteTableServices) data[1]; - if (isCommand) - { - if (loadState() != LS_LOADING) + if (isCommand) { - println("access violation. filter table can only be modified in LS_LOADING"); - resultData[0] = ReturnCodes::AccessReadOnly; - resultData[1] = srvId; - resultLength = 2; - return; - } - - switch (srvId) - { - case ClearRoutingTable: - commandClearSetRoutingTable(false); - resultData[0] = ReturnCodes::Success; - resultData[1] = srvId; - resultLength = 2; - return; - - case SetRoutingTable: - commandClearSetRoutingTable(true); - resultData[0] = ReturnCodes::Success; - resultData[1] = srvId; - resultLength = 2; - return; - - case ClearGroupAddress: + if (loadState() != LS_LOADING) { - uint16_t startAddress; - uint16_t endAddress; - popWord(startAddress, &data[2]); - popWord(endAddress, &data[4]); - commandClearSetGroupAddress(startAddress, endAddress, false); - resultData[0] = ReturnCodes::Success; + println("access violation. filter table can only be modified in LS_LOADING"); + resultData[0] = ReturnCodes::AccessReadOnly; resultData[1] = srvId; - pushWord(startAddress, &resultData[2]); - pushWord(endAddress, &resultData[4]); - resultLength = 6; + resultLength = 2; return; } - case SetGroupAddress: + switch (srvId) { - uint16_t startAddress; - uint16_t endAddress; - popWord(startAddress, &data[2]); - popWord(endAddress, &data[4]); - commandClearSetGroupAddress(startAddress, endAddress, true); - resultData[0] = ReturnCodes::Success; - resultData[1] = srvId; - pushWord(startAddress, &resultData[2]); - pushWord(endAddress, &resultData[4]); - resultLength = 6; - return; + case ClearRoutingTable: + commandClearSetRoutingTable(false); + resultData[0] = ReturnCodes::Success; + resultData[1] = srvId; + resultLength = 2; + return; + + case SetRoutingTable: + commandClearSetRoutingTable(true); + resultData[0] = ReturnCodes::Success; + resultData[1] = srvId; + resultLength = 2; + return; + + case ClearGroupAddress: + { + uint16_t startAddress; + uint16_t endAddress; + popWord(startAddress, &data[2]); + popWord(endAddress, &data[4]); + commandClearSetGroupAddress(startAddress, endAddress, false); + resultData[0] = ReturnCodes::Success; + resultData[1] = srvId; + pushWord(startAddress, &resultData[2]); + pushWord(endAddress, &resultData[4]); + resultLength = 6; + return; + } + + case SetGroupAddress: + { + uint16_t startAddress; + uint16_t endAddress; + popWord(startAddress, &data[2]); + popWord(endAddress, &data[4]); + commandClearSetGroupAddress(startAddress, endAddress, true); + resultData[0] = ReturnCodes::Success; + resultData[1] = srvId; + pushWord(startAddress, &resultData[2]); + pushWord(endAddress, &resultData[4]); + resultLength = 6; + return; + } } } - } - else - { - switch (srvId) + else { - case ClearRoutingTable: - resultData[0] = statusClearSetRoutingTable(false) ? ReturnCodes::Success : ReturnCodes::GenericError; - resultData[1] = srvId; - resultLength = 2; - return; - - case SetRoutingTable: - resultData[0] = statusClearSetRoutingTable(true) ? ReturnCodes::Success : ReturnCodes::GenericError; - resultData[1] = srvId; - resultLength = 2; - return; - - case ClearGroupAddress: + switch (srvId) { - uint16_t startAddress; - uint16_t endAddress; - popWord(startAddress, &data[2]); - popWord(endAddress, &data[4]); - resultData[0] = statusClearSetGroupAddress(startAddress, endAddress, false) ? ReturnCodes::Success : ReturnCodes::GenericError; - resultData[1] = srvId; - pushWord(startAddress, &resultData[2]); - pushWord(endAddress, &resultData[4]); - resultLength = 6; - return; - } + case ClearRoutingTable: + resultData[0] = statusClearSetRoutingTable(false) ? ReturnCodes::Success : ReturnCodes::GenericError; + resultData[1] = srvId; + resultLength = 2; + return; + + case SetRoutingTable: + resultData[0] = statusClearSetRoutingTable(true) ? ReturnCodes::Success : ReturnCodes::GenericError; + resultData[1] = srvId; + resultLength = 2; + return; + + case ClearGroupAddress: + { + uint16_t startAddress; + uint16_t endAddress; + popWord(startAddress, &data[2]); + popWord(endAddress, &data[4]); + resultData[0] = statusClearSetGroupAddress(startAddress, endAddress, false) ? ReturnCodes::Success : ReturnCodes::GenericError; + resultData[1] = srvId; + pushWord(startAddress, &resultData[2]); + pushWord(endAddress, &resultData[4]); + resultLength = 6; + return; + } - case SetGroupAddress: - { - uint16_t startAddress; - uint16_t endAddress; - popWord(startAddress, &data[2]); - popWord(endAddress, &data[4]); - resultData[0] = statusClearSetGroupAddress(startAddress, endAddress, true) ? ReturnCodes::Success : ReturnCodes::GenericError; - resultData[1] = srvId; - pushWord(startAddress, &resultData[2]); - pushWord(endAddress, &resultData[4]); - resultLength = 6; - return; + case SetGroupAddress: + { + uint16_t startAddress; + uint16_t endAddress; + popWord(startAddress, &data[2]); + popWord(endAddress, &data[4]); + resultData[0] = statusClearSetGroupAddress(startAddress, endAddress, true) ? ReturnCodes::Success : ReturnCodes::GenericError; + resultData[1] = srvId; + pushWord(startAddress, &resultData[2]); + pushWord(endAddress, &resultData[4]); + resultLength = 6; + return; + } } } - } - // We should not get here - resultData[0] = ReturnCodes::GenericError; - resultData[1] = srvId; - resultLength = 2; -} + // We should not get here + resultData[0] = ReturnCodes::GenericError; + resultData[1] = srvId; + resultLength = 2; + } -void RouterObject::functionRfEnableSbc(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -{ - if (isCommand) + void RouterObject::functionRfEnableSbc(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) { - _rfSbcRoutingEnabled = (data[0] == 1) ? true : false; - } + if (isCommand) + { + _rfSbcRoutingEnabled = (data[0] == 1) ? true : false; + } - resultData[0] = ReturnCodes::Success; - resultData[1] = _rfSbcRoutingEnabled ? 1 : 0; - resultLength = 2; -} + resultData[0] = ReturnCodes::Success; + resultData[1] = _rfSbcRoutingEnabled ? 1 : 0; + resultLength = 2; + } -bool RouterObject::isRfSbcRoutingEnabled() -{ + bool RouterObject::isRfSbcRoutingEnabled() + { #ifdef KNX_LOG_COUPLER - print("RouterObject::isRfSbcRoutingEnabled "); - println(_rfSbcRoutingEnabled); + print("RouterObject::isRfSbcRoutingEnabled "); + println(_rfSbcRoutingEnabled); #endif - return _rfSbcRoutingEnabled; -} + return _rfSbcRoutingEnabled; + } -// TODO: check if IP SBC works the same way, just copied from RF -void RouterObject::functionIpEnableSbc(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -{ + // TODO: check if IP SBC works the same way, just copied from RF + void RouterObject::functionIpEnableSbc(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) + { #ifdef KNX_LOG_COUPLER - print("RouterObject::functionIpEnableSbc "); - print(isCommand); - printHex(" ", data, length); + print("RouterObject::functionIpEnableSbc "); + print(isCommand); + printHex(" ", data, length); #endif - if (isCommand) - { - _ipSbcRoutingEnabled = (data[0] == 1) ? true : false; - } + if (isCommand) + { + _ipSbcRoutingEnabled = (data[0] == 1) ? true : false; + } - resultData[0] = ReturnCodes::Success; - resultData[1] = _ipSbcRoutingEnabled ? 1 : 0; - resultLength = 2; -} + resultData[0] = ReturnCodes::Success; + resultData[1] = _ipSbcRoutingEnabled ? 1 : 0; + resultLength = 2; + } -// TODO: check if IP SBC works the same way, just copied from RF -bool RouterObject::isIpSbcRoutingEnabled() -{ + // TODO: check if IP SBC works the same way, just copied from RF + bool RouterObject::isIpSbcRoutingEnabled() + { #ifdef KNX_LOG_COUPLER - print("RouterObject::isIpSbcRoutingEnabled "); - println(_ipSbcRoutingEnabled); + print("RouterObject::isIpSbcRoutingEnabled "); + println(_ipSbcRoutingEnabled); #endif - return _ipSbcRoutingEnabled; -} + return _ipSbcRoutingEnabled; + } -void RouterObject::beforeStateChange(LoadState& newState) -{ + void RouterObject::beforeStateChange(LoadState& newState) + { #ifdef KNX_LOG_COUPLER - println("RouterObject::beforeStateChange"); + println("RouterObject::beforeStateChange"); #endif - if (newState != LS_LOADED) - return; -} + if (newState != LS_LOADED) + return; + } -void RouterObject::masterReset(EraseCode eraseCode, uint8_t channel) -{ + void RouterObject::masterReset(EraseCode eraseCode, uint8_t channel) + { #ifdef KNX_LOG_COUPLER - print("RouterObject::masterReset "); - print(eraseCode); - print(" "); - println(channel); + print("RouterObject::masterReset "); + print(eraseCode); + print(" "); + println(channel); #endif - if (eraseCode == FactoryReset) - { - // TODO: handle different erase codes - println("Factory reset of router object with filter table requested."); + if (eraseCode == FactoryReset) + { + // TODO: handle different erase codes + println("Factory reset of router object with filter table requested."); + } } -} - -bool RouterObject::isGroupAddressInFilterTable(uint16_t groupAddress) -{ - if (loadState() != LS_LOADED) - return false; - - uint8_t filterTableUse = 0x01; - Property* propFilterTableUse = property(PID_FILTER_TABLE_USE); - if (propFilterTableUse) // check if property PID_FILTER_TABLE_USE exists (only coupler 20), if not, ignore this - if (propFilterTableUse->read(filterTableUse) == 0) // check if property PID_FILTER_TABLE_USE is empty, if so, return false + bool RouterObject::isGroupAddressInFilterTable(uint16_t groupAddress) + { + if (loadState() != LS_LOADED) return false; - if ((filterTableUse & 0x01) == 1) - { - uint8_t* filterTable = data(); - // octet_address = GA_value div 8 - // bit_position = GA_value mod 8 - uint16_t octetAddress = groupAddress / 8; - uint8_t bitPosition = groupAddress % 8; + uint8_t filterTableUse = 0x01; + Property* propFilterTableUse = property(PID_FILTER_TABLE_USE); + if (propFilterTableUse) // check if property PID_FILTER_TABLE_USE exists (only coupler 20), if not, ignore this + if (propFilterTableUse->read(filterTableUse) == 0) // check if property PID_FILTER_TABLE_USE is empty, if so, return false + return false; - if (filterTable) - return (filterTable[octetAddress] & (1 << bitPosition)) == (1 << bitPosition); - else + if ((filterTableUse & 0x01) == 1) { - println("RouterObject::isGroupAddressInFilterTable filterTable is NULL"); - return false; + uint8_t* filterTable = data(); + // octet_address = GA_value div 8 + // bit_position = GA_value mod 8 + uint16_t octetAddress = groupAddress / 8; + uint8_t bitPosition = groupAddress % 8; + + + if (filterTable) + return (filterTable[octetAddress] & (1 << bitPosition)) == (1 << bitPosition); + else + { + println("RouterObject::isGroupAddressInFilterTable filterTable is NULL"); + return false; + } } - } - return false; + return false; + } } \ No newline at end of file diff --git a/src/knx/coupler/router_object.h b/src/knx/coupler/router_object.h index 3ed7c7b1..ba2beffd 100644 --- a/src/knx/coupler/router_object.h +++ b/src/knx/coupler/router_object.h @@ -4,54 +4,57 @@ #include "../config.h" #include "../knx_types.h" -class Memory; - -enum CouplerModel -{ - Model_1x, - Model_20 -}; - -enum RouterObjectType +namespace Knx { - Primary, - Secondary, - Single // Not used, just a placeholder for better readability for coupler model 1.x -}; - -class RouterObject : public TableObject -{ - public: - RouterObject(Memory& memory, uint32_t staticTableAdr = 0, uint32_t staticTableSize = 0); - - void initialize1x(DptMedium mediumType, uint16_t maxApduSize); - void initialize20(uint8_t objIndex, DptMedium mediumType, RouterObjectType rtType, uint16_t maxApduSize); - void initialize(CouplerModel model, uint8_t objIndex, DptMedium mediumType, RouterObjectType rtType, uint16_t maxApduSize); - - bool isGroupAddressInFilterTable(uint16_t groupAddress); - - bool isRfSbcRoutingEnabled(); - bool isIpSbcRoutingEnabled(); - - void masterReset(EraseCode eraseCode, uint8_t channel) override; - - const uint8_t* restore(const uint8_t* buffer) override; - - protected: - void beforeStateChange(LoadState& newState) override; - - private: - // Function properties - void functionRouteTableControl(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength); - void functionRfEnableSbc(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength); - void functionIpEnableSbc(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength); - - void commandClearSetRoutingTable(bool bitIsSet); - bool statusClearSetRoutingTable(bool bitIsSet); - void commandClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet); - bool statusClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet); - - bool _rfSbcRoutingEnabled = false; - bool _ipSbcRoutingEnabled = false; - CouplerModel _model = CouplerModel::Model_20; -}; + class Memory; + + enum CouplerModel + { + Model_1x, + Model_20 + }; + + enum RouterObjectType + { + Primary, + Secondary, + Single // Not used, just a placeholder for better readability for coupler model 1.x + }; + + class RouterObject : public TableObject + { + public: + RouterObject(Memory& memory, uint32_t staticTableAdr = 0, uint32_t staticTableSize = 0); + + void initialize1x(DptMedium mediumType, uint16_t maxApduSize); + void initialize20(uint8_t objIndex, DptMedium mediumType, RouterObjectType rtType, uint16_t maxApduSize); + void initialize(CouplerModel model, uint8_t objIndex, DptMedium mediumType, RouterObjectType rtType, uint16_t maxApduSize); + + bool isGroupAddressInFilterTable(uint16_t groupAddress); + + bool isRfSbcRoutingEnabled(); + bool isIpSbcRoutingEnabled(); + + void masterReset(EraseCode eraseCode, uint8_t channel) override; + + const uint8_t* restore(const uint8_t* buffer) override; + + protected: + void beforeStateChange(LoadState& newState) override; + + private: + // Function properties + void functionRouteTableControl(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength); + void functionRfEnableSbc(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength); + void functionIpEnableSbc(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength); + + void commandClearSetRoutingTable(bool bitIsSet); + bool statusClearSetRoutingTable(bool bitIsSet); + void commandClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet); + bool statusClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet); + + bool _rfSbcRoutingEnabled = false; + bool _ipSbcRoutingEnabled = false; + CouplerModel _model = CouplerModel::Model_20; + }; +} \ No newline at end of file diff --git a/src/knx/data_secure/secure_application_layer.cpp b/src/knx/data_secure/secure_application_layer.cpp index ddf12daf..37a18bd7 100644 --- a/src/knx/data_secure/secure_application_layer.cpp +++ b/src/knx/data_secure/secure_application_layer.cpp @@ -24,1310 +24,1313 @@ #define ECB 0 #include "../util/aes.hpp" -static constexpr uint8_t kSecureDataPdu = 0; -static constexpr uint8_t kSecureSyncRequest = 2; -static constexpr uint8_t kSecureSyncResponse = 3; - -SecureApplicationLayer::SecureApplicationLayer(DeviceObject& deviceObj, SecurityInterfaceObject& secIfObj, BusAccessUnit& bau): - ApplicationLayer(bau), - _secIfObj(secIfObj), - _deviceObj(deviceObj) +namespace Knx { -} - -void SecureApplicationLayer::groupAddressTable(AddressTableObject& addrTable) -{ - _addrTab = &addrTable; -} - -/* from transport layer */ + static constexpr uint8_t kSecureDataPdu = 0; + static constexpr uint8_t kSecureSyncRequest = 2; + static constexpr uint8_t kSecureSyncResponse = 3; + + SecureApplicationLayer::SecureApplicationLayer(DeviceObject& deviceObj, SecurityInterfaceObject& secIfObj, BusAccessUnit& bau): + ApplicationLayer(bau), + _secIfObj(secIfObj), + _deviceObj(deviceObj) + { + } -void SecureApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) -{ - if (_addrTab == nullptr) - return; + void SecureApplicationLayer::groupAddressTable(AddressTableObject& addrTable) + { + _addrTab = &addrTable; + } - println("dataGroupIndication"); + /* from transport layer */ - if (apdu.type() == SecureService) + void SecureApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) { - // Will be filled in by decodeSecureApdu() - SecurityControl secCtrl; + if (_addrTab == nullptr) + return; - // Decrypt secure APDU - // Somehow ugly that we need to know the size in advance here at this point - uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) - CemiFrame plainFrame(plainApduLength); + println("dataGroupIndication"); - // Decrypt secure APDU - if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) + if (apdu.type() == SecureService) { - // Process decrypted inner APDU - ApplicationLayer::dataGroupIndication(hopType, priority, tsap, plainFrame.apdu(), secCtrl); - } + // Will be filled in by decodeSecureApdu() + SecurityControl secCtrl; - return; - } - - ApplicationLayer::dataGroupIndication(hopType, priority, tsap, apdu); -} + // Decrypt secure APDU + // Somehow ugly that we need to know the size in advance here at this point + uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) + CemiFrame plainFrame(plainApduLength); -void SecureApplicationLayer::dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status) -{ - println("dataGroupConfirm"); + // Decrypt secure APDU + if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) + { + // Process decrypted inner APDU + ApplicationLayer::dataGroupIndication(hopType, priority, tsap, plainFrame.apdu(), secCtrl); + } - if (apdu.type() == SecureService) - { - // We do not care about confirmations of our sync communication - if (isSyncService(apdu)) - { return; } - // Will be filled in by decodeSecureApdu() - SecurityControl secCtrl; + ApplicationLayer::dataGroupIndication(hopType, priority, tsap, apdu); + } - // Decrypt secure APDU - // Somehow ugly that we need to know the size in advance here at this point - uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) - CemiFrame plainFrame(plainApduLength); + void SecureApplicationLayer::dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status) + { + println("dataGroupConfirm"); - // Decrypt secure APDU - if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) + if (apdu.type() == SecureService) { - // Process decrypted inner APDU - ApplicationLayer::dataGroupConfirm(ack, hopType, priority, tsap, plainFrame.apdu(), secCtrl, status); - } - - return; - } - - ApplicationLayer::dataGroupConfirm(ack, hopType, priority, tsap, apdu, status); -} + // We do not care about confirmations of our sync communication + if (isSyncService(apdu)) + { + return; + } -void SecureApplicationLayer::dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) -{ - println("dataBroadcastIndication"); + // Will be filled in by decodeSecureApdu() + SecurityControl secCtrl; - if (apdu.type() == SecureService) - { - // Will be filled in by decodeSecureApdu() - SecurityControl secCtrl; + // Decrypt secure APDU + // Somehow ugly that we need to know the size in advance here at this point + uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) + CemiFrame plainFrame(plainApduLength); - // Decrypt secure APDU - // Somehow ugly that we need to know the size in advance here at this point - uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) - CemiFrame plainFrame(plainApduLength); + // Decrypt secure APDU + if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) + { + // Process decrypted inner APDU + ApplicationLayer::dataGroupConfirm(ack, hopType, priority, tsap, plainFrame.apdu(), secCtrl, status); + } - // Decrypt secure APDU - if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) - { - // Process decrypted inner APDU - ApplicationLayer::dataBroadcastIndication(hopType, priority, source, plainFrame.apdu(), secCtrl); + return; } - return; + ApplicationLayer::dataGroupConfirm(ack, hopType, priority, tsap, apdu, status); } - ApplicationLayer::dataBroadcastIndication(hopType, priority, source, apdu); -} - -void SecureApplicationLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, bool status) -{ - println("dataBroadcastConfirm"); - - if (apdu.type() == SecureService) + void SecureApplicationLayer::dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) { - // We do not care about confirmations of our sync communication - if (isSyncService(apdu)) + println("dataBroadcastIndication"); + + if (apdu.type() == SecureService) { - return; - } + // Will be filled in by decodeSecureApdu() + SecurityControl secCtrl; - // Will be filled in by decodeSecureApdu() - SecurityControl secCtrl; + // Decrypt secure APDU + // Somehow ugly that we need to know the size in advance here at this point + uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) + CemiFrame plainFrame(plainApduLength); - // Decrypt secure APDU - // Somehow ugly that we need to know the size in advance here at this point - uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) - CemiFrame plainFrame(plainApduLength); + // Decrypt secure APDU + if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) + { + // Process decrypted inner APDU + ApplicationLayer::dataBroadcastIndication(hopType, priority, source, plainFrame.apdu(), secCtrl); + } - // Decrypt secure APDU - if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) - { - // Process decrypted inner APDU - ApplicationLayer::dataBroadcastConfirm(ack, hopType, priority, plainFrame.apdu(), secCtrl, status); + return; } - return; + ApplicationLayer::dataBroadcastIndication(hopType, priority, source, apdu); } - ApplicationLayer::dataBroadcastConfirm(ack, hopType, priority, apdu, status); -} - -void SecureApplicationLayer::dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) -{ - println("dataSystemBroadcastIndication"); - - if (apdu.type() == SecureService) + void SecureApplicationLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, bool status) { - // Will be filled in by decodeSecureApdu() - SecurityControl secCtrl; + println("dataBroadcastConfirm"); - // Decrypt secure APDU - // Somehow ugly that we need to know the size in advance here at this point - uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) - CemiFrame plainFrame(plainApduLength); - - // Decrypt secure APDU - if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) + if (apdu.type() == SecureService) { - // Process decrypted inner APDU - ApplicationLayer::dataSystemBroadcastIndication(hopType, priority, source, plainFrame.apdu(), secCtrl); - } + // We do not care about confirmations of our sync communication + if (isSyncService(apdu)) + { + return; + } - return; - } + // Will be filled in by decodeSecureApdu() + SecurityControl secCtrl; - ApplicationLayer::dataSystemBroadcastIndication(hopType, priority, source, apdu); -} + // Decrypt secure APDU + // Somehow ugly that we need to know the size in advance here at this point + uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) + CemiFrame plainFrame(plainApduLength); -void SecureApplicationLayer::dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, bool status) -{ - println("dataSystemBroadcastConfirm"); + // Decrypt secure APDU + if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) + { + // Process decrypted inner APDU + ApplicationLayer::dataBroadcastConfirm(ack, hopType, priority, plainFrame.apdu(), secCtrl, status); + } - if (apdu.type() == SecureService) - { - // We do not care about confirmations of our sync communication - if (isSyncService(apdu)) - { return; } - // Will be filled in by decodeSecureApdu() - SecurityControl secCtrl; - - // Decrypt secure APDU - // Somehow ugly that we need to know the size in advance here at this point - uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) - CemiFrame plainFrame(plainApduLength); - - // Decrypt secure APDU - if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) - { - // Process decrypted inner APDU - ApplicationLayer::dataSystemBroadcastConfirm(hopType, priority, plainFrame.apdu(), secCtrl, status); - } - - return; + ApplicationLayer::dataBroadcastConfirm(ack, hopType, priority, apdu, status); } - ApplicationLayer::dataSystemBroadcastConfirm(hopType, priority, apdu, status); -} + void SecureApplicationLayer::dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) + { + println("dataSystemBroadcastIndication"); -void SecureApplicationLayer::dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) -{ - println("dataIndividualIndication"); + if (apdu.type() == SecureService) + { + // Will be filled in by decodeSecureApdu() + SecurityControl secCtrl; - if (apdu.type() == SecureService) - { - // Will be filled in by decodeSecureApdu() - SecurityControl secCtrl; + // Decrypt secure APDU + // Somehow ugly that we need to know the size in advance here at this point + uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) + CemiFrame plainFrame(plainApduLength); - // Decrypt secure APDU - // Somehow ugly that we need to know the size in advance here at this point - uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) - CemiFrame plainFrame(plainApduLength); + // Decrypt secure APDU + if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) + { + // Process decrypted inner APDU + ApplicationLayer::dataSystemBroadcastIndication(hopType, priority, source, plainFrame.apdu(), secCtrl); + } - // Decrypt secure APDU - if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) - { - // Process decrypted inner APDU - ApplicationLayer::dataIndividualIndication(hopType, priority, source, plainFrame.apdu(), secCtrl); + return; } - return; + ApplicationLayer::dataSystemBroadcastIndication(hopType, priority, source, apdu); } - ApplicationLayer::dataIndividualIndication(hopType, priority, source, apdu); -} - -void SecureApplicationLayer::dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, bool status) -{ - println("dataIndividualConfirm"); - - if (apdu.type() == SecureService) + void SecureApplicationLayer::dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, bool status) { - // We do not care about confirmations of our sync communication - if (isSyncService(apdu)) + println("dataSystemBroadcastConfirm"); + + if (apdu.type() == SecureService) { - return; - } + // We do not care about confirmations of our sync communication + if (isSyncService(apdu)) + { + return; + } - // Will be filled in by decodeSecureApdu() - SecurityControl secCtrl; + // Will be filled in by decodeSecureApdu() + SecurityControl secCtrl; - // Decrypt secure APDU - // Somehow ugly that we need to know the size in advance here at this point - uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) - CemiFrame plainFrame(plainApduLength); + // Decrypt secure APDU + // Somehow ugly that we need to know the size in advance here at this point + uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) + CemiFrame plainFrame(plainApduLength); - // Decrypt secure APDU - if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) - { - // Process decrypted inner APDU - ApplicationLayer::dataIndividualConfirm(ack, hopType, priority, source, apdu, secCtrl, status); + // Decrypt secure APDU + if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) + { + // Process decrypted inner APDU + ApplicationLayer::dataSystemBroadcastConfirm(hopType, priority, plainFrame.apdu(), secCtrl, status); + } + + return; } - return; + ApplicationLayer::dataSystemBroadcastConfirm(hopType, priority, apdu, status); } - else + + void SecureApplicationLayer::dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) { - ApplicationLayer::dataIndividualConfirm(ack, hopType, priority, source, apdu, status); - } -} + println("dataIndividualIndication"); -void SecureApplicationLayer::dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu) -{ - println("dataConnectedIndication"); + if (apdu.type() == SecureService) + { + // Will be filled in by decodeSecureApdu() + SecurityControl secCtrl; - if (apdu.type() == SecureService) - { - // Will be filled in by decodeSecureApdu() - SecurityControl secCtrl; + // Decrypt secure APDU + // Somehow ugly that we need to know the size in advance here at this point + uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) + CemiFrame plainFrame(plainApduLength); - // Decrypt secure APDU - // Somehow ugly that we need to know the size in advance here at this point - uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) - CemiFrame plainFrame(plainApduLength); + // Decrypt secure APDU + if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) + { + // Process decrypted inner APDU + ApplicationLayer::dataIndividualIndication(hopType, priority, source, plainFrame.apdu(), secCtrl); + } - // Decrypt secure APDU - if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) - { - // Process decrypted inner APDU - ApplicationLayer::dataConnectedIndication(priority, tsap, plainFrame.apdu(), secCtrl); + return; } - return; + ApplicationLayer::dataIndividualIndication(hopType, priority, source, apdu); } - ApplicationLayer::dataConnectedIndication(priority, tsap, apdu); -} - -void SecureApplicationLayer::dataConnectedConfirm(uint16_t tsap) -{ - // Just the confirmation issued by the transport layer in case of T_DATA_CONNECTED - ApplicationLayer::dataConnectedConfirm(tsap); -} - -/* to transport layer */ + void SecureApplicationLayer::dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, bool status) + { + println("dataIndividualConfirm"); -void SecureApplicationLayer::dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) -{ - if (_addrTab == nullptr) - return; + if (apdu.type() == SecureService) + { + // We do not care about confirmations of our sync communication + if (isSyncService(apdu)) + { + return; + } - println("dataGroupRequest"); + // Will be filled in by decodeSecureApdu() + SecurityControl secCtrl; - if (secCtrl.dataSecurity != DataSecurity::None) - { - apdu.frame().sourceAddress(_deviceObj.individualAddress()); - apdu.frame().destinationAddress(_addrTab->getGroupAddress(tsap)); - apdu.frame().addressType(GroupAddress); + // Decrypt secure APDU + // Somehow ugly that we need to know the size in advance here at this point + uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) + CemiFrame plainFrame(plainApduLength); - uint16_t secureApduLength = apdu.length() + 3 + 6 + 4; // 3(TPCI,APCI,SCF) + sizeof(seqNum) + apdu.length() + 4 - CemiFrame secureFrame(secureApduLength); + // Decrypt secure APDU + if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) + { + // Process decrypted inner APDU + ApplicationLayer::dataIndividualConfirm(ack, hopType, priority, source, apdu, secCtrl, status); + } - // create secure APDU - if (createSecureApdu(apdu, secureFrame.apdu(), secCtrl)) + return; + } + else { - ApplicationLayer::dataGroupRequest(ack, hopType, priority, tsap, secureFrame.apdu(), secCtrl); + ApplicationLayer::dataIndividualConfirm(ack, hopType, priority, source, apdu, status); } - - return; } - ApplicationLayer::dataGroupRequest(ack, hopType, priority, tsap, apdu, secCtrl); -} + void SecureApplicationLayer::dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu) + { + println("dataConnectedIndication"); -void SecureApplicationLayer::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl) -{ - println("dataBroadcastRequest"); + if (apdu.type() == SecureService) + { + // Will be filled in by decodeSecureApdu() + SecurityControl secCtrl; - if (secCtrl.dataSecurity != DataSecurity::None) - { - apdu.frame().sourceAddress(_deviceObj.individualAddress()); - apdu.frame().destinationAddress(0x0000); - apdu.frame().addressType(GroupAddress); - apdu.frame().systemBroadcast(Broadcast); + // Decrypt secure APDU + // Somehow ugly that we need to know the size in advance here at this point + uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac) + CemiFrame plainFrame(plainApduLength); - uint16_t secureApduLength = apdu.length() + 3 + 6 + 4; // 3(TPCI,APCI,SCF) + sizeof(seqNum) + apdu.length() + 4 - CemiFrame secureFrame(secureApduLength); + // Decrypt secure APDU + if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl)) + { + // Process decrypted inner APDU + ApplicationLayer::dataConnectedIndication(priority, tsap, plainFrame.apdu(), secCtrl); + } - // create secure APDU - if (createSecureApdu(apdu, secureFrame.apdu(), secCtrl)) - { - ApplicationLayer::dataBroadcastRequest(ack, hopType, SystemPriority, secureFrame.apdu(), secCtrl); + return; } - return; + ApplicationLayer::dataConnectedIndication(priority, tsap, apdu); } - ApplicationLayer::dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); -} + void SecureApplicationLayer::dataConnectedConfirm(uint16_t tsap) + { + // Just the confirmation issued by the transport layer in case of T_DATA_CONNECTED + ApplicationLayer::dataConnectedConfirm(tsap); + } -void SecureApplicationLayer::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl) -{ - println("dataSystemBroadcastRequest"); + /* to transport layer */ - if (secCtrl.dataSecurity != DataSecurity::None) + void SecureApplicationLayer::dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) { - apdu.frame().sourceAddress(_deviceObj.individualAddress()); - apdu.frame().destinationAddress(0x0000); - apdu.frame().addressType(GroupAddress); - apdu.frame().systemBroadcast(SysBroadcast); + if (_addrTab == nullptr) + return; - uint16_t secureApduLength = apdu.length() + 3 + 6 + 4; // 3(TPCI,APCI,SCF) + sizeof(seqNum) + apdu.length() + 4 - CemiFrame secureFrame(secureApduLength); + println("dataGroupRequest"); - // create secure APDU - if (createSecureApdu(apdu, secureFrame.apdu(), secCtrl)) + if (secCtrl.dataSecurity != DataSecurity::None) { - ApplicationLayer::dataSystemBroadcastRequest(ack, hopType, SystemPriority, secureFrame.apdu(), secCtrl); + apdu.frame().sourceAddress(_deviceObj.individualAddress()); + apdu.frame().destinationAddress(_addrTab->getGroupAddress(tsap)); + apdu.frame().addressType(GroupAddress); + + uint16_t secureApduLength = apdu.length() + 3 + 6 + 4; // 3(TPCI,APCI,SCF) + sizeof(seqNum) + apdu.length() + 4 + CemiFrame secureFrame(secureApduLength); + + // create secure APDU + if (createSecureApdu(apdu, secureFrame.apdu(), secCtrl)) + { + ApplicationLayer::dataGroupRequest(ack, hopType, priority, tsap, secureFrame.apdu(), secCtrl); + } + + return; } - return; + ApplicationLayer::dataGroupRequest(ack, hopType, priority, tsap, apdu, secCtrl); } - ApplicationLayer::dataSystemBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); -} + void SecureApplicationLayer::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl) + { + println("dataBroadcastRequest"); -void SecureApplicationLayer::dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu, const SecurityControl& secCtrl) -{ - println("dataIndividualRequest"); + if (secCtrl.dataSecurity != DataSecurity::None) + { + apdu.frame().sourceAddress(_deviceObj.individualAddress()); + apdu.frame().destinationAddress(0x0000); + apdu.frame().addressType(GroupAddress); + apdu.frame().systemBroadcast(Broadcast); - if (secCtrl.dataSecurity != DataSecurity::None) - { - apdu.frame().sourceAddress(_deviceObj.individualAddress()); - apdu.frame().destinationAddress(destination); - apdu.frame().addressType(IndividualAddress); + uint16_t secureApduLength = apdu.length() + 3 + 6 + 4; // 3(TPCI,APCI,SCF) + sizeof(seqNum) + apdu.length() + 4 + CemiFrame secureFrame(secureApduLength); - uint16_t secureApduLength = apdu.length() + 3 + 6 + 4; // 3(TPCI,APCI,SCF) + sizeof(seqNum) + apdu.length() + 4 - CemiFrame secureFrame(secureApduLength); + // create secure APDU + if (createSecureApdu(apdu, secureFrame.apdu(), secCtrl)) + { + ApplicationLayer::dataBroadcastRequest(ack, hopType, SystemPriority, secureFrame.apdu(), secCtrl); + } - // create secure APDU - if (createSecureApdu(apdu, secureFrame.apdu(), secCtrl)) - { - ApplicationLayer::dataIndividualRequest(ack, hopType, priority, destination, secureFrame.apdu(), secCtrl); + return; } - return; + ApplicationLayer::dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); } - ApplicationLayer::dataIndividualRequest(ack, hopType, priority, destination, apdu, secCtrl); -} + void SecureApplicationLayer::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl) + { + println("dataSystemBroadcastRequest"); -void SecureApplicationLayer::dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu, const SecurityControl& secCtrl) -{ - println("dataConnectedRequest"); + if (secCtrl.dataSecurity != DataSecurity::None) + { + apdu.frame().sourceAddress(_deviceObj.individualAddress()); + apdu.frame().destinationAddress(0x0000); + apdu.frame().addressType(GroupAddress); + apdu.frame().systemBroadcast(SysBroadcast); - if (secCtrl.dataSecurity != DataSecurity::None) - { - apdu.frame().sourceAddress(_deviceObj.individualAddress()); - apdu.frame().destinationAddress(_transportLayer->getConnectionAddress()); - apdu.frame().addressType(IndividualAddress); + uint16_t secureApduLength = apdu.length() + 3 + 6 + 4; // 3(TPCI,APCI,SCF) + sizeof(seqNum) + apdu.length() + 4 + CemiFrame secureFrame(secureApduLength); - uint16_t secureApduLength = apdu.length() + 3 + 6 + 4; // 3(TPCI,APCI,SCF) + sizeof(seqNum) + apdu.length() + 4 - CemiFrame secureFrame(secureApduLength); + // create secure APDU + if (createSecureApdu(apdu, secureFrame.apdu(), secCtrl)) + { + ApplicationLayer::dataSystemBroadcastRequest(ack, hopType, SystemPriority, secureFrame.apdu(), secCtrl); + } - // create secure APDU - if (createSecureApdu(apdu, secureFrame.apdu(), secCtrl)) - { - ApplicationLayer::dataConnectedRequest(tsap, priority, secureFrame.apdu(), secCtrl); + return; } - return; + ApplicationLayer::dataSystemBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); } - // apdu must be valid until it was confirmed - ApplicationLayer::dataConnectedRequest(tsap, priority, apdu, secCtrl); -} - -void SecureApplicationLayer::encryptAesCbc(uint8_t* buffer, uint16_t bufLen, const uint8_t* iv, const uint8_t* key) -{ - // Use zeroes as IV for first round - uint8_t zeroIv[16] = {0x00}; - - struct AES_ctx ctx; - AES_init_ctx_iv(&ctx, key, zeroIv); + void SecureApplicationLayer::dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu, const SecurityControl& secCtrl) + { + println("dataIndividualRequest"); - // Now encrypt first block B0. - AES_CBC_encrypt_buffer(&ctx, (uint8_t*) iv, 16); + if (secCtrl.dataSecurity != DataSecurity::None) + { + apdu.frame().sourceAddress(_deviceObj.individualAddress()); + apdu.frame().destinationAddress(destination); + apdu.frame().addressType(IndividualAddress); - // Encrypt remaining buffer - AES_CBC_encrypt_buffer(&ctx, buffer, bufLen); -} + uint16_t secureApduLength = apdu.length() + 3 + 6 + 4; // 3(TPCI,APCI,SCF) + sizeof(seqNum) + apdu.length() + 4 + CemiFrame secureFrame(secureApduLength); -void SecureApplicationLayer::xcryptAesCtr(uint8_t* buffer, uint16_t bufLen, const uint8_t* iv, const uint8_t* key) -{ - struct AES_ctx ctx; + // create secure APDU + if (createSecureApdu(apdu, secureFrame.apdu(), secCtrl)) + { + ApplicationLayer::dataIndividualRequest(ack, hopType, priority, destination, secureFrame.apdu(), secCtrl); + } - AES_init_ctx_iv(&ctx, key, iv); + return; + } - AES_CTR_xcrypt_buffer(&ctx, buffer, bufLen); -} + ApplicationLayer::dataIndividualRequest(ack, hopType, priority, destination, apdu, secCtrl); + } -uint32_t SecureApplicationLayer::calcAuthOnlyMac(uint8_t* apdu, uint8_t apduLength, const uint8_t* key, uint8_t* iv, uint8_t* ctr0) -{ - uint16_t bufLen = 2 + apduLength; // 2 bytes for the length field (uint16_t) - // AES-128 operates on blocks of 16 bytes, add padding - uint16_t bufLenPadded = (bufLen + 15) / 16 * 16; - uint8_t buffer[bufLenPadded]; - // Make sure to have zeroes everywhere, because of the padding - memset(buffer, 0x00, bufLenPadded); + void SecureApplicationLayer::dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu, const SecurityControl& secCtrl) + { + println("dataConnectedRequest"); - uint8_t* pBuf = buffer; + if (secCtrl.dataSecurity != DataSecurity::None) + { + apdu.frame().sourceAddress(_deviceObj.individualAddress()); + apdu.frame().destinationAddress(_transportLayer->getConnectionAddress()); + apdu.frame().addressType(IndividualAddress); - pBuf = pushWord(apduLength, pBuf); - pBuf = pushByteArray(apdu, apduLength, pBuf); + uint16_t secureApduLength = apdu.length() + 3 + 6 + 4; // 3(TPCI,APCI,SCF) + sizeof(seqNum) + apdu.length() + 4 + CemiFrame secureFrame(secureApduLength); - encryptAesCbc(buffer, bufLenPadded, iv, key); - xcryptAesCtr(buffer, 4, ctr0, key); // 4 bytes only for the MAC + // create secure APDU + if (createSecureApdu(apdu, secureFrame.apdu(), secCtrl)) + { + ApplicationLayer::dataConnectedRequest(tsap, priority, secureFrame.apdu(), secCtrl); + } - uint32_t mac; - popInt(mac, &buffer[0]); + return; + } - return mac; -} + // apdu must be valid until it was confirmed + ApplicationLayer::dataConnectedRequest(tsap, priority, apdu, secCtrl); + } -uint32_t SecureApplicationLayer::calcConfAuthMac(uint8_t* associatedData, uint16_t associatedDataLength, - uint8_t* apdu, uint8_t apduLength, - const uint8_t* key, uint8_t* iv) -{ - uint16_t bufLen = 2 + associatedDataLength + apduLength; // 2 bytes for the length field (uint16_t) - // AES-128 operates on blocks of 16 bytes, add padding - uint16_t bufLenPadded = (bufLen + 15) / 16 * 16; - uint8_t buffer[bufLenPadded]; - // Make sure to have zeroes everywhere, because of the padding - memset(buffer, 0x00, bufLenPadded); + void SecureApplicationLayer::encryptAesCbc(uint8_t* buffer, uint16_t bufLen, const uint8_t* iv, const uint8_t* key) + { + // Use zeroes as IV for first round + uint8_t zeroIv[16] = {0x00}; - uint8_t* pBuf = buffer; + struct AES_ctx ctx; + AES_init_ctx_iv(&ctx, key, zeroIv); - pBuf = pushWord(associatedDataLength, pBuf); - pBuf = pushByteArray(associatedData, associatedDataLength, pBuf); - pBuf = pushByteArray(apdu, apduLength, pBuf); + // Now encrypt first block B0. + AES_CBC_encrypt_buffer(&ctx, (uint8_t*) iv, 16); - encryptAesCbc(buffer, bufLenPadded, iv, key); + // Encrypt remaining buffer + AES_CBC_encrypt_buffer(&ctx, buffer, bufLen); + } - uint32_t mac; - popInt(mac, &buffer[bufLenPadded - 16]); // bufLenPadded has a guaranteed minimum size of 16 bytes + void SecureApplicationLayer::xcryptAesCtr(uint8_t* buffer, uint16_t bufLen, const uint8_t* iv, const uint8_t* key) + { + struct AES_ctx ctx; - return mac; -} + AES_init_ctx_iv(&ctx, key, iv); -void SecureApplicationLayer::block0(uint8_t* buffer, uint8_t* seqNum, uint16_t indSrcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, uint8_t extFrameFormat, uint8_t tpci, uint8_t apci, uint8_t payloadLength) -{ - uint8_t* pBuf = buffer; - pBuf = pushByteArray(seqNum, 6, pBuf); - pBuf = pushWord(indSrcAddr, pBuf); - pBuf = pushWord(dstAddr, pBuf); - pBuf = pushByte(0x00, pBuf); // FT: frametype - pBuf = pushByte( (dstAddrIsGroupAddr ? 0x80 : 0x00) | (extFrameFormat & 0xf), pBuf); // AT: address type - pBuf = pushByte(tpci, pBuf); // TPCI - pBuf = pushByte(apci, pBuf); // APCI // draft spec shows something different! - pBuf = pushByte(0x00, pBuf); // Reserved: fixed 0x00 (really?) - pBuf = pushByte(payloadLength, pBuf); // Payload length -} + AES_CTR_xcrypt_buffer(&ctx, buffer, bufLen); + } -void SecureApplicationLayer::blockCtr0(uint8_t* buffer, uint8_t* seqNum, uint16_t indSrcAddr, uint16_t dstAddr) -{ - uint8_t* pBuf = buffer; - pBuf = pushByteArray(seqNum, 6, pBuf); - pBuf = pushWord(indSrcAddr, pBuf); - pBuf = pushWord(dstAddr, pBuf); - pBuf = pushInt(0x00000000, pBuf); - pBuf = pushByte(0x01, pBuf); -} + uint32_t SecureApplicationLayer::calcAuthOnlyMac(uint8_t* apdu, uint8_t apduLength, const uint8_t* key, uint8_t* iv, uint8_t* ctr0) + { + uint16_t bufLen = 2 + apduLength; // 2 bytes for the length field (uint16_t) + // AES-128 operates on blocks of 16 bytes, add padding + uint16_t bufLenPadded = (bufLen + 15) / 16 * 16; + uint8_t buffer[bufLenPadded]; + // Make sure to have zeroes everywhere, because of the padding + memset(buffer, 0x00, bufLenPadded); -uint16_t SecureApplicationLayer::groupAddressIndex(uint16_t groupAddr) -{ - // Just for safety reasons, we should never get here, because the dataGroupIndication will return already return early without doing anything - if (_addrTab == nullptr) - return 0; + uint8_t* pBuf = buffer; - return _addrTab->getTsap(groupAddr); -} + pBuf = pushWord(apduLength, pBuf); + pBuf = pushByteArray(apdu, apduLength, pBuf); -const uint8_t* SecureApplicationLayer::securityKey(uint16_t addr, bool isGroupAddress) -{ - if (isGroupAddress) - { - uint16_t gaIndex = groupAddressIndex(addr); + encryptAesCbc(buffer, bufLenPadded, iv, key); + xcryptAesCtr(buffer, 4, ctr0, key); // 4 bytes only for the MAC - if (gaIndex > 0) - return _secIfObj.groupKey(gaIndex); - } - else - { - uint16_t iaIndex = _secIfObj.indAddressIndex(addr); + uint32_t mac; + popInt(mac, &buffer[0]); - if (iaIndex > 0) - return _secIfObj.p2pKey(iaIndex); + return mac; } - return nullptr; -} + uint32_t SecureApplicationLayer::calcConfAuthMac(uint8_t* associatedData, uint16_t associatedDataLength, + uint8_t* apdu, uint8_t apduLength, + const uint8_t* key, uint8_t* iv) + { + uint16_t bufLen = 2 + associatedDataLength + apduLength; // 2 bytes for the length field (uint16_t) + // AES-128 operates on blocks of 16 bytes, add padding + uint16_t bufLenPadded = (bufLen + 15) / 16 * 16; + uint8_t buffer[bufLenPadded]; + // Make sure to have zeroes everywhere, because of the padding + memset(buffer, 0x00, bufLenPadded); -// returns next outgoing sequence number for secure communication -uint64_t SecureApplicationLayer::nextSequenceNumber(bool toolAccess) -{ - return toolAccess ? _sequenceNumberToolAccess : _sequenceNumber; -} + uint8_t* pBuf = buffer; -// stores next outgoing sequence number for secure communication -void SecureApplicationLayer::updateSequenceNumber(bool toolAccess, uint64_t seqNum) -{ - if (toolAccess) - { - _sequenceNumberToolAccess = seqNum; - } - else - { - _sequenceNumber = seqNum; - } + pBuf = pushWord(associatedDataLength, pBuf); + pBuf = pushByteArray(associatedData, associatedDataLength, pBuf); + pBuf = pushByteArray(apdu, apduLength, pBuf); - // Also update the properties accordingly - _secIfObj.setSequenceNumber(toolAccess, seqNum); -} + encryptAesCbc(buffer, bufLenPadded, iv, key); -uint64_t SecureApplicationLayer::lastValidSequenceNumber(bool toolAccess, uint16_t srcAddr) -{ - if (toolAccess) - { - // TODO: check if we really have to support multiple tools at the same time - if (srcAddr == _deviceObj.individualAddress()) - return _sequenceNumberToolAccess; + uint32_t mac; + popInt(mac, &buffer[bufLenPadded - 16]); // bufLenPadded has a guaranteed minimum size of 16 bytes - return _lastValidSequenceNumberTool; + return mac; } - else + + void SecureApplicationLayer::block0(uint8_t* buffer, uint8_t* seqNum, uint16_t indSrcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, uint8_t extFrameFormat, uint8_t tpci, uint8_t apci, uint8_t payloadLength) { - return _secIfObj.getLastValidSequenceNumber(srcAddr); + uint8_t* pBuf = buffer; + pBuf = pushByteArray(seqNum, 6, pBuf); + pBuf = pushWord(indSrcAddr, pBuf); + pBuf = pushWord(dstAddr, pBuf); + pBuf = pushByte(0x00, pBuf); // FT: frametype + pBuf = pushByte( (dstAddrIsGroupAddr ? 0x80 : 0x00) | (extFrameFormat & 0xf), pBuf); // AT: address type + pBuf = pushByte(tpci, pBuf); // TPCI + pBuf = pushByte(apci, pBuf); // APCI // draft spec shows something different! + pBuf = pushByte(0x00, pBuf); // Reserved: fixed 0x00 (really?) + pBuf = pushByte(payloadLength, pBuf); // Payload length } - return 0; -} - -void SecureApplicationLayer::updateLastValidSequence(bool toolAccess, uint16_t remoteAddr, uint64_t seqNo) -{ - if (toolAccess) - // TODO: check if we really have to support multiple tools at the same time - _lastValidSequenceNumberTool = seqNo; - else + void SecureApplicationLayer::blockCtr0(uint8_t* buffer, uint8_t* seqNum, uint16_t indSrcAddr, uint16_t dstAddr) { - _secIfObj.setLastValidSequenceNumber(remoteAddr, seqNo); + uint8_t* pBuf = buffer; + pBuf = pushByteArray(seqNum, 6, pBuf); + pBuf = pushWord(indSrcAddr, pBuf); + pBuf = pushWord(dstAddr, pBuf); + pBuf = pushInt(0x00000000, pBuf); + pBuf = pushByte(0x01, pBuf); } -} -void SecureApplicationLayer::sendSyncRequest(uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl& secCtrl, bool systemBcast) -{ - if (secCtrl.dataSecurity != DataSecurity::AuthConf) + uint16_t SecureApplicationLayer::groupAddressIndex(uint16_t groupAddr) { - println("sync.req is always sent with auth+conf!"); - return; + // Just for safety reasons, we should never get here, because the dataGroupIndication will return already return early without doing anything + if (_addrTab == nullptr) + return 0; + + return _addrTab->getTsap(groupAddr); } - _syncReqBroadcastOutgoing = (dstAddr == 0x0000) && dstAddrIsGroupAddr; + const uint8_t* SecureApplicationLayer::securityKey(uint16_t addr, bool isGroupAddress) + { + if (isGroupAddress) + { + uint16_t gaIndex = groupAddressIndex(addr); - // use random number in SyncResponse - uint64_t challenge = getRandomNumber(); + if (gaIndex > 0) + return _secIfObj.groupKey(gaIndex); + } + else + { + uint16_t iaIndex = _secIfObj.indAddressIndex(addr); - uint8_t asdu[6]; - sixBytesFromUInt64(challenge, &asdu[0]); + if (iaIndex > 0) + return _secIfObj.p2pKey(iaIndex); + } - CemiFrame request(2 + 6 + sizeof(asdu) + 4); // 2 bytes (APCI, SCF) + 6 bytes (SeqNum) + 6 bytes (challenge) + 4 bytes (MAC) - // Note: additional TPCI byte is already handled internally! + return nullptr; + } - uint8_t tpci = 0; + // returns next outgoing sequence number for secure communication + uint64_t SecureApplicationLayer::nextSequenceNumber(bool toolAccess) + { + return toolAccess ? _sequenceNumberToolAccess : _sequenceNumber; + } - if (!_syncReqBroadcastOutgoing) + // stores next outgoing sequence number for secure communication + void SecureApplicationLayer::updateSequenceNumber(bool toolAccess, uint64_t seqNum) { - if (isConnected()) + if (toolAccess) { - tpci |= 0x40 | _transportLayer->getTpciSeqNum(); // get next TPCI sequence number for MAC calculation from TL (T_DATA_CONNECTED) + _sequenceNumberToolAccess = seqNum; + } + else + { + _sequenceNumber = seqNum; } - } - print("sendSyncRequest: TPCI: "); - println(tpci, HEX); + // Also update the properties accordingly + _secIfObj.setSequenceNumber(toolAccess, seqNum); + } - if (secure(request.data() + APDU_LPDU_DIFF, kSecureSyncRequest, _deviceObj.individualAddress(), dstAddr, dstAddrIsGroupAddr, tpci, asdu, sizeof(asdu), secCtrl, systemBcast)) + uint64_t SecureApplicationLayer::lastValidSequenceNumber(bool toolAccess, uint16_t srcAddr) { - LOGGER.info("SyncRequest: ", request.apdu()); - - if (_syncReqBroadcastOutgoing) + if (toolAccess) { - _transportLayer->dataBroadcastRequest(AckType::AckDontCare, HopCountType::NetworkLayerParameter, Priority::SystemPriority, request.apdu()); + // TODO: check if we really have to support multiple tools at the same time + if (srcAddr == _deviceObj.individualAddress()) + return _sequenceNumberToolAccess; + + return _lastValidSequenceNumberTool; } else { - // either send on T_DATA_INDIVIDUAL or T_DATA_CONNECTED - if (isConnected()) - { - _transportLayer->dataConnectedRequest(getConnectedTsasp(), SystemPriority, request.apdu()); - } - else - { - // Send encrypted SyncResponse message using T_DATA_INDIVIDUAL - _transportLayer->dataIndividualRequest(AckType::AckDontCare, NetworkLayerParameter, SystemPriority, dstAddr, request.apdu()); - } + return _secIfObj.getLastValidSequenceNumber(srcAddr); } - Addr toAddr = _syncReqBroadcastOutgoing ? (Addr)GrpAddr(0) : (Addr)IndAddr(dstAddr); - _pendingOutgoingSyncRequests.insertOrAssign(toAddr, challenge); + return 0; } - else + + void SecureApplicationLayer::updateLastValidSequence(bool toolAccess, uint16_t remoteAddr, uint64_t seqNo) { - println("SyncRequest: failure during encryption"); + if (toolAccess) + // TODO: check if we really have to support multiple tools at the same time + _lastValidSequenceNumberTool = seqNo; + else + { + _secIfObj.setLastValidSequenceNumber(remoteAddr, seqNo); + } } -} -void SecureApplicationLayer::sendSyncResponse(uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl& secCtrl, uint64_t remoteNextSeqNum, bool systemBcast) -{ - if (secCtrl.dataSecurity != DataSecurity::AuthConf) + void SecureApplicationLayer::sendSyncRequest(uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl& secCtrl, bool systemBcast) { - println("sync.res is always sent with auth+conf!"); - return; - } + if (secCtrl.dataSecurity != DataSecurity::AuthConf) + { + println("sync.req is always sent with auth+conf!"); + return; + } - uint64_t ourNextSeqNum = nextSequenceNumber(secCtrl.toolAccess); + _syncReqBroadcastOutgoing = (dstAddr == 0x0000) && dstAddrIsGroupAddr; - uint8_t asdu[12]; - sixBytesFromUInt64(ourNextSeqNum, &asdu[0]); - sixBytesFromUInt64(remoteNextSeqNum, &asdu[6]); + // use random number in SyncResponse + uint64_t challenge = getRandomNumber(); - CemiFrame response(2 + 6 + sizeof(asdu) + 4); // 2 bytes (APCI, SCF) + 6 bytes (SeqNum) + 12 bytes + 4 bytes (MAC) - // Note: additional TPCI byte is already handled internally! + uint8_t asdu[6]; + sixBytesFromUInt64(challenge, &asdu[0]); - uint8_t tpci = 0; + CemiFrame request(2 + 6 + sizeof(asdu) + 4); // 2 bytes (APCI, SCF) + 6 bytes (SeqNum) + 6 bytes (challenge) + 4 bytes (MAC) + // Note: additional TPCI byte is already handled internally! - if (!_syncReqBroadcastIncoming) - { - if (isConnected()) + uint8_t tpci = 0; + + if (!_syncReqBroadcastOutgoing) { - tpci |= 0x40 | _transportLayer->getTpciSeqNum(); // get next TPCI sequence number for MAC calculation from TL (T_DATA_CONNECTED) + if (isConnected()) + { + tpci |= 0x40 | _transportLayer->getTpciSeqNum(); // get next TPCI sequence number for MAC calculation from TL (T_DATA_CONNECTED) + } } - } - - print("sendSyncResponse: TPCI: "); - println(tpci, HEX); - - if (secure(response.data() + APDU_LPDU_DIFF, kSecureSyncResponse, _deviceObj.individualAddress(), dstAddr, dstAddrIsGroupAddr, tpci, asdu, sizeof(asdu), secCtrl, systemBcast)) - { - _lastSyncRes = millis(); - LOGGER.info("SyncResponse: ", response.apdu()); + print("sendSyncRequest: TPCI: "); + println(tpci, HEX); - if (_syncReqBroadcastIncoming) + if (secure(request.data() + APDU_LPDU_DIFF, kSecureSyncRequest, _deviceObj.individualAddress(), dstAddr, dstAddrIsGroupAddr, tpci, asdu, sizeof(asdu), secCtrl, systemBcast)) { - _transportLayer->dataBroadcastRequest(AckType::AckDontCare, HopCountType::NetworkLayerParameter, Priority::SystemPriority, response.apdu()); - } - else - { - // either send on T_DATA_INDIVIDUAL or T_DATA_CONNECTED - if (isConnected()) + LOGGER.info("SyncRequest: ", request.apdu()); + + if (_syncReqBroadcastOutgoing) { - _transportLayer->dataConnectedRequest(getConnectedTsasp(), SystemPriority, response.apdu()); + _transportLayer->dataBroadcastRequest(AckType::AckDontCare, HopCountType::NetworkLayerParameter, Priority::SystemPriority, request.apdu()); } else { - // Send encrypted SyncResponse message using T_DATA_INDIVIDUAL - _transportLayer->dataIndividualRequest(AckType::AckDontCare, NetworkLayerParameter, SystemPriority, dstAddr, response.apdu()); + // either send on T_DATA_INDIVIDUAL or T_DATA_CONNECTED + if (isConnected()) + { + _transportLayer->dataConnectedRequest(getConnectedTsasp(), SystemPriority, request.apdu()); + } + else + { + // Send encrypted SyncResponse message using T_DATA_INDIVIDUAL + _transportLayer->dataIndividualRequest(AckType::AckDontCare, NetworkLayerParameter, SystemPriority, dstAddr, request.apdu()); + } } - } - } - else - { - println("SyncResponse: failure during encryption"); - } -} - -void SecureApplicationLayer::receivedSyncRequest(uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl& secCtrl, uint8_t* seqNum, uint64_t challenge, bool systemBcast) -{ - println("Received SyncRequest:"); - - uint64_t nextRemoteSeqNum = sixBytesToUInt64(seqNum); - uint64_t nextSeqNum = 1 + lastValidSequenceNumber(secCtrl.toolAccess, srcAddr); - - if (nextRemoteSeqNum > nextSeqNum) - { - updateLastValidSequence(secCtrl.toolAccess, srcAddr, nextRemoteSeqNum - 1); - nextSeqNum = nextRemoteSeqNum; - } - - _syncReqBroadcastIncoming = (dstAddr == 0x0000) && dstAddrIsGroupAddr; - // Remember challenge for securing the sync.res later - _pendingIncomingSyncRequests.insertOrAssign(_syncReqBroadcastIncoming ? (Addr) GrpAddr(0) : (Addr) IndAddr(srcAddr), challenge); - - uint16_t toAddr = _syncReqBroadcastIncoming ? dstAddr : srcAddr; - bool toIsGroupAddress = _syncReqBroadcastIncoming; - sendSyncResponse(toAddr, toIsGroupAddress, secCtrl, nextSeqNum, systemBcast); -} - -void SecureApplicationLayer::receivedSyncResponse(uint16_t remote, const SecurityControl& secCtrl, uint8_t* plainApdu) -{ - println("Received SyncResponse:"); - - if (_syncReqBroadcastOutgoing) - { - if (_pendingOutgoingSyncRequests.get(GrpAddr(0)) == nullptr) + Addr toAddr = _syncReqBroadcastOutgoing ? (Addr)GrpAddr(0) : (Addr)IndAddr(dstAddr); + _pendingOutgoingSyncRequests.insertOrAssign(toAddr, challenge); + } + else { - println("Cannot handle sync.res without pending sync.req! (broadcast/systembroadcast)"); - return; + println("SyncRequest: failure during encryption"); } } - else + + void SecureApplicationLayer::sendSyncResponse(uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl& secCtrl, uint64_t remoteNextSeqNum, bool systemBcast) { - if (_pendingOutgoingSyncRequests.get(IndAddr(remote)) == nullptr) + if (secCtrl.dataSecurity != DataSecurity::AuthConf) { - println("Cannot handle sync.res without pending sync.req!"); + println("sync.res is always sent with auth+conf!"); return; } - } - // Bytes 0-5 in the "APDU" buffer contain the remote sequence number - // Bytes 6-11 in the "APDU" buffer contain the local sequence number - uint64_t remoteSeq = sixBytesToUInt64(plainApdu + 0); - uint64_t localSeq = sixBytesToUInt64(plainApdu + 6); + uint64_t ourNextSeqNum = nextSequenceNumber(secCtrl.toolAccess); - uint64_t last = lastValidSequenceNumber(secCtrl.toolAccess, remote); - - if (remoteSeq - 1 > last) - { - //logger.debug("sync.res update {} last valid {} seq -> {}", remote, toolAccess ? "tool access" : "p2p", remoteSeq -1); - updateLastValidSequence(secCtrl.toolAccess, remote, remoteSeq - 1); - } + uint8_t asdu[12]; + sixBytesFromUInt64(ourNextSeqNum, &asdu[0]); + sixBytesFromUInt64(remoteNextSeqNum, &asdu[6]); - uint64_t next = nextSequenceNumber(secCtrl.toolAccess); + CemiFrame response(2 + 6 + sizeof(asdu) + 4); // 2 bytes (APCI, SCF) + 6 bytes (SeqNum) + 12 bytes + 4 bytes (MAC) + // Note: additional TPCI byte is already handled internally! - if (localSeq > next) - { - //logger.debug("sync.res update local next {} seq -> {}", toolAccess ? "tool access" : "p2p", localSeq); - updateSequenceNumber(secCtrl.toolAccess, localSeq); - } + uint8_t tpci = 0; - Addr remoteAddr = _syncReqBroadcastOutgoing ? (Addr)GrpAddr(0) : (Addr)IndAddr(remote); - _pendingOutgoingSyncRequests.erase(remoteAddr); -} + if (!_syncReqBroadcastIncoming) + { + if (isConnected()) + { + tpci |= 0x40 | _transportLayer->getTpciSeqNum(); // get next TPCI sequence number for MAC calculation from TL (T_DATA_CONNECTED) + } + } -bool SecureApplicationLayer::decrypt(uint8_t* plainApdu, uint16_t plainApduLength, uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, uint8_t tpci, uint8_t* secureAsdu, SecurityControl& secCtrl, bool systemBcast) -{ - const uint8_t* pBuf; - uint8_t scf; + print("sendSyncResponse: TPCI: "); + println(tpci, HEX); - pBuf = popByte(scf, secureAsdu); + if (secure(response.data() + APDU_LPDU_DIFF, kSecureSyncResponse, _deviceObj.individualAddress(), dstAddr, dstAddrIsGroupAddr, tpci, asdu, sizeof(asdu), secCtrl, systemBcast)) + { + _lastSyncRes = millis(); - bool toolAccess = ((scf & 0x80) == 0x80); - bool systemBroadcast = ((scf & 0x08) == 0x08); - uint8_t sai = (scf >> 4) & 0x07; // sai can only be 0x0 (CCM auth only) or 0x1 (CCM with auth+conf), other values are reserved - bool authOnly = ( sai == 0); - uint8_t service = (scf & 0x07); // only 0x0 (S-A_Data-PDU), 0x2 (S-A_Sync_Req-PDU) or 0x3 (S-A_Sync_Rsp-PDU) are valid values + LOGGER.info("SyncResponse: ", response.apdu()); - if (systemBroadcast != systemBcast) - { - println("SBC flag in SCF does not match actual communication mode!"); + if (_syncReqBroadcastIncoming) + { + _transportLayer->dataBroadcastRequest(AckType::AckDontCare, HopCountType::NetworkLayerParameter, Priority::SystemPriority, response.apdu()); + } + else + { + // either send on T_DATA_INDIVIDUAL or T_DATA_CONNECTED + if (isConnected()) + { + _transportLayer->dataConnectedRequest(getConnectedTsasp(), SystemPriority, response.apdu()); + } + else + { + // Send encrypted SyncResponse message using T_DATA_INDIVIDUAL + _transportLayer->dataIndividualRequest(AckType::AckDontCare, NetworkLayerParameter, SystemPriority, dstAddr, response.apdu()); + } + } + } + else + { + println("SyncResponse: failure during encryption"); + } } - secCtrl.toolAccess = toolAccess; - secCtrl.dataSecurity = authOnly ? DataSecurity::Auth : DataSecurity::AuthConf; - - bool syncReq = service == kSecureSyncRequest; - bool syncRes = service == kSecureSyncResponse; + void SecureApplicationLayer::receivedSyncRequest(uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl& secCtrl, uint8_t* seqNum, uint64_t challenge, bool systemBcast) + { + println("Received SyncRequest:"); - //const uint8_t* key = dstAddrIsGroupAddr ? securityKey(dstAddr, dstAddrIsGroupAddr) : toolAccess ? toolKey() : securityKey(srcAddr, false); - const uint8_t* key = dstAddrIsGroupAddr && (dstAddr != 0) ? securityKey(dstAddr, dstAddrIsGroupAddr) : toolAccess ? _secIfObj.toolKey() : securityKey(srcAddr, false); + uint64_t nextRemoteSeqNum = sixBytesToUInt64(seqNum); + uint64_t nextSeqNum = 1 + lastValidSequenceNumber(secCtrl.toolAccess, srcAddr); - if (key == nullptr) - { - print("Error: No key found. toolAccess: "); - println(toolAccess ? "true" : "false"); - return false; - } + if (nextRemoteSeqNum > nextSeqNum) + { + updateLastValidSequence(secCtrl.toolAccess, srcAddr, nextRemoteSeqNum - 1); + nextSeqNum = nextRemoteSeqNum; + } - uint8_t seqNum[6]; - pBuf = popByteArray(seqNum, 6, pBuf); - uint64_t receivedSeqNumber = sixBytesToUInt64(seqNum); + _syncReqBroadcastIncoming = (dstAddr == 0x0000) && dstAddrIsGroupAddr; - // Provide array for KNX serial number if it is a SyncRequest - // DataService and SyncResponse do not use this variable. - uint8_t knxSerialNumber[6]; + // Remember challenge for securing the sync.res later + _pendingIncomingSyncRequests.insertOrAssign(_syncReqBroadcastIncoming ? (Addr) GrpAddr(0) : (Addr) IndAddr(srcAddr), challenge); - uint16_t remainingPlainApduLength = plainApduLength; + uint16_t toAddr = _syncReqBroadcastIncoming ? dstAddr : srcAddr; + bool toIsGroupAddress = _syncReqBroadcastIncoming; + sendSyncResponse(toAddr, toIsGroupAddress, secCtrl, nextSeqNum, systemBcast); + } - if (service == kSecureDataPdu) + void SecureApplicationLayer::receivedSyncResponse(uint16_t remote, const SecurityControl& secCtrl, uint8_t* plainApdu) { - if (srcAddr != _deviceObj.individualAddress()) - { - uint64_t expectedSeqNumber = lastValidSequenceNumber(toolAccess, srcAddr) + 1; + println("Received SyncResponse:"); - if (receivedSeqNumber < expectedSeqNumber) + if (_syncReqBroadcastOutgoing) + { + if (_pendingOutgoingSyncRequests.get(GrpAddr(0)) == nullptr) { - // security failure - print("security failure: received seqNum: "); - print(receivedSeqNumber, HEX); - print(" < expected seqNum: "); - print(expectedSeqNumber, HEX); - return false; + println("Cannot handle sync.res without pending sync.req! (broadcast/systembroadcast)"); + return; } } - } - else if (syncReq) - { - pBuf = popByteArray(knxSerialNumber, 6, pBuf); - remainingPlainApduLength -= 6; - - // ignore sync.reqs not addressed to us - if (!memcmp(knxSerialNumber, _deviceObj.propertyData(PID_SERIAL_NUMBER), 6)) + else { - uint8_t emptySerialNumber[6] = {0}; - - if (systemBroadcast || dstAddr != _deviceObj.individualAddress() || !memcmp(knxSerialNumber, emptySerialNumber, 6)) - return false; + if (_pendingOutgoingSyncRequests.get(IndAddr(remote)) == nullptr) + { + println("Cannot handle sync.res without pending sync.req!"); + return; + } } - // if responded to another request within the last 1 second, ignore - if ((millis() - _lastSyncRes) < 1000) - { - return false; - } - } - else if (syncRes) - { - // fetch challenge depending on srcAddr to handle multiple requests - uint64_t* challenge = _pendingOutgoingSyncRequests.get(IndAddr(srcAddr)); + // Bytes 0-5 in the "APDU" buffer contain the remote sequence number + // Bytes 6-11 in the "APDU" buffer contain the local sequence number + uint64_t remoteSeq = sixBytesToUInt64(plainApdu + 0); + uint64_t localSeq = sixBytesToUInt64(plainApdu + 6); - if (challenge == nullptr) + uint64_t last = lastValidSequenceNumber(secCtrl.toolAccess, remote); + + if (remoteSeq - 1 > last) { - println("Cannot find matching challenge for source address!"); - return false; + //logger.debug("sync.res update {} last valid {} seq -> {}", remote, toolAccess ? "tool access" : "p2p", remoteSeq -1); + updateLastValidSequence(secCtrl.toolAccess, remote, remoteSeq - 1); } - uint8_t _challengeSixBytes[6]; - sixBytesFromUInt64(*challenge, _challengeSixBytes); + uint64_t next = nextSequenceNumber(secCtrl.toolAccess); - // in a sync.res, seq actually contains our challenge from sync.req xored with a random value - // extract the random value and store it in seqNum to use it for block0 and ctr0 - for (uint8_t i = 0; i < sizeof(seqNum); i++) + if (localSeq > next) { - seqNum[i] ^= _challengeSixBytes[i]; + //logger.debug("sync.res update local next {} seq -> {}", toolAccess ? "tool access" : "p2p", localSeq); + updateSequenceNumber(secCtrl.toolAccess, localSeq); } + + Addr remoteAddr = _syncReqBroadcastOutgoing ? (Addr)GrpAddr(0) : (Addr)IndAddr(remote); + _pendingOutgoingSyncRequests.erase(remoteAddr); } - pBuf = popByteArray(plainApdu, remainingPlainApduLength, pBuf); - - // No LTE-HEE for now - // Data Secure always uses extended frame format with APDU length > 15 octets (long messages), no standard frames - uint8_t extendedFrameFormat = 0; - // Clear IV buffer - uint8_t iv[16] = {0x00}; - // Create first block B0 for AES CBC MAC calculation, used as IV later - /* - printHex("seq: ", seqNum, 6); - printHex("src: ", (uint8_t*) &srcAddr, 2); - printHex("dst: ", (uint8_t*) &dstAddr, 2); - print("dstAddrisGroup: ");println(dstAddrIsGroupAddr ? "true" : "false"); - */ - block0(iv, seqNum, srcAddr, dstAddr, dstAddrIsGroupAddr, extendedFrameFormat, tpci | (SecureService >> 8), SecureService & 0x00FF, remainingPlainApduLength); - - // Clear block counter0 buffer - uint8_t ctr0[16] = {0x00}; - // Create first block for block counter 0 - blockCtr0(ctr0, seqNum, srcAddr, dstAddr); - - uint32_t mac; - pBuf = popInt(mac, pBuf); - - if (authOnly) + bool SecureApplicationLayer::decrypt(uint8_t* plainApdu, uint16_t plainApduLength, uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, uint8_t tpci, uint8_t* secureAsdu, SecurityControl& secCtrl, bool systemBcast) { - // APDU is already plain, no decryption needed + const uint8_t* pBuf; + uint8_t scf; + + pBuf = popByte(scf, secureAsdu); - // Only check the MAC - uint32_t calculatedMac = calcAuthOnlyMac(plainApdu, remainingPlainApduLength, key, iv, ctr0); + bool toolAccess = ((scf & 0x80) == 0x80); + bool systemBroadcast = ((scf & 0x08) == 0x08); + uint8_t sai = (scf >> 4) & 0x07; // sai can only be 0x0 (CCM auth only) or 0x1 (CCM with auth+conf), other values are reserved + bool authOnly = ( sai == 0); + uint8_t service = (scf & 0x07); // only 0x0 (S-A_Data-PDU), 0x2 (S-A_Sync_Req-PDU) or 0x3 (S-A_Sync_Rsp-PDU) are valid values - if (calculatedMac != mac) + if (systemBroadcast != systemBcast) { - // security failure - print("security failure(auth): calculated MAC: "); - print(calculatedMac, HEX); - print(" != received MAC: "); - print(mac, HEX); - println("\n"); + println("SBC flag in SCF does not match actual communication mode!"); + } + + secCtrl.toolAccess = toolAccess; + secCtrl.dataSecurity = authOnly ? DataSecurity::Auth : DataSecurity::AuthConf; + + bool syncReq = service == kSecureSyncRequest; + bool syncRes = service == kSecureSyncResponse; + + //const uint8_t* key = dstAddrIsGroupAddr ? securityKey(dstAddr, dstAddrIsGroupAddr) : toolAccess ? toolKey() : securityKey(srcAddr, false); + const uint8_t* key = dstAddrIsGroupAddr && (dstAddr != 0) ? securityKey(dstAddr, dstAddrIsGroupAddr) : toolAccess ? _secIfObj.toolKey() : securityKey(srcAddr, false); + if (key == nullptr) + { + print("Error: No key found. toolAccess: "); + println(toolAccess ? "true" : "false"); return false; } - memcpy(plainApdu, secureAsdu, remainingPlainApduLength); - } - else - { - // APDU is encrypted and needs decryption + uint8_t seqNum[6]; + pBuf = popByteArray(seqNum, 6, pBuf); + uint64_t receivedSeqNumber = sixBytesToUInt64(seqNum); - uint16_t bufLen = 4 + remainingPlainApduLength; - // AES-128 operates on blocks of 16 bytes, add padding - uint16_t bufLenPadded = (bufLen + 15) / 16 * 16; - uint8_t buffer[bufLenPadded]; - //uint8_t buffer[bufLen]; - // Make sure to have zeroes everywhere, because of the padding - memset(buffer, 0x00, bufLenPadded); + // Provide array for KNX serial number if it is a SyncRequest + // DataService and SyncResponse do not use this variable. + uint8_t knxSerialNumber[6]; - pushInt(mac, &buffer[0]); - pushByteArray(plainApdu, remainingPlainApduLength, &buffer[4]); // apdu is still encrypted + uint16_t remainingPlainApduLength = plainApduLength; - xcryptAesCtr(buffer, bufLenPadded, ctr0, key); - //xcryptAesCtr(buffer, bufLen, ctr0, key); + if (service == kSecureDataPdu) + { + if (srcAddr != _deviceObj.individualAddress()) + { + uint64_t expectedSeqNumber = lastValidSequenceNumber(toolAccess, srcAddr) + 1; + + if (receivedSeqNumber < expectedSeqNumber) + { + // security failure + print("security failure: received seqNum: "); + print(receivedSeqNumber, HEX); + print(" < expected seqNum: "); + print(expectedSeqNumber, HEX); + return false; + } + } + } + else if (syncReq) + { + pBuf = popByteArray(knxSerialNumber, 6, pBuf); + remainingPlainApduLength -= 6; - uint32_t decryptedMac; - popInt(decryptedMac, &buffer[0]); - popByteArray(plainApdu, remainingPlainApduLength, &buffer[4]); // apdu is now decrypted (overwritten) + // ignore sync.reqs not addressed to us + if (!memcmp(knxSerialNumber, _deviceObj.propertyData(PID_SERIAL_NUMBER), 6)) + { + uint8_t emptySerialNumber[6] = {0}; - // Do calculations for Auth+Conf - uint8_t associatedData[syncReq ? 7 : 1]; - associatedData[0] = scf; + if (systemBroadcast || dstAddr != _deviceObj.individualAddress() || !memcmp(knxSerialNumber, emptySerialNumber, 6)) + return false; + } - if (syncReq) + // if responded to another request within the last 1 second, ignore + if ((millis() - _lastSyncRes) < 1000) + { + return false; + } + } + else if (syncRes) { - memcpy(&associatedData[1], knxSerialNumber, 6); + // fetch challenge depending on srcAddr to handle multiple requests + uint64_t* challenge = _pendingOutgoingSyncRequests.get(IndAddr(srcAddr)); + + if (challenge == nullptr) + { + println("Cannot find matching challenge for source address!"); + return false; + } + + uint8_t _challengeSixBytes[6]; + sixBytesFromUInt64(*challenge, _challengeSixBytes); + + // in a sync.res, seq actually contains our challenge from sync.req xored with a random value + // extract the random value and store it in seqNum to use it for block0 and ctr0 + for (uint8_t i = 0; i < sizeof(seqNum); i++) + { + seqNum[i] ^= _challengeSixBytes[i]; + } } + pBuf = popByteArray(plainApdu, remainingPlainApduLength, pBuf); + + // No LTE-HEE for now + // Data Secure always uses extended frame format with APDU length > 15 octets (long messages), no standard frames + uint8_t extendedFrameFormat = 0; + // Clear IV buffer + uint8_t iv[16] = {0x00}; + // Create first block B0 for AES CBC MAC calculation, used as IV later /* - printHex("APDU--------->", plainApdu, remainingPlainApduLength); - printHex("Key---------->", key, 16); - printHex("ASSOC-------->", associatedData, sizeof(associatedData)); + printHex("seq: ", seqNum, 6); + printHex("src: ", (uint8_t*) &srcAddr, 2); + printHex("dst: ", (uint8_t*) &dstAddr, 2); + print("dstAddrisGroup: ");println(dstAddrIsGroupAddr ? "true" : "false"); */ - uint32_t calculatedMac = calcConfAuthMac(associatedData, sizeof(associatedData), plainApdu, remainingPlainApduLength, key, iv); + block0(iv, seqNum, srcAddr, dstAddr, dstAddrIsGroupAddr, extendedFrameFormat, tpci | (SecureService >> 8), SecureService & 0x00FF, remainingPlainApduLength); + + // Clear block counter0 buffer + uint8_t ctr0[16] = {0x00}; + // Create first block for block counter 0 + blockCtr0(ctr0, seqNum, srcAddr, dstAddr); - if (calculatedMac != decryptedMac) + uint32_t mac; + pBuf = popInt(mac, pBuf); + + if (authOnly) { - // security failure - print("security failure(conf+auth): calculated MAC: "); - print(calculatedMac, HEX); - print(" != decrypted MAC: "); - print(decryptedMac, HEX); - println("\n"); + // APDU is already plain, no decryption needed - return false; - } + // Only check the MAC + uint32_t calculatedMac = calcAuthOnlyMac(plainApdu, remainingPlainApduLength, key, iv, ctr0); - // prevent a sync.req sent by us to trigger sync notification, this happens if we provide our own tool key - // for decryption above - if (syncReq && (srcAddr == _deviceObj.individualAddress())) - return false; + if (calculatedMac != mac) + { + // security failure + print("security failure(auth): calculated MAC: "); + print(calculatedMac, HEX); + print(" != received MAC: "); + print(mac, HEX); + println("\n"); - if (syncReq) - { - uint64_t challenge = sixBytesToUInt64(&plainApdu[0]); - receivedSyncRequest(srcAddr, dstAddr, dstAddrIsGroupAddr, secCtrl, seqNum, challenge, systemBroadcast); - return false; - } - else if (syncRes) - { - receivedSyncResponse(srcAddr, secCtrl, plainApdu); - return false; + return false; + } + + memcpy(plainApdu, secureAsdu, remainingPlainApduLength); } else { - if (srcAddr == _deviceObj.individualAddress()) + // APDU is encrypted and needs decryption + + uint16_t bufLen = 4 + remainingPlainApduLength; + // AES-128 operates on blocks of 16 bytes, add padding + uint16_t bufLenPadded = (bufLen + 15) / 16 * 16; + uint8_t buffer[bufLenPadded]; + //uint8_t buffer[bufLen]; + // Make sure to have zeroes everywhere, because of the padding + memset(buffer, 0x00, bufLenPadded); + + pushInt(mac, &buffer[0]); + pushByteArray(plainApdu, remainingPlainApduLength, &buffer[4]); // apdu is still encrypted + + xcryptAesCtr(buffer, bufLenPadded, ctr0, key); + //xcryptAesCtr(buffer, bufLen, ctr0, key); + + uint32_t decryptedMac; + popInt(decryptedMac, &buffer[0]); + popByteArray(plainApdu, remainingPlainApduLength, &buffer[4]); // apdu is now decrypted (overwritten) + + // Do calculations for Auth+Conf + uint8_t associatedData[syncReq ? 7 : 1]; + associatedData[0] = scf; + + if (syncReq) + { + memcpy(&associatedData[1], knxSerialNumber, 6); + } + + /* + printHex("APDU--------->", plainApdu, remainingPlainApduLength); + printHex("Key---------->", key, 16); + printHex("ASSOC-------->", associatedData, sizeof(associatedData)); + */ + uint32_t calculatedMac = calcConfAuthMac(associatedData, sizeof(associatedData), plainApdu, remainingPlainApduLength, key, iv); + + if (calculatedMac != decryptedMac) + { + // security failure + print("security failure(conf+auth): calculated MAC: "); + print(calculatedMac, HEX); + print(" != decrypted MAC: "); + print(decryptedMac, HEX); + println("\n"); + + return false; + } + + // prevent a sync.req sent by us to trigger sync notification, this happens if we provide our own tool key + // for decryption above + if (syncReq && (srcAddr == _deviceObj.individualAddress())) + return false; + + if (syncReq) { - print("Update our next "); - print(toolAccess ? "tool access" : ""); - print(" seq from "); - print(srcAddr, HEX); - print(" -> (+1) "); - println(receivedSeqNumber, HEX); - updateSequenceNumber(toolAccess, receivedSeqNumber + 1); + uint64_t challenge = sixBytesToUInt64(&plainApdu[0]); + receivedSyncRequest(srcAddr, dstAddr, dstAddrIsGroupAddr, secCtrl, seqNum, challenge, systemBroadcast); + return false; + } + else if (syncRes) + { + receivedSyncResponse(srcAddr, secCtrl, plainApdu); + return false; } else { - print("Update last valid "); - print(toolAccess ? "tool access" : ""); - print(" seq from "); - print(srcAddr, HEX); - print(" -> "); - println(receivedSeqNumber, HEX); - updateLastValidSequence(toolAccess, srcAddr, receivedSeqNumber); + if (srcAddr == _deviceObj.individualAddress()) + { + print("Update our next "); + print(toolAccess ? "tool access" : ""); + print(" seq from "); + print(srcAddr, HEX); + print(" -> (+1) "); + println(receivedSeqNumber, HEX); + updateSequenceNumber(toolAccess, receivedSeqNumber + 1); + } + else + { + print("Update last valid "); + print(toolAccess ? "tool access" : ""); + print(" seq from "); + print(srcAddr, HEX); + print(" -> "); + println(receivedSeqNumber, HEX); + updateLastValidSequence(toolAccess, srcAddr, receivedSeqNumber); + } } } - } - - return true; -} -bool SecureApplicationLayer::decodeSecureApdu(APDU& secureApdu, APDU& plainApdu, SecurityControl& secCtrl) -{ - // Decode secure APDU - LOGGER.info("decodeSecureApdu: Secure APDU: ", secureApdu); - - uint16_t srcAddress = secureApdu.frame().sourceAddress(); - uint16_t dstAddress = secureApdu.frame().destinationAddress(); - bool isDstAddrGroupAddr = secureApdu.frame().addressType() == GroupAddress; - bool isSystemBroadcast = secureApdu.frame().systemBroadcast(); - uint8_t tpci = secureApdu.frame().data()[TPDU_LPDU_DIFF]; // FIXME: when cEMI class is refactored, there might be additional info fields in cEMI [fixed TPDU_LPDU_DIFF] - print("decodeSecureApdu: TPCI: "); - println(tpci, HEX); - // Note: - // The TPCI is also included in the MAC calculation to provide authenticity for this field. - // However, a secure APDU (with a MAC) is only included in transport layer PDUs T_DATA_GROUP, T_DATA_TAG_GROUP, T_DATA_INDIVIDUAL, T_DATA_CONNECTED - // and not in T_CONNECT, T_DISCONNECT, T_ACK, T_NACK. - // This means the DATA/CONTROL flag is always 0(=DATA). The flag "NUMBERED" differentiates between T_DATA_INDIVIDUAL and T_DATA_CONNECTED. - // The seqNumber is only used in T_DATA_CONNECTED and 0 in case of T_DATA_GROUP and T_DATA_GROUP (leaving out T_DATA_TAG_GROUP). - // Summary: effectively only the "NUMBERED" flag (bit6) and the SeqNumber (bit5-2) are used from transport layer. - // In T_DATA_* services the bits1-0 of TPCI octet are used as bits9-8 for APCI type which is fixed to 0x03. SecureService APCI is 0x03F1. - - // FIXME: when cEMI class is refactored, there might be additional info fields in cEMI (fixed APDU_LPDU_DIFF) - // 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: ", plainApdu.frame().apdu()); return true; } - return false; -} + bool SecureApplicationLayer::decodeSecureApdu(APDU& secureApdu, APDU& plainApdu, SecurityControl& secCtrl) + { + // Decode secure APDU + LOGGER.info("decodeSecureApdu: Secure APDU: ", secureApdu); + + uint16_t srcAddress = secureApdu.frame().sourceAddress(); + uint16_t dstAddress = secureApdu.frame().destinationAddress(); + bool isDstAddrGroupAddr = secureApdu.frame().addressType() == GroupAddress; + bool isSystemBroadcast = secureApdu.frame().systemBroadcast(); + uint8_t tpci = secureApdu.frame().data()[TPDU_LPDU_DIFF]; // FIXME: when cEMI class is refactored, there might be additional info fields in cEMI [fixed TPDU_LPDU_DIFF] + print("decodeSecureApdu: TPCI: "); + println(tpci, HEX); + // Note: + // The TPCI is also included in the MAC calculation to provide authenticity for this field. + // However, a secure APDU (with a MAC) is only included in transport layer PDUs T_DATA_GROUP, T_DATA_TAG_GROUP, T_DATA_INDIVIDUAL, T_DATA_CONNECTED + // and not in T_CONNECT, T_DISCONNECT, T_ACK, T_NACK. + // This means the DATA/CONTROL flag is always 0(=DATA). The flag "NUMBERED" differentiates between T_DATA_INDIVIDUAL and T_DATA_CONNECTED. + // The seqNumber is only used in T_DATA_CONNECTED and 0 in case of T_DATA_GROUP and T_DATA_GROUP (leaving out T_DATA_TAG_GROUP). + // Summary: effectively only the "NUMBERED" flag (bit6) and the SeqNumber (bit5-2) are used from transport layer. + // In T_DATA_* services the bits1-0 of TPCI octet are used as bits9-8 for APCI type which is fixed to 0x03. SecureService APCI is 0x03F1. + + // FIXME: when cEMI class is refactored, there might be additional info fields in cEMI (fixed APDU_LPDU_DIFF) + // 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: ", plainApdu.frame().apdu()); + return true; + } -bool SecureApplicationLayer::secure(uint8_t* buffer, uint16_t service, uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, uint8_t tpci, - uint8_t* apdu, uint16_t apduLength, const SecurityControl& secCtrl, bool systemBcast) -{ - bool toolAccess = secCtrl.toolAccess; - bool confidentiality = secCtrl.dataSecurity == DataSecurity::AuthConf; + return false; + } - if (toolAccess) + bool SecureApplicationLayer::secure(uint8_t* buffer, uint16_t service, uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, uint8_t tpci, + uint8_t* apdu, uint16_t apduLength, const SecurityControl& secCtrl, bool systemBcast) { - if (!confidentiality) + bool toolAccess = secCtrl.toolAccess; + bool confidentiality = secCtrl.dataSecurity == DataSecurity::AuthConf; + + if (toolAccess) { - println("Error: tool access requires auth+conf security"); - return false; + if (!confidentiality) + { + println("Error: tool access requires auth+conf security"); + return false; + } + + if (dstAddrIsGroupAddr && dstAddr != 0) + { + println("Error: tool access requires individual address"); + return false; + } } - if (dstAddrIsGroupAddr && dstAddr != 0) + const uint8_t* key = toolAccess ? _secIfObj.toolKey() : securityKey(dstAddr, dstAddrIsGroupAddr); + + if (key == nullptr) { - println("Error: tool access requires individual address"); + print("Error: No key found. toolAccess: "); + println(toolAccess ? "true" : "false"); return false; } - } - const uint8_t* key = toolAccess ? _secIfObj.toolKey() : securityKey(dstAddr, dstAddrIsGroupAddr); + bool syncReq = service == kSecureSyncRequest; + bool syncRes = service == kSecureSyncResponse; - if (key == nullptr) - { - print("Error: No key found. toolAccess: "); - println(toolAccess ? "true" : "false"); - return false; - } + tpci |= SecureService >> 8; // OR'ing upper two APCI bits + uint8_t apci = SecureService & 0x00FF; + uint8_t* pBuf = buffer; + pBuf = pushByte(tpci, pBuf); // TPCI + pBuf = pushByte(apci, pBuf); // APCI - bool syncReq = service == kSecureSyncRequest; - bool syncRes = service == kSecureSyncResponse; + uint8_t scf; + scf = service; + scf |= toolAccess ? 0x80 : 0; + scf |= confidentiality ? 0x10 : 0; + scf |= systemBcast ? 0x8 : 0; - tpci |= SecureService >> 8; // OR'ing upper two APCI bits - uint8_t apci = SecureService & 0x00FF; - uint8_t* pBuf = buffer; - pBuf = pushByte(tpci, pBuf); // TPCI - pBuf = pushByte(apci, pBuf); // APCI + pBuf = pushByte(scf, pBuf); // SCF - uint8_t scf; - scf = service; - scf |= toolAccess ? 0x80 : 0; - scf |= confidentiality ? 0x10 : 0; - scf |= systemBcast ? 0x8 : 0; + uint64_t seqSend = nextSequenceNumber(toolAccess); - pBuf = pushByte(scf, pBuf); // SCF + if (seqSend == 0) + println("0 is not a valid sequence number"); - uint64_t seqSend = nextSequenceNumber(toolAccess); + uint8_t seq[6]; + sixBytesFromUInt64(seqSend, seq); - if (seqSend == 0) - println("0 is not a valid sequence number"); + if (!syncRes) + pBuf = pushByteArray(seq, 6, pBuf); // Sequence Number - uint8_t seq[6]; - sixBytesFromUInt64(seqSend, seq); + // Prepare associated data depending on service (SyncRequest, SyncResponse or just DataService) + uint8_t associatedData[syncReq ? 7 : 1]; + associatedData[0] = scf; - if (!syncRes) - pBuf = pushByteArray(seq, 6, pBuf); // Sequence Number + if (syncReq) + { + // TODO: NYI lookup serial number of target device for SBC sync.req + uint8_t remoteSerialNo[6] = {0}; - // Prepare associated data depending on service (SyncRequest, SyncResponse or just DataService) - uint8_t associatedData[syncReq ? 7 : 1]; - associatedData[0] = scf; + uint8_t emptySerialNo[6] = {0}; + pBuf = pushByteArray(systemBcast ? remoteSerialNo : emptySerialNo, 6, pBuf); + pushByteArray(_deviceObj.propertyData(PID_SERIAL_NUMBER), 6, &associatedData[1]); + } + else if (syncRes) + { + // use random number in SyncResponse + uint64_t randomNumber = getRandomNumber(); + sixBytesFromUInt64(randomNumber, seq); - if (syncReq) - { - // TODO: NYI lookup serial number of target device for SBC sync.req - uint8_t remoteSerialNo[6] = {0}; + Addr remote = _syncReqBroadcastIncoming ? (Addr)GrpAddr(0) : (Addr)IndAddr(dstAddr); - uint8_t emptySerialNo[6] = {0}; - pBuf = pushByteArray(systemBcast ? remoteSerialNo : emptySerialNo, 6, pBuf); - pushByteArray(_deviceObj.propertyData(PID_SERIAL_NUMBER), 6, &associatedData[1]); - } - else if (syncRes) - { - // use random number in SyncResponse - uint64_t randomNumber = getRandomNumber(); - sixBytesFromUInt64(randomNumber, seq); + // Get challenge from sync.req + uint64_t* challenge = _pendingIncomingSyncRequests.get(remote); - Addr remote = _syncReqBroadcastIncoming ? (Addr)GrpAddr(0) : (Addr)IndAddr(dstAddr); + if (challenge == nullptr) + { + println("Cannot send sync.res without corresponding sync.req"); + return false; + } + else + { + _pendingIncomingSyncRequests.erase(remote); + } - // Get challenge from sync.req - uint64_t* challenge = _pendingIncomingSyncRequests.get(remote); + uint8_t challengeSixBytes[6]; + sixBytesFromUInt64(*challenge, challengeSixBytes); + //printHex("Decrypted challenge: ", challengeSixBytes, 6); - if (challenge == nullptr) - { - println("Cannot send sync.res without corresponding sync.req"); - return false; - } - else - { - _pendingIncomingSyncRequests.erase(remote); + // Now XOR the new random SeqNum with the challenge from the SyncRequest + uint8_t rndXorChallenge[6]; + pushByteArray(seq, 6, rndXorChallenge); + + for (uint8_t i = 0; i < sizeof(rndXorChallenge); i++) + { + rndXorChallenge[i] ^= challengeSixBytes[i]; + } + + pBuf = pushByteArray(rndXorChallenge, 6, pBuf); } - uint8_t challengeSixBytes[6]; - sixBytesFromUInt64(*challenge, challengeSixBytes); - //printHex("Decrypted challenge: ", challengeSixBytes, 6); + // No LTE-HEE for now + // Data Secure always uses extended frame format with APDU length > 15 octets (long messages), no standard frames + uint8_t extendedFrameFormat = 0; + // Clear IV buffer + uint8_t iv[16] = {0x00}; + // Create first block B0 for AES CBC MAC calculation, used as IV later + /* + printHex("seq: ", seq, 6); + printHex("src: ", (uint8_t*) &srcAddr, 2); + printHex("dst: ", (uint8_t*) &dstAddr, 2); + print("dstAddrisGroup: ");println(dstAddrIsGroupAddr ? "true" : "false"); + */ + block0(iv, seq, srcAddr, dstAddr, dstAddrIsGroupAddr, extendedFrameFormat, tpci, apci, apduLength); - // Now XOR the new random SeqNum with the challenge from the SyncRequest - uint8_t rndXorChallenge[6]; - pushByteArray(seq, 6, rndXorChallenge); + // Clear block counter0 buffer + uint8_t ctr0[16] = {0x00}; + // Create first block for block counter 0 + blockCtr0(ctr0, seq, srcAddr, dstAddr); - for (uint8_t i = 0; i < sizeof(rndXorChallenge); i++) + if (confidentiality) { - rndXorChallenge[i] ^= challengeSixBytes[i]; - } + // Do calculations for Auth+Conf + /* + printHex("APDU--------->", apdu, apduLength); + printHex("Key---------->", key, 16); + printHex("ASSOC-------->", associatedData, sizeof(associatedData)); + */ + uint32_t mac = calcConfAuthMac(associatedData, sizeof(associatedData), apdu, apduLength, key, iv); - pBuf = pushByteArray(rndXorChallenge, 6, pBuf); - } + uint8_t tmpBuffer[4 + apduLength]; + pushInt(mac, tmpBuffer); + pushByteArray(apdu, apduLength, &tmpBuffer[4]); - // No LTE-HEE for now - // Data Secure always uses extended frame format with APDU length > 15 octets (long messages), no standard frames - uint8_t extendedFrameFormat = 0; - // Clear IV buffer - uint8_t iv[16] = {0x00}; - // Create first block B0 for AES CBC MAC calculation, used as IV later - /* - printHex("seq: ", seq, 6); - printHex("src: ", (uint8_t*) &srcAddr, 2); - printHex("dst: ", (uint8_t*) &dstAddr, 2); - print("dstAddrisGroup: ");println(dstAddrIsGroupAddr ? "true" : "false"); - */ - block0(iv, seq, srcAddr, dstAddr, dstAddrIsGroupAddr, extendedFrameFormat, tpci, apci, apduLength); - - // Clear block counter0 buffer - uint8_t ctr0[16] = {0x00}; - // Create first block for block counter 0 - blockCtr0(ctr0, seq, srcAddr, dstAddr); - - if (confidentiality) - { - // Do calculations for Auth+Conf - /* - printHex("APDU--------->", apdu, apduLength); - printHex("Key---------->", key, 16); - printHex("ASSOC-------->", associatedData, sizeof(associatedData)); - */ - uint32_t mac = calcConfAuthMac(associatedData, sizeof(associatedData), apdu, apduLength, key, iv); + xcryptAesCtr(tmpBuffer, apduLength + 4, ctr0, key); // APDU + MAC (4 bytes) - uint8_t tmpBuffer[4 + apduLength]; - pushInt(mac, tmpBuffer); - pushByteArray(apdu, apduLength, &tmpBuffer[4]); + pBuf = pushByteArray(tmpBuffer + 4, apduLength, pBuf); // Encrypted APDU + pBuf = pushByteArray(tmpBuffer + 0, 4, pBuf); // Encrypted MAC - xcryptAesCtr(tmpBuffer, apduLength + 4, ctr0, key); // APDU + MAC (4 bytes) + //print("MAC(encrypted): "); + //println(*((uint32_t*)(tmpBuffer + 0)),HEX); + } + else + { + // Do calculations for AuthOnly + uint32_t tmpMac = calcAuthOnlyMac(apdu, apduLength, key, iv, ctr0); - pBuf = pushByteArray(tmpBuffer + 4, apduLength, pBuf); // Encrypted APDU - pBuf = pushByteArray(tmpBuffer + 0, 4, pBuf); // Encrypted MAC + pBuf = pushByteArray(apdu, apduLength, pBuf); // Plain APDU + pBuf = pushInt(tmpMac, pBuf); // MAC - //print("MAC(encrypted): "); - //println(*((uint32_t*)(tmpBuffer + 0)),HEX); + print("MAC: "); + println(tmpMac, HEX); + } + + return true; } - else + + bool SecureApplicationLayer::createSecureApdu(APDU& plainApdu, APDU& secureApdu, const SecurityControl& secCtrl) { - // Do calculations for AuthOnly - uint32_t tmpMac = calcAuthOnlyMac(apdu, apduLength, key, iv, ctr0); + // Create secure APDU - pBuf = pushByteArray(apdu, apduLength, pBuf); // Plain APDU - pBuf = pushInt(tmpMac, pBuf); // MAC + LOGGER.info("createSecureApdu: Plain APDU: ", plainApdu.frame().apdu()); - print("MAC: "); - println(tmpMac, HEX); - } + uint16_t srcAddress = plainApdu.frame().sourceAddress(); + uint16_t dstAddress = plainApdu.frame().destinationAddress(); + bool isDstAddrGroupAddr = plainApdu.frame().addressType() == GroupAddress; + bool isSystemBroadcast = plainApdu.frame().systemBroadcast(); + uint8_t tpci = 0x00; - return true; -} + if (isConnected()) + { + tpci |= 0x40 | _transportLayer->getTpciSeqNum(); // get next TPCI sequence number for MAC calculation from TL (T_DATA_CONNECTED) + } -bool SecureApplicationLayer::createSecureApdu(APDU& plainApdu, APDU& secureApdu, const SecurityControl& secCtrl) -{ - // Create secure APDU + print("createSecureApdu: TPCI: "); + println(tpci, HEX); + // Note: + // The TPCI is also included in the MAC calculation to provide authenticity for this field. + // However, a secure APDU (with a MAC) is only included in transport layer PDUs T_DATA_GROUP, T_DATA_TAG_GROUP, T_DATA_INDIVIDUAL, T_DATA_CONNECTED + // and not in T_CONNECT, T_DISCONNECT, T_ACK, T_NACK. + // This means the DATA/CONTROL flag is always 0(=DATA). The flag "NUMBERED" differentiates between T_DATA_INDIVIDUAL and T_DATA_CONNECTED. + // The seqNumber is only used in T_DATA_CONNECTED and 0 in case of T_DATA_GROUP and T_DATA_GROUP (leaving out T_DATA_TAG_GROUP). + // Summary: effectively only the "NUMBERED" flag (bit6) and the SeqNumber (bit5-2) are used from transport layer. + // In T_DATA_* services the bits1-0 of TPCI octet are used as bits9-8 for APCI type which is fixed to 0x03. SecureService APCI is 0x03F1. + + // FIXME: when cEMI class is refactored, there might be additional info fields in cEMI (fixed APDU_LPDU_DIFF) + // We are starting from TPCI octet (including): plainApdu.frame().data()+APDU_LPDU_DIFF + if (secure(secureApdu.frame().data() + APDU_LPDU_DIFF, kSecureDataPdu, srcAddress, dstAddress, isDstAddrGroupAddr, tpci, plainApdu.frame().data() + APDU_LPDU_DIFF, plainApdu.length() + 1, secCtrl, isSystemBroadcast)) + { + print("Update our next "); + print(secCtrl.toolAccess ? "tool access" : ""); + print(" seq from "); + print(srcAddress, HEX); + print(" -> (+1) "); + println(nextSequenceNumber(secCtrl.toolAccess), HEX); + updateSequenceNumber(secCtrl.toolAccess, nextSequenceNumber(secCtrl.toolAccess) + 1); - LOGGER.info("createSecureApdu: Plain APDU: ", plainApdu.frame().apdu()); + LOGGER.info("createSecureApdu: Secure APDU: ", secureApdu.frame().apdu()); - uint16_t srcAddress = plainApdu.frame().sourceAddress(); - uint16_t dstAddress = plainApdu.frame().destinationAddress(); - bool isDstAddrGroupAddr = plainApdu.frame().addressType() == GroupAddress; - bool isSystemBroadcast = plainApdu.frame().systemBroadcast(); - uint8_t tpci = 0x00; + return true; + } - if (isConnected()) - { - tpci |= 0x40 | _transportLayer->getTpciSeqNum(); // get next TPCI sequence number for MAC calculation from TL (T_DATA_CONNECTED) + return false; } - print("createSecureApdu: TPCI: "); - println(tpci, HEX); - // Note: - // The TPCI is also included in the MAC calculation to provide authenticity for this field. - // However, a secure APDU (with a MAC) is only included in transport layer PDUs T_DATA_GROUP, T_DATA_TAG_GROUP, T_DATA_INDIVIDUAL, T_DATA_CONNECTED - // and not in T_CONNECT, T_DISCONNECT, T_ACK, T_NACK. - // This means the DATA/CONTROL flag is always 0(=DATA). The flag "NUMBERED" differentiates between T_DATA_INDIVIDUAL and T_DATA_CONNECTED. - // The seqNumber is only used in T_DATA_CONNECTED and 0 in case of T_DATA_GROUP and T_DATA_GROUP (leaving out T_DATA_TAG_GROUP). - // Summary: effectively only the "NUMBERED" flag (bit6) and the SeqNumber (bit5-2) are used from transport layer. - // In T_DATA_* services the bits1-0 of TPCI octet are used as bits9-8 for APCI type which is fixed to 0x03. SecureService APCI is 0x03F1. - - // FIXME: when cEMI class is refactored, there might be additional info fields in cEMI (fixed APDU_LPDU_DIFF) - // We are starting from TPCI octet (including): plainApdu.frame().data()+APDU_LPDU_DIFF - if (secure(secureApdu.frame().data() + APDU_LPDU_DIFF, kSecureDataPdu, srcAddress, dstAddress, isDstAddrGroupAddr, tpci, plainApdu.frame().data() + APDU_LPDU_DIFF, plainApdu.length() + 1, secCtrl, isSystemBroadcast)) + uint64_t SecureApplicationLayer::getRandomNumber() { - print("Update our next "); - print(secCtrl.toolAccess ? "tool access" : ""); - print(" seq from "); - print(srcAddress, HEX); - print(" -> (+1) "); - println(nextSequenceNumber(secCtrl.toolAccess), HEX); - updateSequenceNumber(secCtrl.toolAccess, nextSequenceNumber(secCtrl.toolAccess) + 1); - - LOGGER.info("createSecureApdu: Secure APDU: ", secureApdu.frame().apdu()); - - return true; + return 0x000102030405; // TODO: generate random number } - return false; -} - -uint64_t SecureApplicationLayer::getRandomNumber() -{ - return 0x000102030405; // TODO: generate random number -} + void SecureApplicationLayer::loop() + { + // TODO: handle timeout of outgoing sync requests + //_pendingOutgoingSyncRequests + } -void SecureApplicationLayer::loop() -{ - // TODO: handle timeout of outgoing sync requests - //_pendingOutgoingSyncRequests -} + bool SecureApplicationLayer::isSyncService(APDU& secureApdu) + { + uint8_t scf = *(secureApdu.data() + 1); + uint8_t service = (scf & 0x07); // only 0x0 (S-A_Data-PDU), 0x2 (S-A_Sync_Req-PDU) or 0x3 (S-A_Sync_Rsp-PDU) are valid values -bool SecureApplicationLayer::isSyncService(APDU& secureApdu) -{ - uint8_t scf = *(secureApdu.data() + 1); - uint8_t service = (scf & 0x07); // only 0x0 (S-A_Data-PDU), 0x2 (S-A_Sync_Req-PDU) or 0x3 (S-A_Sync_Rsp-PDU) are valid values + if ((service == kSecureSyncRequest) || (service == kSecureSyncResponse)) + { + return true; + } - if ((service == kSecureSyncRequest) || (service == kSecureSyncResponse)) - { - return true; + return false; } - - return false; } -#endif +#endif \ No newline at end of file diff --git a/src/knx/data_secure/secure_application_layer.h b/src/knx/data_secure/secure_application_layer.h index 7a106c1e..99778ad3 100644 --- a/src/knx/data_secure/secure_application_layer.h +++ b/src/knx/data_secure/secure_application_layer.h @@ -6,155 +6,158 @@ #include -class DeviceObject; -class SecurityInterfaceObject; -class AssociationTableObject; -class AddressTableObject; -class BusAccessUnit; -/** - * This is an implementation of the application layer as specified in @cite knx:3/5/1. - * It provides methods for the BusAccessUnit to do different things and translates this - * call to an APDU and calls the correct method of the TransportLayer. - * It also takes calls from TransportLayer, decodes the submitted APDU and calls the coresponding - * methods of the BusAccessUnit class. - */ -class SecureApplicationLayer : public ApplicationLayer +namespace Knx { - public: - /** - * The constructor. - * @param assocTable The AssociationTable is used to translate between asap (i.e. group objects) and group addresses. - * @param bau methods are called here depending of the content of the APDU - */ - SecureApplicationLayer(DeviceObject& deviceObj, SecurityInterfaceObject& secIfObj, BusAccessUnit& bau); - - void groupAddressTable(AddressTableObject& addrTable); - - // from transport layer - void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) override; - void dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, - APDU& apdu, bool status) override; - void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override; - void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, bool status) override; - void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override; - void dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, bool status) override; - void dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override; - void dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status) override; - void dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu) override; - void dataConnectedConfirm(uint16_t tsap) override; - - void loop(); - - protected: - // to transport layer - void dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) override; - void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl) override; - void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl) override; - void dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu, const SecurityControl& secCtrl) override; - void dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu, const SecurityControl& secCtrl) override; // apdu must be valid until it was confirmed - - private: - enum class AddrType : uint8_t - { - group, - individual, - unknown - }; - - struct Addr - { - Addr() = default; - Addr(uint8_t addr) : addr{addr} {} - - uint16_t addr; - AddrType addrType{AddrType::unknown}; - - bool operator ==(const Addr& cmpAddr) const + class DeviceObject; + class SecurityInterfaceObject; + class AssociationTableObject; + class AddressTableObject; + class BusAccessUnit; + /** + * This is an implementation of the application layer as specified in @cite knx:3/5/1. + * It provides methods for the BusAccessUnit to do different things and translates this + * call to an APDU and calls the correct method of the TransportLayer. + * It also takes calls from TransportLayer, decodes the submitted APDU and calls the coresponding + * methods of the BusAccessUnit class. + */ + class SecureApplicationLayer : public ApplicationLayer + { + public: + /** + * The constructor. + * @param assocTable The AssociationTable is used to translate between asap (i.e. group objects) and group addresses. + * @param bau methods are called here depending of the content of the APDU + */ + SecureApplicationLayer(DeviceObject& deviceObj, SecurityInterfaceObject& secIfObj, BusAccessUnit& bau); + + void groupAddressTable(AddressTableObject& addrTable); + + // from transport layer + void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) override; + void dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, + APDU& apdu, bool status) override; + void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override; + void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, bool status) override; + void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override; + void dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, bool status) override; + void dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override; + void dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status) override; + void dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu) override; + void dataConnectedConfirm(uint16_t tsap) override; + + void loop(); + + protected: + // to transport layer + void dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) override; + void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl) override; + void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl) override; + void dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu, const SecurityControl& secCtrl) override; + void dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu, const SecurityControl& secCtrl) override; // apdu must be valid until it was confirmed + + private: + enum class AddrType : uint8_t { - if ((cmpAddr.addrType == AddrType::unknown) || (addrType == AddrType::unknown)) + group, + individual, + unknown + }; + + struct Addr + { + Addr() = default; + Addr(uint8_t addr) : addr{addr} {} + + uint16_t addr; + AddrType addrType{AddrType::unknown}; + + bool operator ==(const Addr& cmpAddr) const { - return false; - } + if ((cmpAddr.addrType == AddrType::unknown) || (addrType == AddrType::unknown)) + { + return false; + } - return (cmpAddr.addr == addr) && (cmpAddr.addrType == addrType); - } - }; + return (cmpAddr.addr == addr) && (cmpAddr.addrType == addrType); + } + }; - struct GrpAddr : Addr - { - GrpAddr() + struct GrpAddr : Addr { - addrType = AddrType::group; - } - GrpAddr(uint8_t addr) : Addr{addr} - { - addrType = AddrType::group; - } - }; + GrpAddr() + { + addrType = AddrType::group; + } + GrpAddr(uint8_t addr) : Addr{addr} + { + addrType = AddrType::group; + } + }; - struct IndAddr : Addr - { - IndAddr() - { - addrType = AddrType::individual; - } - IndAddr(uint8_t addr) : Addr{addr} + struct IndAddr : Addr { - addrType = AddrType::individual; - } - }; + IndAddr() + { + addrType = AddrType::individual; + } + IndAddr(uint8_t addr) : Addr{addr} + { + addrType = AddrType::individual; + } + }; - uint32_t calcAuthOnlyMac(uint8_t* apdu, uint8_t apduLength, const uint8_t* key, uint8_t* iv, uint8_t* ctr0); - uint32_t calcConfAuthMac(uint8_t* associatedData, uint16_t associatedDataLength, uint8_t* apdu, uint8_t apduLength, const uint8_t* key, uint8_t* iv); + uint32_t calcAuthOnlyMac(uint8_t* apdu, uint8_t apduLength, const uint8_t* key, uint8_t* iv, uint8_t* ctr0); + uint32_t calcConfAuthMac(uint8_t* associatedData, uint16_t associatedDataLength, uint8_t* apdu, uint8_t apduLength, const uint8_t* key, uint8_t* iv); - void block0(uint8_t* buffer, uint8_t* seqNum, uint16_t indSrcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, uint8_t extFrameFormat, uint8_t tpci, uint8_t apci, uint8_t payloadLength); - void blockCtr0(uint8_t* buffer, uint8_t* seqNum, uint16_t indSrcAddr, uint16_t dstAddr); + void block0(uint8_t* buffer, uint8_t* seqNum, uint16_t indSrcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, uint8_t extFrameFormat, uint8_t tpci, uint8_t apci, uint8_t payloadLength); + void blockCtr0(uint8_t* buffer, uint8_t* seqNum, uint16_t indSrcAddr, uint16_t dstAddr); - const uint8_t* securityKey(uint16_t addr, bool isGroupAddress); + const uint8_t* securityKey(uint16_t addr, bool isGroupAddress); - uint16_t groupAddressIndex(uint16_t groupAddr); // returns 1-based index of address in group address table - uint16_t groupObjectIndex(uint16_t groupAddrIndex); // returns 1-based index of object in association table + uint16_t groupAddressIndex(uint16_t groupAddr); // returns 1-based index of address in group address table + uint16_t groupObjectIndex(uint16_t groupAddrIndex); // returns 1-based index of object in association table - uint8_t groupObjectSecurity(uint16_t groupObjectIndex); + uint8_t groupObjectSecurity(uint16_t groupObjectIndex); - uint64_t nextSequenceNumber(bool toolAccess); - void updateSequenceNumber(bool toolAccess, uint64_t seqNum); + uint64_t nextSequenceNumber(bool toolAccess); + void updateSequenceNumber(bool toolAccess, uint64_t seqNum); - uint64_t lastValidSequenceNumber(bool toolAcces, uint16_t srcAddr); - void updateLastValidSequence(bool toolAccess, uint16_t remoteAddr, uint64_t seqNo); + uint64_t lastValidSequenceNumber(bool toolAcces, uint16_t srcAddr); + void updateLastValidSequence(bool toolAccess, uint16_t remoteAddr, uint64_t seqNo); - uint64_t getRandomNumber(); + uint64_t getRandomNumber(); - bool isSyncService(APDU& secureAsdu); + bool isSyncService(APDU& secureAsdu); - void sendSyncRequest(uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl& secCtrl, bool systemBcast); - void sendSyncResponse(uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl& secCtrl, uint64_t remoteNextSeqNum, bool systemBcast); - void receivedSyncRequest(uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl& secCtrl, uint8_t* seq, uint64_t challenge, bool systemBcast); - void receivedSyncResponse(uint16_t remoteAddr, const SecurityControl& secCtrl, uint8_t* plainApdu); + void sendSyncRequest(uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl& secCtrl, bool systemBcast); + void sendSyncResponse(uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl& secCtrl, uint64_t remoteNextSeqNum, bool systemBcast); + void receivedSyncRequest(uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl& secCtrl, uint8_t* seq, uint64_t challenge, bool systemBcast); + void receivedSyncResponse(uint16_t remoteAddr, const SecurityControl& secCtrl, uint8_t* plainApdu); - bool decrypt(uint8_t* plainApdu, uint16_t plainapduLength, uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, uint8_t tpci, uint8_t* secureAsdu, SecurityControl& secCtrl, bool systemBcast); - bool secure(uint8_t* buffer, uint16_t service, uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, uint8_t tpci, uint8_t* apdu, uint16_t apduLength, const SecurityControl& secCtrl, bool systemBcast); + bool decrypt(uint8_t* plainApdu, uint16_t plainapduLength, uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, uint8_t tpci, uint8_t* secureAsdu, SecurityControl& secCtrl, bool systemBcast); + bool secure(uint8_t* buffer, uint16_t service, uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, uint8_t tpci, uint8_t* apdu, uint16_t apduLength, const SecurityControl& secCtrl, bool systemBcast); - bool decodeSecureApdu(APDU& secureApdu, APDU& plainApdu, SecurityControl& secCtrl); - bool createSecureApdu(APDU& plainApdu, APDU& secureApdu, const SecurityControl& secCtrl); + bool decodeSecureApdu(APDU& secureApdu, APDU& plainApdu, SecurityControl& secCtrl); + bool createSecureApdu(APDU& plainApdu, APDU& secureApdu, const SecurityControl& secCtrl); - void encryptAesCbc(uint8_t* buffer, uint16_t bufLen, const uint8_t* iv, const uint8_t* key); - void xcryptAesCtr(uint8_t* buffer, uint16_t bufLen, const uint8_t* iv, const uint8_t* key); + void encryptAesCbc(uint8_t* buffer, uint16_t bufLen, const uint8_t* iv, const uint8_t* key); + void xcryptAesCtr(uint8_t* buffer, uint16_t bufLen, const uint8_t* iv, const uint8_t* key); - bool _syncReqBroadcastIncoming{false}; - bool _syncReqBroadcastOutgoing{false}; - uint32_t _lastSyncRes; + bool _syncReqBroadcastIncoming{false}; + bool _syncReqBroadcastOutgoing{false}; + uint32_t _lastSyncRes; - Map _pendingOutgoingSyncRequests; // Store challenges for outgoing sync requests - Map _pendingIncomingSyncRequests; // Store challenges for incoming sync requests + Map _pendingOutgoingSyncRequests; // Store challenges for outgoing sync requests + Map _pendingIncomingSyncRequests; // Store challenges for incoming sync requests - uint64_t _sequenceNumberToolAccess = 50; - uint64_t _sequenceNumber = 0; + uint64_t _sequenceNumberToolAccess = 50; + uint64_t _sequenceNumber = 0; - uint64_t _lastValidSequenceNumberTool = 0; - uint64_t _lastValidSequenceNumber = 0; + uint64_t _lastValidSequenceNumberTool = 0; + uint64_t _lastValidSequenceNumber = 0; - SecurityInterfaceObject& _secIfObj; - DeviceObject& _deviceObj; - AddressTableObject* _addrTab = nullptr; -}; + SecurityInterfaceObject& _secIfObj; + DeviceObject& _deviceObj; + AddressTableObject* _addrTab = nullptr; + }; +} \ No newline at end of file diff --git a/src/knx/data_secure/security_interface_object.cpp b/src/knx/data_secure/security_interface_object.cpp index c3c3d73b..468f2d1b 100644 --- a/src/knx/data_secure/security_interface_object.cpp +++ b/src/knx/data_secure/security_interface_object.cpp @@ -7,597 +7,598 @@ #include -// Our FDSK. It is never changed from ETS. This is the permanent default tool key that is restored on every factory reset of the device. -const uint8_t SecurityInterfaceObject::_fdsk[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; -uint8_t SecurityInterfaceObject::_secReport[] = { 0x00, 0x00, 0x00 }; -uint8_t SecurityInterfaceObject::_secReportCtrl[] = { 0x00, 0x00, 0x00 }; - -SecurityInterfaceObject::SecurityInterfaceObject() +namespace Knx { - Property* properties[] = + // Our FDSK. It is never changed from ETS. This is the permanent default tool key that is restored on every factory reset of the device. + const uint8_t SecurityInterfaceObject::_fdsk[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; + uint8_t SecurityInterfaceObject::_secReport[] = { 0x00, 0x00, 0x00 }; + uint8_t SecurityInterfaceObject::_secReportCtrl[] = { 0x00, 0x00, 0x00 }; + + SecurityInterfaceObject::SecurityInterfaceObject() { - new DataProperty( PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_SECURITY ), - new CallbackProperty(this, PID_LOAD_STATE_CONTROL, true, PDT_CONTROL, 1, ReadLv3 | WriteLv3, - // ReadCallback of PID_LOAD_STATE_CONTROL - [](SecurityInterfaceObject * obj, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { - if (start == 0) + Property* properties[] = + { + new DataProperty( PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_SECURITY ), + new CallbackProperty(this, PID_LOAD_STATE_CONTROL, true, PDT_CONTROL, 1, ReadLv3 | WriteLv3, + // ReadCallback of PID_LOAD_STATE_CONTROL + [](SecurityInterfaceObject * obj, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { + if (start == 0) + return 1; + + data[0] = obj->_state; return 1; + }, + // WriteCallback of PID_LOAD_STATE_CONTROL + [](SecurityInterfaceObject * obj, uint16_t start, uint8_t count, const uint8_t* data) -> uint8_t { + obj->loadEvent(data); + return 1; + }), + new FunctionProperty(this, PID_SECURITY_MODE, + // Command Callback of PID_SECURITY_MODE + [](SecurityInterfaceObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void { + uint8_t serviceId = data[1] & 0xff; - data[0] = obj->_state; - return 1; - }, - // WriteCallback of PID_LOAD_STATE_CONTROL - [](SecurityInterfaceObject * obj, uint16_t start, uint8_t count, const uint8_t* data) -> uint8_t { - obj->loadEvent(data); - return 1; - }), - new FunctionProperty(this, PID_SECURITY_MODE, - // Command Callback of PID_SECURITY_MODE - [](SecurityInterfaceObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void { - uint8_t serviceId = data[1] & 0xff; - - if (serviceId != 0) - { - resultData[0] - = ReturnCodes::InvalidCommand; - resultLength = 1; - return; - } - if (length == 3) - { - uint8_t mode = data[2]; - - if (mode > 1) + if (serviceId != 0) { - resultData[0] = ReturnCodes::DataVoid; + resultData[0] + = ReturnCodes::InvalidCommand; resultLength = 1; return; } + if (length == 3) + { + uint8_t mode = data[2]; - obj->setSecurityMode(mode == 1); - resultData[0] = ReturnCodes::Success; - resultData[1] = serviceId; - resultLength = 2; - return; - } - resultData[0] = ReturnCodes::GenericError; - resultLength = 1; - }, - // State Callback of PID_SECURITY_MODE - [](SecurityInterfaceObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void { - uint8_t serviceId = data[1] & 0xff; - - if (serviceId != 0) - { - resultData[0] - = ReturnCodes::InvalidCommand; - resultLength = 1; - return; - } - if (length == 2) - { - resultData[0] - = ReturnCodes::Success; - resultData[1] = serviceId; - resultData[2] = obj->isSecurityModeEnabled() ? 1 : 0; - resultLength = 3; - return; - } - resultData[0] = ReturnCodes::GenericError; - resultLength = 1; - }), - new DataProperty( PID_P2P_KEY_TABLE, true, PDT_GENERIC_20, 1, ReadLv3 | WriteLv0 ), // written by ETS - new DataProperty( PID_GRP_KEY_TABLE, true, PDT_GENERIC_18, 50, ReadLv3 | WriteLv0 ), // written by ETS - new DataProperty( PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE, true, PDT_GENERIC_08, 32, ReadLv3 | WriteLv0 ), // written by ETS - new FunctionProperty(this, PID_SECURITY_FAILURES_LOG, - // Command Callback of PID_SECURITY_FAILURES_LOG - [](SecurityInterfaceObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void { - if (length != 3) - { - resultData[0] - = ReturnCodes::DataVoid; - resultLength = 1; - return; - } - uint8_t id = data[1]; - uint8_t info = data[2]; + if (mode > 1) + { + resultData[0] = ReturnCodes::DataVoid; + resultLength = 1; + return; + } - if (id == 0 && info == 0) - { - obj->clearFailureLog(); - resultData[0] = ReturnCodes::Success; - resultData[1] = id; - resultLength = 2; - return; - } - resultData[0] = ReturnCodes::GenericError; - resultLength = 1; - }, - // State Callback of PID_SECURITY_FAILURES_LOG - [](SecurityInterfaceObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void { - if (length != 3) - { - resultData[0] - = ReturnCodes::DataVoid; + obj->setSecurityMode(mode == 1); + resultData[0] = ReturnCodes::Success; + resultData[1] = serviceId; + resultLength = 2; + return; + } + resultData[0] = ReturnCodes::GenericError; resultLength = 1; - return; - } - uint8_t id = data[1]; - uint8_t info = data[2]; + }, + // State Callback of PID_SECURITY_MODE + [](SecurityInterfaceObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void { + uint8_t serviceId = data[1] & 0xff; - // failure counters - if (id == 0 && info == 0) - { - resultData[0] - = ReturnCodes::Success; - resultData[1] = id; - resultData[2] = info; - obj->getFailureCounters(&resultData[3]); // Put 8 bytes in the buffer - resultLength = 3 + 8; - return; - } - // query latest failure by index - else if (id == 1) - { - uint8_t maxBufferSize = resultLength; // Remember the maximum buffer size of the buffer that is provided to us - uint8_t index = info; - uint8_t numBytes = obj->getFromFailureLogByIndex(index, &resultData[2], maxBufferSize); + if (serviceId != 0) + { + resultData[0] + = ReturnCodes::InvalidCommand; + resultLength = 1; + return; + } + if (length == 2) + { + resultData[0] + = ReturnCodes::Success; + resultData[1] = serviceId; + resultData[2] = obj->isSecurityModeEnabled() ? 1 : 0; + resultLength = 3; + return; + } + resultData[0] = ReturnCodes::GenericError; + resultLength = 1; + }), + new DataProperty( PID_P2P_KEY_TABLE, true, PDT_GENERIC_20, 1, ReadLv3 | WriteLv0 ), // written by ETS + new DataProperty( PID_GRP_KEY_TABLE, true, PDT_GENERIC_18, 50, ReadLv3 | WriteLv0 ), // written by ETS + new DataProperty( PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE, true, PDT_GENERIC_08, 32, ReadLv3 | WriteLv0 ), // written by ETS + new FunctionProperty(this, PID_SECURITY_FAILURES_LOG, + // Command Callback of PID_SECURITY_FAILURES_LOG + [](SecurityInterfaceObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void { + if (length != 3) + { + resultData[0] + = ReturnCodes::DataVoid; + resultLength = 1; + return; + } + uint8_t id = data[1]; + uint8_t info = data[2]; - if ( numBytes > 0) + if (id == 0 && info == 0) { + obj->clearFailureLog(); resultData[0] = ReturnCodes::Success; resultData[1] = id; - resultData[2] = index; - resultLength += numBytes; - resultLength = 3 + numBytes; + resultLength = 2; + return; + } + resultData[0] = ReturnCodes::GenericError; + resultLength = 1; + }, + // State Callback of PID_SECURITY_FAILURES_LOG + [](SecurityInterfaceObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void { + if (length != 3) + { + resultData[0] + = ReturnCodes::DataVoid; + resultLength = 1; return; } + uint8_t id = data[1]; + uint8_t info = data[2]; - resultData[0] = ReturnCodes::DataVoid; - resultData[1] = id; - resultLength = 2; - return; - } - resultData[0] = ReturnCodes::GenericError; - resultLength = 1; - }), - new DataProperty( PID_TOOL_KEY, true, PDT_GENERIC_16, 1, ReadLv3 | WriteLv0, (uint8_t*) _fdsk ), // default is FDSK // ETS changes this property during programming from FDSK to some random key! - new DataProperty( PID_SECURITY_REPORT, true, PDT_BITSET8, 1, ReadLv3 | WriteLv0, _secReport ), // Not implemented - new DataProperty( PID_SECURITY_REPORT_CONTROL, true, PDT_BINARY_INFORMATION, 1, ReadLv3 | WriteLv0, _secReportCtrl ), // Not implemented - new DataProperty( PID_SEQUENCE_NUMBER_SENDING, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv0 ), // Updated by our device accordingly - new DataProperty( PID_ZONE_KEY_TABLE, true, PDT_GENERIC_19, 1, ReadLv3 | WriteLv0 ), // written by ETS - new DataProperty( PID_GO_SECURITY_FLAGS, true, PDT_GENERIC_01, 256, ReadLv3 | WriteLv0 ), // written by ETS - new DataProperty( PID_ROLE_TABLE, true, PDT_GENERIC_01, 1, ReadLv3 | WriteLv0 ), // written by ETS - new DataProperty( PID_ERROR_CODE, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint8_t)E_NO_FAULT), - new DataProperty( PID_TOOL_SEQUENCE_NUMBER_SENDING, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv0 ) // Updated by our device accordingly (non-standardized!) - }; - initializeProperties(sizeof(properties), properties); -} + // failure counters + if (id == 0 && info == 0) + { + resultData[0] + = ReturnCodes::Success; + resultData[1] = id; + resultData[2] = info; + obj->getFailureCounters(&resultData[3]); // Put 8 bytes in the buffer + resultLength = 3 + 8; + return; + } + // query latest failure by index + else if (id == 1) + { + uint8_t maxBufferSize = resultLength; // Remember the maximum buffer size of the buffer that is provided to us + uint8_t index = info; + uint8_t numBytes = obj->getFromFailureLogByIndex(index, &resultData[2], maxBufferSize); + + if ( numBytes > 0) + { + resultData[0] = ReturnCodes::Success; + resultData[1] = id; + resultData[2] = index; + resultLength += numBytes; + resultLength = 3 + numBytes; + return; + } -uint8_t* SecurityInterfaceObject::save(uint8_t* buffer) -{ - buffer = pushByte(_state, buffer); - buffer = pushByte(_securityModeEnabled, buffer); + resultData[0] = ReturnCodes::DataVoid; + resultData[1] = id; + resultLength = 2; + return; + } + resultData[0] = ReturnCodes::GenericError; + resultLength = 1; + }), + new DataProperty( PID_TOOL_KEY, true, PDT_GENERIC_16, 1, ReadLv3 | WriteLv0, (uint8_t*) _fdsk ), // default is FDSK // ETS changes this property during programming from FDSK to some random key! + new DataProperty( PID_SECURITY_REPORT, true, PDT_BITSET8, 1, ReadLv3 | WriteLv0, _secReport ), // Not implemented + new DataProperty( PID_SECURITY_REPORT_CONTROL, true, PDT_BINARY_INFORMATION, 1, ReadLv3 | WriteLv0, _secReportCtrl ), // Not implemented + new DataProperty( PID_SEQUENCE_NUMBER_SENDING, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv0 ), // Updated by our device accordingly + new DataProperty( PID_ZONE_KEY_TABLE, true, PDT_GENERIC_19, 1, ReadLv3 | WriteLv0 ), // written by ETS + new DataProperty( PID_GO_SECURITY_FLAGS, true, PDT_GENERIC_01, 256, ReadLv3 | WriteLv0 ), // written by ETS + new DataProperty( PID_ROLE_TABLE, true, PDT_GENERIC_01, 1, ReadLv3 | WriteLv0 ), // written by ETS + new DataProperty( PID_ERROR_CODE, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint8_t)E_NO_FAULT), + new DataProperty( PID_TOOL_SEQUENCE_NUMBER_SENDING, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv0 ) // Updated by our device accordingly (non-standardized!) + }; + initializeProperties(sizeof(properties), properties); + } - return InterfaceObject::save(buffer); -} + uint8_t* SecurityInterfaceObject::save(uint8_t* buffer) + { + buffer = pushByte(_state, buffer); + buffer = pushByte(_securityModeEnabled, buffer); -const uint8_t* SecurityInterfaceObject::restore(const uint8_t* buffer) -{ - uint8_t state = 0; - buffer = popByte(state, buffer); - _state = (LoadState)state; + return InterfaceObject::save(buffer); + } - uint8_t securityModeEnabled = 0; - buffer = popByte(securityModeEnabled, buffer); - _securityModeEnabled = securityModeEnabled; + const uint8_t* SecurityInterfaceObject::restore(const uint8_t* buffer) + { + uint8_t state = 0; + buffer = popByte(state, buffer); + _state = (LoadState)state; - return InterfaceObject::restore(buffer); -} + uint8_t securityModeEnabled = 0; + buffer = popByte(securityModeEnabled, buffer); + _securityModeEnabled = securityModeEnabled; -uint16_t SecurityInterfaceObject::saveSize() -{ - return 2 + InterfaceObject::saveSize(); -} + return InterfaceObject::restore(buffer); + } -void SecurityInterfaceObject::setSecurityMode(bool enabled) -{ - print("Security mode set to: "); - println(enabled ? "enabled" : "disabled"); - _securityModeEnabled = enabled; -} + uint16_t SecurityInterfaceObject::saveSize() + { + return 2 + InterfaceObject::saveSize(); + } -bool SecurityInterfaceObject::isSecurityModeEnabled() -{ - return _securityModeEnabled; -} + void SecurityInterfaceObject::setSecurityMode(bool enabled) + { + print("Security mode set to: "); + println(enabled ? "enabled" : "disabled"); + _securityModeEnabled = enabled; + } -void SecurityInterfaceObject::clearFailureLog() -{ - println("clearFailureLog()"); -} + bool SecurityInterfaceObject::isSecurityModeEnabled() + { + return _securityModeEnabled; + } -void SecurityInterfaceObject::getFailureCounters(uint8_t* data) -{ - memset(data, 0, 8); - println("getFailureCounters()"); -} + void SecurityInterfaceObject::clearFailureLog() + { + println("clearFailureLog()"); + } -uint8_t SecurityInterfaceObject::getFromFailureLogByIndex(uint8_t index, uint8_t* data, uint8_t maxDataLen) -{ - print("getFromFailureLogByIndex(): Index: "); - println(index); - return 0; -} + void SecurityInterfaceObject::getFailureCounters(uint8_t* data) + { + memset(data, 0, 8); + println("getFailureCounters()"); + } -bool SecurityInterfaceObject::isLoaded() -{ - return _state == LS_LOADED; -} + uint8_t SecurityInterfaceObject::getFromFailureLogByIndex(uint8_t index, uint8_t* data, uint8_t maxDataLen) + { + print("getFromFailureLogByIndex(): Index: "); + println(index); + return 0; + } -LoadState SecurityInterfaceObject::loadState() -{ - return _state; -} + bool SecurityInterfaceObject::isLoaded() + { + return _state == LS_LOADED; + } -void SecurityInterfaceObject::loadEvent(const uint8_t* data) -{ - switch (_state) + LoadState SecurityInterfaceObject::loadState() + { + return _state; + } + + void SecurityInterfaceObject::loadEvent(const uint8_t* data) { - case LS_UNLOADED: - loadEventUnloaded(data); - break; + switch (_state) + { + case LS_UNLOADED: + loadEventUnloaded(data); + break; - case LS_LOADING: - loadEventLoading(data); - break; + case LS_LOADING: + loadEventLoading(data); + break; - case LS_LOADED: - loadEventLoaded(data); - break; + case LS_LOADED: + loadEventLoaded(data); + break; - case LS_ERROR: - loadEventError(data); - break; + case LS_ERROR: + loadEventError(data); + break; - default: - /* do nothing */ - break; + default: + /* do nothing */ + break; + } } -} - -void SecurityInterfaceObject::loadEventUnloaded(const uint8_t* data) -{ - uint8_t event = data[0]; - switch (event) + void SecurityInterfaceObject::loadEventUnloaded(const uint8_t* data) { - case LE_NOOP: - case LE_LOAD_COMPLETED: - case LE_ADDITIONAL_LOAD_CONTROLS: - case LE_UNLOAD: - break; - - case LE_START_LOADING: - loadState(LS_LOADING); - break; - - default: - loadState(LS_ERROR); - errorCode(E_GOT_UNDEF_LOAD_CMD); - } -} + uint8_t event = data[0]; -void SecurityInterfaceObject::loadEventLoading(const uint8_t* data) -{ - uint8_t event = data[0]; + switch (event) + { + case LE_NOOP: + case LE_LOAD_COMPLETED: + case LE_ADDITIONAL_LOAD_CONTROLS: + case LE_UNLOAD: + break; + + case LE_START_LOADING: + loadState(LS_LOADING); + break; + + default: + loadState(LS_ERROR); + errorCode(E_GOT_UNDEF_LOAD_CMD); + } + } - switch (event) + void SecurityInterfaceObject::loadEventLoading(const uint8_t* data) { - case LE_NOOP: - case LE_START_LOADING: - break; - - case LE_LOAD_COMPLETED: - loadState(LS_LOADED); - break; - - case LE_UNLOAD: - loadState(LS_UNLOADED); - break; - - case LE_ADDITIONAL_LOAD_CONTROLS: // Not supported here - default: - loadState(LS_ERROR); - errorCode(E_GOT_UNDEF_LOAD_CMD); - } -} + uint8_t event = data[0]; -void SecurityInterfaceObject::loadEventLoaded(const uint8_t* data) -{ - uint8_t event = data[0]; + switch (event) + { + case LE_NOOP: + case LE_START_LOADING: + break; + + case LE_LOAD_COMPLETED: + loadState(LS_LOADED); + break; + + case LE_UNLOAD: + loadState(LS_UNLOADED); + break; + + case LE_ADDITIONAL_LOAD_CONTROLS: // Not supported here + default: + loadState(LS_ERROR); + errorCode(E_GOT_UNDEF_LOAD_CMD); + } + } - switch (event) + void SecurityInterfaceObject::loadEventLoaded(const uint8_t* data) { - case LE_NOOP: - case LE_LOAD_COMPLETED: - break; - - case LE_START_LOADING: - loadState(LS_LOADING); - break; - - case LE_UNLOAD: - loadState(LS_UNLOADED); - break; - - case LE_ADDITIONAL_LOAD_CONTROLS: - loadState(LS_ERROR); - errorCode(E_INVALID_OPCODE); - break; - - default: - loadState(LS_ERROR); - errorCode(E_GOT_UNDEF_LOAD_CMD); - } -} + uint8_t event = data[0]; -void SecurityInterfaceObject::loadEventError(const uint8_t* data) -{ - uint8_t event = data[0]; + switch (event) + { + case LE_NOOP: + case LE_LOAD_COMPLETED: + break; + + case LE_START_LOADING: + loadState(LS_LOADING); + break; + + case LE_UNLOAD: + loadState(LS_UNLOADED); + break; + + case LE_ADDITIONAL_LOAD_CONTROLS: + loadState(LS_ERROR); + errorCode(E_INVALID_OPCODE); + break; + + default: + loadState(LS_ERROR); + errorCode(E_GOT_UNDEF_LOAD_CMD); + } + } - switch (event) + void SecurityInterfaceObject::loadEventError(const uint8_t* data) { - case LE_NOOP: - case LE_LOAD_COMPLETED: - case LE_ADDITIONAL_LOAD_CONTROLS: - case LE_START_LOADING: - break; - - case LE_UNLOAD: - loadState(LS_UNLOADED); - break; - - default: - loadState(LS_ERROR); - errorCode(E_GOT_UNDEF_LOAD_CMD); - } -} + uint8_t event = data[0]; -void SecurityInterfaceObject::loadState(LoadState newState) -{ - if (newState == _state) - return; + switch (event) + { + case LE_NOOP: + case LE_LOAD_COMPLETED: + case LE_ADDITIONAL_LOAD_CONTROLS: + case LE_START_LOADING: + break; + + case LE_UNLOAD: + loadState(LS_UNLOADED); + break; + + default: + loadState(LS_ERROR); + errorCode(E_GOT_UNDEF_LOAD_CMD); + } + } - //beforeStateChange(newState); - _state = newState; -} + void SecurityInterfaceObject::loadState(LoadState newState) + { + if (newState == _state) + return; -void SecurityInterfaceObject::errorCode(ErrorCode errorCode) -{ - uint8_t data = errorCode; - Property* prop = property(PID_ERROR_CODE); - prop->write(data); -} + //beforeStateChange(newState); + _state = newState; + } -void SecurityInterfaceObject::masterReset(EraseCode eraseCode, uint8_t channel) -{ - if (eraseCode == FactoryReset) + void SecurityInterfaceObject::errorCode(ErrorCode errorCode) { - // TODO handle different erase codes - println("Factory reset of security interface object requested."); - setSecurityMode(false); - property(PID_TOOL_KEY)->write(1, 1, _fdsk); + uint8_t data = errorCode; + Property* prop = property(PID_ERROR_CODE); + prop->write(data); } -} -const uint8_t* SecurityInterfaceObject::toolKey() -{ - // There is only one tool key - const uint8_t* toolKey = propertyData(PID_TOOL_KEY); - return toolKey; -} - -const uint8_t* SecurityInterfaceObject::p2pKey(uint16_t addressIndex) -{ - if (!isLoaded()) - return nullptr; + void SecurityInterfaceObject::masterReset(EraseCode eraseCode, uint8_t channel) + { + if (eraseCode == FactoryReset) + { + // TODO handle different erase codes + println("Factory reset of security interface object requested."); + setSecurityMode(false); + property(PID_TOOL_KEY)->write(1, 1, _fdsk); + } + } - // Get number of entries for this property - uint16_t numElements = getNumberOfElements(PID_P2P_KEY_TABLE); + const uint8_t* SecurityInterfaceObject::toolKey() + { + // There is only one tool key + const uint8_t* toolKey = propertyData(PID_TOOL_KEY); + return toolKey; + } - if (numElements > 0) + const uint8_t* SecurityInterfaceObject::p2pKey(uint16_t addressIndex) { - uint8_t elementSize = propertySize(PID_P2P_KEY_TABLE); + if (!isLoaded()) + return nullptr; - // Search for address index - uint8_t entry[elementSize]; // 2 bytes index + keysize (16 bytes) + 2 bytes(roles) = 20 bytes + // Get number of entries for this property + uint16_t numElements = getNumberOfElements(PID_P2P_KEY_TABLE); - for (int i = 1; i <= numElements; i++) + if (numElements > 0) { - property(PID_P2P_KEY_TABLE)->read(i, 1, entry); - uint16_t index = (entry[0] << 8) | entry[1]; + uint8_t elementSize = propertySize(PID_P2P_KEY_TABLE); - if (index > addressIndex) - { - return nullptr; - } + // Search for address index + uint8_t entry[elementSize]; // 2 bytes index + keysize (16 bytes) + 2 bytes(roles) = 20 bytes - if (index == addressIndex) + for (int i = 1; i <= numElements; i++) { - return propertyData(PID_P2P_KEY_TABLE, i) + sizeof(index); + property(PID_P2P_KEY_TABLE)->read(i, 1, entry); + uint16_t index = (entry[0] << 8) | entry[1]; + + if (index > addressIndex) + { + return nullptr; + } + + if (index == addressIndex) + { + return propertyData(PID_P2P_KEY_TABLE, i) + sizeof(index); + } } } - } - - return nullptr; -} -const uint8_t* SecurityInterfaceObject::groupKey(uint16_t addressIndex) -{ - if (!isLoaded()) return nullptr; + } - // Get number of entries for this property - uint16_t numElements = getNumberOfElements(PID_GRP_KEY_TABLE); - - if (numElements > 0) + const uint8_t* SecurityInterfaceObject::groupKey(uint16_t addressIndex) { - uint8_t elementSize = propertySize(PID_GRP_KEY_TABLE); + if (!isLoaded()) + return nullptr; - // Search for address index - uint8_t entry[elementSize]; // 2 bytes index + keysize (16 bytes) = 18 bytes + // Get number of entries for this property + uint16_t numElements = getNumberOfElements(PID_GRP_KEY_TABLE); - for (int i = 1; i <= numElements; i++) + if (numElements > 0) { - property(PID_GRP_KEY_TABLE)->read(i, 1, entry); - uint16_t index = ((entry[0] << 8) | entry[1]); + uint8_t elementSize = propertySize(PID_GRP_KEY_TABLE); - if (index > addressIndex) - { - return nullptr; - } + // Search for address index + uint8_t entry[elementSize]; // 2 bytes index + keysize (16 bytes) = 18 bytes - if (index == addressIndex) + for (int i = 1; i <= numElements; i++) { - return propertyData(PID_GRP_KEY_TABLE, i) + sizeof(index); + property(PID_GRP_KEY_TABLE)->read(i, 1, entry); + uint16_t index = ((entry[0] << 8) | entry[1]); + + if (index > addressIndex) + { + return nullptr; + } + + if (index == addressIndex) + { + return propertyData(PID_GRP_KEY_TABLE, i) + sizeof(index); + } } } - } - - return nullptr; -} -uint16_t SecurityInterfaceObject::indAddressIndex(uint16_t indAddr) -{ - // Get number of entries for this property - uint16_t numElements = getNumberOfElements(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE); + return nullptr; + } - if (numElements > 0) + uint16_t SecurityInterfaceObject::indAddressIndex(uint16_t indAddr) { - uint8_t elementSize = propertySize(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE); + // Get number of entries for this property + uint16_t numElements = getNumberOfElements(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE); - // Search for individual address - uint8_t entry[elementSize]; // 2 bytes address + 6 bytes seqno = 8 bytes - - for (int i = 1; i <= numElements; i++) + if (numElements > 0) { - property(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE)->read(i, 1, entry); - uint16_t addr = (entry[0] << 8) | entry[1]; + uint8_t elementSize = propertySize(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE); + + // Search for individual address + uint8_t entry[elementSize]; // 2 bytes address + 6 bytes seqno = 8 bytes - if (addr == indAddr) + for (int i = 1; i <= numElements; i++) { - return i; + property(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE)->read(i, 1, entry); + uint16_t addr = (entry[0] << 8) | entry[1]; + + if (addr == indAddr) + { + return i; + } } } - } - // Not found - return 0; -} - -void SecurityInterfaceObject::setSequenceNumber(bool toolAccess, uint64_t seqNum) -{ - uint8_t seqBytes[6] = {0x00}; - sixBytesFromUInt64(seqNum, seqBytes); + // Not found + return 0; + } - if (toolAccess) + void SecurityInterfaceObject::setSequenceNumber(bool toolAccess, uint64_t seqNum) { - property(PID_TOOL_SEQUENCE_NUMBER_SENDING)->write(1, 1, seqBytes); + uint8_t seqBytes[6] = {0x00}; + sixBytesFromUInt64(seqNum, seqBytes); + + if (toolAccess) + { + property(PID_TOOL_SEQUENCE_NUMBER_SENDING)->write(1, 1, seqBytes); + } + else + { + property(PID_SEQUENCE_NUMBER_SENDING)->write(1, 1, seqBytes); + } } - else + + uint16_t SecurityInterfaceObject::getNumberOfElements(PropertyID propId) { - property(PID_SEQUENCE_NUMBER_SENDING)->write(1, 1, seqBytes); - } -} + // Get number of entries for this property + uint16_t numElements = 0; -uint16_t SecurityInterfaceObject::getNumberOfElements(PropertyID propId) -{ - // Get number of entries for this property - uint16_t numElements = 0; + uint8_t data[sizeof(uint16_t)]; // is sizeof(_currentElements) which is uint16_t + uint8_t count = property(propId)->read(0, 1, data); - uint8_t data[sizeof(uint16_t)]; // is sizeof(_currentElements) which is uint16_t - uint8_t count = property(propId)->read(0, 1, data); + if (count > 0) + { + popWord(numElements, data); + } - if (count > 0) - { - popWord(numElements, data); + return numElements; } - return numElements; -} - -uint64_t SecurityInterfaceObject::getLastValidSequenceNumber(uint16_t deviceAddr) -{ - // Get number of entries for this property - uint16_t numElements = getNumberOfElements(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE); - - if (numElements > 0) + uint64_t SecurityInterfaceObject::getLastValidSequenceNumber(uint16_t deviceAddr) { - uint8_t elementSize = propertySize(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE); - - // Search for individual address - uint8_t entry[elementSize]; // 2 bytes address + 6 bytes seqno = 8 bytes + // Get number of entries for this property + uint16_t numElements = getNumberOfElements(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE); - for (int i = 1; i <= numElements; i++) + if (numElements > 0) { - property(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE)->read(i, 1, entry); - uint16_t addr = (entry[0] << 8) | entry[1]; + uint8_t elementSize = propertySize(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE); - if (addr == deviceAddr) + // Search for individual address + uint8_t entry[elementSize]; // 2 bytes address + 6 bytes seqno = 8 bytes + + for (int i = 1; i <= numElements; i++) { - return sixBytesToUInt64(&entry[2]); + property(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE)->read(i, 1, entry); + uint16_t addr = (entry[0] << 8) | entry[1]; + + if (addr == deviceAddr) + { + return sixBytesToUInt64(&entry[2]); + } } } - } - - return 0; -} -void SecurityInterfaceObject::setLastValidSequenceNumber(uint16_t deviceAddr, uint64_t seqNum) -{ - // Get number of entries for this property - uint16_t numElements = getNumberOfElements(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE); + return 0; + } - if (numElements > 0) + void SecurityInterfaceObject::setLastValidSequenceNumber(uint16_t deviceAddr, uint64_t seqNum) { - uint8_t elementSize = propertySize(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE); - - // Search for individual address - uint8_t entry[elementSize]; // 2 bytes address + 6 bytes seqno = 8 bytes + // Get number of entries for this property + uint16_t numElements = getNumberOfElements(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE); - for (int i = 1; i <= numElements; i++) + if (numElements > 0) { - property(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE)->read(i, 1, entry); - uint16_t addr = (entry[0] << 8) | entry[1]; + uint8_t elementSize = propertySize(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE); - if (addr == deviceAddr) + // Search for individual address + uint8_t entry[elementSize]; // 2 bytes address + 6 bytes seqno = 8 bytes + + for (int i = 1; i <= numElements; i++) { - sixBytesFromUInt64(seqNum, &entry[2]); - property(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE)->write(i, 1, entry); + property(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE)->read(i, 1, entry); + uint16_t addr = (entry[0] << 8) | entry[1]; + + if (addr == deviceAddr) + { + sixBytesFromUInt64(seqNum, &entry[2]); + property(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE)->write(i, 1, entry); + } } } } -} -DataSecurity SecurityInterfaceObject::getGroupObjectSecurity(uint16_t index) -{ - // security table uses same index as group object table + DataSecurity SecurityInterfaceObject::getGroupObjectSecurity(uint16_t index) + { + // security table uses same index as group object table - uint8_t data[propertySize(PID_GO_SECURITY_FLAGS)]; + uint8_t data[propertySize(PID_GO_SECURITY_FLAGS)]; - uint8_t count = property(PID_GO_SECURITY_FLAGS)->read(index, 1, data); + uint8_t count = property(PID_GO_SECURITY_FLAGS)->read(index, 1, data); - if (count > 0) - { - // write access flags, approved spec. AN158, p.97 - bool conf = (data[0] & 2) == 2; - bool auth = (data[0] & 1) == 1; - return conf ? DataSecurity::AuthConf : auth ? DataSecurity::Auth : DataSecurity::None; - } + if (count > 0) + { + // write access flags, approved spec. AN158, p.97 + bool conf = (data[0] & 2) == 2; + bool auth = (data[0] & 1) == 1; + return conf ? DataSecurity::AuthConf : auth ? DataSecurity::Auth : DataSecurity::None; + } - return DataSecurity::None; + return DataSecurity::None; + } } - -#endif - +#endif \ No newline at end of file diff --git a/src/knx/data_secure/security_interface_object.h b/src/knx/data_secure/security_interface_object.h index 5de959f1..82b1c2a0 100644 --- a/src/knx/data_secure/security_interface_object.h +++ b/src/knx/data_secure/security_interface_object.h @@ -6,59 +6,62 @@ #include "../interface_object/interface_object.h" #include "../knx_types.h" -class SecurityInterfaceObject: public InterfaceObject +namespace Knx { - public: - SecurityInterfaceObject(); + class SecurityInterfaceObject: public InterfaceObject + { + public: + SecurityInterfaceObject(); - void masterReset(EraseCode eraseCode, uint8_t channel) override; + void masterReset(EraseCode eraseCode, uint8_t channel) override; - bool isSecurityModeEnabled(); + bool isSecurityModeEnabled(); - bool isLoaded(); + bool isLoaded(); - const uint8_t* toolKey(); // returns single tool key (ETS) - const uint8_t* p2pKey(uint16_t addressIndex); // returns p2p key for IA index - const uint8_t* groupKey(uint16_t addressIndex); // returns group key for group address index + const uint8_t* toolKey(); // returns single tool key (ETS) + const uint8_t* p2pKey(uint16_t addressIndex); // returns p2p key for IA index + const uint8_t* groupKey(uint16_t addressIndex); // returns group key for group address index - uint16_t indAddressIndex(uint16_t indAddr); // returns 1-based index of address in security IA table + uint16_t indAddressIndex(uint16_t indAddr); // returns 1-based index of address in security IA table - void setSequenceNumber(bool toolAccess, uint64_t seqNum); - uint64_t getLastValidSequenceNumber(uint16_t deviceAddr); - void setLastValidSequenceNumber(uint16_t deviceAddr, uint64_t seqNum); + void setSequenceNumber(bool toolAccess, uint64_t seqNum); + uint64_t getLastValidSequenceNumber(uint16_t deviceAddr); + void setLastValidSequenceNumber(uint16_t deviceAddr, uint64_t seqNum); - DataSecurity getGroupObjectSecurity(uint16_t index); + DataSecurity getGroupObjectSecurity(uint16_t index); - LoadState loadState(); - uint8_t* save(uint8_t* buffer) override; - const uint8_t* restore(const uint8_t* buffer) override; - uint16_t saveSize() override; + LoadState loadState(); + uint8_t* save(uint8_t* buffer) override; + const uint8_t* restore(const uint8_t* buffer) override; + uint16_t saveSize() override; - private: - void setSecurityMode(bool enabled); + private: + void setSecurityMode(bool enabled); - void clearFailureLog(); - void getFailureCounters(uint8_t* data); - uint8_t getFromFailureLogByIndex(uint8_t index, uint8_t* data, uint8_t maxDataLen); + void clearFailureLog(); + void getFailureCounters(uint8_t* data); + uint8_t getFromFailureLogByIndex(uint8_t index, uint8_t* data, uint8_t maxDataLen); - void errorCode(ErrorCode errorCode); + void errorCode(ErrorCode errorCode); - void loadEvent(const uint8_t* data); - void loadEventUnloaded(const uint8_t* data); - void loadEventLoading(const uint8_t* data); - void loadEventLoaded(const uint8_t* data); - void loadEventError(const uint8_t* data); + void loadEvent(const uint8_t* data); + void loadEventUnloaded(const uint8_t* data); + void loadEventLoading(const uint8_t* data); + void loadEventLoaded(const uint8_t* data); + void loadEventError(const uint8_t* data); - void loadState(LoadState newState); - LoadState _state = LS_UNLOADED; + void loadState(LoadState newState); + LoadState _state = LS_UNLOADED; - bool _securityModeEnabled {false}; + bool _securityModeEnabled {false}; - uint16_t getNumberOfElements(PropertyID propId); + uint16_t getNumberOfElements(PropertyID propId); - // Our FDSK - static const uint8_t _fdsk[]; - static uint8_t _secReport[]; - static uint8_t _secReportCtrl[]; -}; -#endif + // Our FDSK + static const uint8_t _fdsk[]; + static uint8_t _secReport[]; + static uint8_t _secReportCtrl[]; + }; +} +#endif \ No newline at end of file diff --git a/src/knx/datalink_layer/cemi_frame.cpp b/src/knx/datalink_layer/cemi_frame.cpp index bff85ca2..e29d8cda 100644 --- a/src/knx/datalink_layer/cemi_frame.cpp +++ b/src/knx/datalink_layer/cemi_frame.cpp @@ -76,355 +76,358 @@ Control Field 1 ------+--------------------------------------------------------------- */ -CemiFrame::CemiFrame(uint8_t* data, uint16_t length) - : _npdu(data + data[1] + NPDU_LPDU_DIFF, *this), - _tpdu(data + data[1] + TPDU_LPDU_DIFF, *this), - _apdu(data + data[1] + APDU_LPDU_DIFF, *this) +namespace Knx { - _data = data; - _ctrl1 = data + data[1] + CEMI_HEADER_SIZE; - _length = length; -} - -CemiFrame::CemiFrame(uint8_t apduLength) - : _data(buffer), - _npdu(_data + NPDU_LPDU_DIFF, *this), - _tpdu(_data + TPDU_LPDU_DIFF, *this), - _apdu(_data + APDU_LPDU_DIFF, *this) -{ - _ctrl1 = _data + CEMI_HEADER_SIZE; - - memset(_data, 0, apduLength + APDU_LPDU_DIFF); - _ctrl1[0] |= Broadcast; - _npdu.octetCount(apduLength); - _length = _npdu.length() + NPDU_LPDU_DIFF; -} - -CemiFrame::CemiFrame(const CemiFrame& other) - : _data(buffer), - _npdu(_data + NPDU_LPDU_DIFF, *this), - _tpdu(_data + TPDU_LPDU_DIFF, *this), - _apdu(_data + APDU_LPDU_DIFF, *this) -{ - _ctrl1 = _data + CEMI_HEADER_SIZE; - _length = other._length; + CemiFrame::CemiFrame(uint8_t* data, uint16_t length) + : _npdu(data + data[1] + NPDU_LPDU_DIFF, *this), + _tpdu(data + data[1] + TPDU_LPDU_DIFF, *this), + _apdu(data + data[1] + APDU_LPDU_DIFF, *this) + { + _data = data; + _ctrl1 = data + data[1] + CEMI_HEADER_SIZE; + _length = length; + } - memcpy(_data, other._data, other.totalLenght()); -} + CemiFrame::CemiFrame(uint8_t apduLength) + : _data(buffer), + _npdu(_data + NPDU_LPDU_DIFF, *this), + _tpdu(_data + TPDU_LPDU_DIFF, *this), + _apdu(_data + APDU_LPDU_DIFF, *this) + { + _ctrl1 = _data + CEMI_HEADER_SIZE; -CemiFrame& CemiFrame::operator=(CemiFrame other) -{ - _length = other._length; - _data = buffer; - _ctrl1 = _data + CEMI_HEADER_SIZE; - memcpy(_data, other._data, other.totalLenght()); - _npdu._data = _data + NPDU_LPDU_DIFF; - _tpdu._data = _data + TPDU_LPDU_DIFF; - _apdu._data = _data + APDU_LPDU_DIFF; - return *this; -} - - -MessageCode CemiFrame::messageCode() const -{ - return (MessageCode)_data[0]; -} + memset(_data, 0, apduLength + APDU_LPDU_DIFF); + _ctrl1[0] |= Broadcast; + _npdu.octetCount(apduLength); + _length = _npdu.length() + NPDU_LPDU_DIFF; + } -void CemiFrame::messageCode(MessageCode msgCode) -{ - _data[0] = msgCode; -} + CemiFrame::CemiFrame(const CemiFrame& other) + : _data(buffer), + _npdu(_data + NPDU_LPDU_DIFF, *this), + _tpdu(_data + TPDU_LPDU_DIFF, *this), + _apdu(_data + APDU_LPDU_DIFF, *this) + { + _ctrl1 = _data + CEMI_HEADER_SIZE; + _length = other._length; -uint16_t CemiFrame::totalLenght() const -{ - return _length; -} + memcpy(_data, other._data, other.totalLenght()); + } -uint16_t CemiFrame::telegramLengthtTP() const -{ - if (frameType() == StandardFrame) - return totalLenght() - 2; /*-AddInfo -MsgCode - only one CTRL + CRC, */ - else - return totalLenght() - 1; /*-AddInfo -MsgCode + CRC, */ -} + CemiFrame& CemiFrame::operator=(CemiFrame other) + { + _length = other._length; + _data = buffer; + _ctrl1 = _data + CEMI_HEADER_SIZE; + memcpy(_data, other._data, other.totalLenght()); + _npdu._data = _data + NPDU_LPDU_DIFF; + _tpdu._data = _data + TPDU_LPDU_DIFF; + _apdu._data = _data + APDU_LPDU_DIFF; + return *this; + } -void CemiFrame::fillTelegramTP(uint8_t* data) -{ - uint16_t len = telegramLengthtTP(); - if (frameType() == StandardFrame) + MessageCode CemiFrame::messageCode() const { - uint8_t octet5 = (_ctrl1[1] & 0xF0) | (_ctrl1[6] & 0x0F); - data[0] = _ctrl1[0]; //CTRL - memcpy(data + 1, _ctrl1 + 2, 4); // SA, DA - data[5] = octet5; // LEN; Hopcount, .. - memcpy(data + 6, _ctrl1 + 7, len - 7); // APDU + return (MessageCode)_data[0]; } - else + + void CemiFrame::messageCode(MessageCode msgCode) { - memcpy(data, _ctrl1, len - 1); + _data[0] = msgCode; } - data[len - 1] = calcCrcTP(data, len - 1); -} -#ifndef KNX_NO_RF -uint16_t CemiFrame::telegramLengthtRF() const -{ - return totalLenght() - 3; -} + uint16_t CemiFrame::totalLenght() const + { + return _length; + } -void CemiFrame::fillTelegramRF(uint8_t* data) -{ - uint16_t len = telegramLengthtRF(); - - // We prepare the actual KNX telegram for RF here only. - // The packaging into blocks with CRC16 (Format based on FT3 Data Link Layer (IEC 870-5)) - // is done in the RF Data Link Layer code. - // RF always uses the Extended Frame Format. However, the length field is missing (right before the APDU) - // as there is already a length field at the beginning of the raw RF frame which is also used by the - // physical layer to control the HW packet engine of the transceiver. - - data[0] = _ctrl1[1] & 0x0F; // KNX CTRL field for RF (bits 3..0 EFF only), bits 7..4 are set to 0 for asynchronous RF frames - memcpy(data + 1, _ctrl1 + 2, 4); // SA, DA - data[5] = (_ctrl1[1] & 0xF0) | ((_rfLfn & 0x7) << 1) | ((_ctrl1[0] & 0x10) >> 4); // L/NPCI field: AT, Hopcount, LFN, AET - memcpy(data + 6, _ctrl1 + 7, len - 6); // APDU - - //printHex("cEMI_fill: ", &data[0], len); -} -#endif -uint8_t* CemiFrame::data() -{ - return _data; -} + uint16_t CemiFrame::telegramLengthtTP() const + { + if (frameType() == StandardFrame) + return totalLenght() - 2; /*-AddInfo -MsgCode - only one CTRL + CRC, */ + else + return totalLenght() - 1; /*-AddInfo -MsgCode + CRC, */ + } -uint16_t CemiFrame::dataLength() -{ - return _length; -} + void CemiFrame::fillTelegramTP(uint8_t* data) + { + uint16_t len = telegramLengthtTP(); + + if (frameType() == StandardFrame) + { + uint8_t octet5 = (_ctrl1[1] & 0xF0) | (_ctrl1[6] & 0x0F); + data[0] = _ctrl1[0]; //CTRL + memcpy(data + 1, _ctrl1 + 2, 4); // SA, DA + data[5] = octet5; // LEN; Hopcount, .. + memcpy(data + 6, _ctrl1 + 7, len - 7); // APDU + } + else + { + memcpy(data, _ctrl1, len - 1); + } + + data[len - 1] = calcCrcTP(data, len - 1); + } +#ifndef KNX_NO_RF + uint16_t CemiFrame::telegramLengthtRF() const + { + return totalLenght() - 3; + } -uint8_t CemiFrame::calcCrcTP(uint8_t* buffer, uint16_t len) -{ - uint8_t crc = 0xFF; + void CemiFrame::fillTelegramRF(uint8_t* data) + { + uint16_t len = telegramLengthtRF(); - for (uint16_t i = 0; i < len; i++) - crc ^= buffer[i]; + // We prepare the actual KNX telegram for RF here only. + // The packaging into blocks with CRC16 (Format based on FT3 Data Link Layer (IEC 870-5)) + // is done in the RF Data Link Layer code. + // RF always uses the Extended Frame Format. However, the length field is missing (right before the APDU) + // as there is already a length field at the beginning of the raw RF frame which is also used by the + // physical layer to control the HW packet engine of the transceiver. - return crc; -} + data[0] = _ctrl1[1] & 0x0F; // KNX CTRL field for RF (bits 3..0 EFF only), bits 7..4 are set to 0 for asynchronous RF frames + memcpy(data + 1, _ctrl1 + 2, 4); // SA, DA + data[5] = (_ctrl1[1] & 0xF0) | ((_rfLfn & 0x7) << 1) | ((_ctrl1[0] & 0x10) >> 4); // L/NPCI field: AT, Hopcount, LFN, AET + memcpy(data + 6, _ctrl1 + 7, len - 6); // APDU -FrameFormat CemiFrame::frameType() const -{ - return (FrameFormat)(_ctrl1[0] & StandardFrame); -} + //printHex("cEMI_fill: ", &data[0], len); + } +#endif + uint8_t* CemiFrame::data() + { + return _data; + } -void CemiFrame::frameType(FrameFormat type) -{ - _ctrl1[0] &= ~StandardFrame; - _ctrl1[0] |= type; -} + uint16_t CemiFrame::dataLength() + { + return _length; + } -Repetition CemiFrame::repetition() const -{ - return (Repetition)(_ctrl1[0] & RepetitionAllowed); -} + uint8_t CemiFrame::calcCrcTP(uint8_t* buffer, uint16_t len) + { + uint8_t crc = 0xFF; -void CemiFrame::repetition(Repetition rep) -{ - _ctrl1[0] &= ~RepetitionAllowed; - _ctrl1[0] |= rep; -} + for (uint16_t i = 0; i < len; i++) + crc ^= buffer[i]; -SystemBroadcast CemiFrame::systemBroadcast() const -{ - return (SystemBroadcast)(_ctrl1[0] & Broadcast); -} + return crc; + } -void CemiFrame::systemBroadcast(SystemBroadcast value) -{ - _ctrl1[0] &= ~Broadcast; - _ctrl1[0] |= value; -} + FrameFormat CemiFrame::frameType() const + { + return (FrameFormat)(_ctrl1[0] & StandardFrame); + } -Priority CemiFrame::priority() const -{ - return (Priority)(_ctrl1[0] & LowPriority); -} + void CemiFrame::frameType(FrameFormat type) + { + _ctrl1[0] &= ~StandardFrame; + _ctrl1[0] |= type; + } -void CemiFrame::priority(Priority value) -{ - _ctrl1[0] &= ~LowPriority; - _ctrl1[0] |= value; -} + Repetition CemiFrame::repetition() const + { + return (Repetition)(_ctrl1[0] & RepetitionAllowed); + } -AckType CemiFrame::ack() const -{ - return (AckType)(_ctrl1[0] & AckRequested); -} + void CemiFrame::repetition(Repetition rep) + { + _ctrl1[0] &= ~RepetitionAllowed; + _ctrl1[0] |= rep; + } -void CemiFrame::ack(AckType value) -{ - _ctrl1[0] &= ~AckRequested; - _ctrl1[0] |= value; -} + SystemBroadcast CemiFrame::systemBroadcast() const + { + return (SystemBroadcast)(_ctrl1[0] & Broadcast); + } -Confirm CemiFrame::confirm() const -{ - return (Confirm)(_ctrl1[0] & ConfirmError); -} + void CemiFrame::systemBroadcast(SystemBroadcast value) + { + _ctrl1[0] &= ~Broadcast; + _ctrl1[0] |= value; + } -void CemiFrame::confirm(Confirm value) -{ - _ctrl1[0] &= ~ConfirmError; - _ctrl1[0] |= value; -} + Priority CemiFrame::priority() const + { + return (Priority)(_ctrl1[0] & LowPriority); + } -AddressType CemiFrame::addressType() const -{ - return (AddressType)(_ctrl1[1] & GroupAddress); -} + void CemiFrame::priority(Priority value) + { + _ctrl1[0] &= ~LowPriority; + _ctrl1[0] |= value; + } -void CemiFrame::addressType(AddressType value) -{ - _ctrl1[1] &= ~GroupAddress; - _ctrl1[1] |= value; -} + AckType CemiFrame::ack() const + { + return (AckType)(_ctrl1[0] & AckRequested); + } -uint8_t CemiFrame::hopCount() const -{ - return ((_ctrl1[1] >> 4) & 0x7); -} + void CemiFrame::ack(AckType value) + { + _ctrl1[0] &= ~AckRequested; + _ctrl1[0] |= value; + } -void CemiFrame::hopCount(uint8_t value) -{ - _ctrl1[1] &= ~(0x7 << 4); - _ctrl1[1] |= ((value & 0x7) << 4); -} + Confirm CemiFrame::confirm() const + { + return (Confirm)(_ctrl1[0] & ConfirmError); + } -uint16_t CemiFrame::sourceAddress() const -{ - uint16_t addr; - popWord(addr, _ctrl1 + 2); - return addr; -} + void CemiFrame::confirm(Confirm value) + { + _ctrl1[0] &= ~ConfirmError; + _ctrl1[0] |= value; + } -void CemiFrame::sourceAddress(uint16_t value) -{ - pushWord(value, _ctrl1 + 2); -} + AddressType CemiFrame::addressType() const + { + return (AddressType)(_ctrl1[1] & GroupAddress); + } -uint16_t CemiFrame::destinationAddress() const -{ - uint16_t addr; - popWord(addr, _ctrl1 + 4); - return addr; -} + void CemiFrame::addressType(AddressType value) + { + _ctrl1[1] &= ~GroupAddress; + _ctrl1[1] |= value; + } -void CemiFrame::destinationAddress(uint16_t value) -{ - pushWord(value, _ctrl1 + 4); -} -#ifndef KNX_NO_RF -uint8_t* CemiFrame::rfSerialOrDoA() const -{ - return _rfSerialOrDoA; -} + uint8_t CemiFrame::hopCount() const + { + return ((_ctrl1[1] >> 4) & 0x7); + } -void CemiFrame::rfSerialOrDoA(const uint8_t* rfSerialOrDoA) -{ - _rfSerialOrDoA = (uint8_t*)rfSerialOrDoA; -} + void CemiFrame::hopCount(uint8_t value) + { + _ctrl1[1] &= ~(0x7 << 4); + _ctrl1[1] |= ((value & 0x7) << 4); + } -uint8_t CemiFrame::rfInfo() const -{ - return _rfInfo; -} + uint16_t CemiFrame::sourceAddress() const + { + uint16_t addr; + popWord(addr, _ctrl1 + 2); + return addr; + } -void CemiFrame::rfInfo(uint8_t rfInfo) -{ - _rfInfo = rfInfo; -} + void CemiFrame::sourceAddress(uint16_t value) + { + pushWord(value, _ctrl1 + 2); + } -uint8_t CemiFrame::rfLfn() const -{ - return _rfLfn; -} + uint16_t CemiFrame::destinationAddress() const + { + uint16_t addr; + popWord(addr, _ctrl1 + 4); + return addr; + } -void CemiFrame::rfLfn(uint8_t rfLfn) -{ - _rfLfn = rfLfn; -} -#endif -NPDU& CemiFrame::npdu() -{ - return _npdu; -} + void CemiFrame::destinationAddress(uint16_t value) + { + pushWord(value, _ctrl1 + 4); + } +#ifndef KNX_NO_RF + uint8_t* CemiFrame::rfSerialOrDoA() const + { + return _rfSerialOrDoA; + } -TPDU& CemiFrame::tpdu() -{ - return _tpdu; -} + void CemiFrame::rfSerialOrDoA(const uint8_t* rfSerialOrDoA) + { + _rfSerialOrDoA = (uint8_t*)rfSerialOrDoA; + } -APDU& CemiFrame::apdu() -{ - return _apdu; -} + uint8_t CemiFrame::rfInfo() const + { + return _rfInfo; + } -bool CemiFrame::valid() const -{ - uint8_t addInfoLen = _data[1]; - uint8_t apduLen = _data[_data[1] + NPDU_LPDU_DIFF]; + void CemiFrame::rfInfo(uint8_t rfInfo) + { + _rfInfo = rfInfo; + } - if (_length != 0 && _length != (addInfoLen + apduLen + NPDU_LPDU_DIFF + 2)) + uint8_t CemiFrame::rfLfn() const { - print("length issue, length: "); - print(_length); - print(" addInfoLen: "); - print(addInfoLen); - print(" apduLen: "); - print(apduLen); - print(" expected length: "); - println(addInfoLen + apduLen + NPDU_LPDU_DIFF + 2); - printHex("Frame: ", _data, _length, true); + return _rfLfn; + } - return false; + void CemiFrame::rfLfn(uint8_t rfLfn) + { + _rfLfn = rfLfn; + } +#endif + NPDU& CemiFrame::npdu() + { + return _npdu; } - if ((_ctrl1[0] & 0x40) > 0 // Bit 6 has do be 0 - || (_ctrl1[1] & 0xF) > 0 // only standard or extended frames - || _npdu.octetCount() == 0xFF // not allowed - || (_npdu.octetCount() > 15 && frameType() == StandardFrame) - ) + TPDU& CemiFrame::tpdu() { - print("Other issue"); - return false; + return _tpdu; } - return true; -} + APDU& CemiFrame::apdu() + { + return _apdu; + } -void CemiFrame::printIt() const -{ + bool CemiFrame::valid() const + { + uint8_t addInfoLen = _data[1]; + uint8_t apduLen = _data[_data[1] + NPDU_LPDU_DIFF]; + + if (_length != 0 && _length != (addInfoLen + apduLen + NPDU_LPDU_DIFF + 2)) + { + print("length issue, length: "); + print(_length); + print(" addInfoLen: "); + print(addInfoLen); + print(" apduLen: "); + print(apduLen); + print(" expected length: "); + println(addInfoLen + apduLen + NPDU_LPDU_DIFF + 2); + printHex("Frame: ", _data, _length, true); + + return false; + } + + if ((_ctrl1[0] & 0x40) > 0 // Bit 6 has do be 0 + || (_ctrl1[1] & 0xF) > 0 // only standard or extended frames + || _npdu.octetCount() == 0xFF // not allowed + || (_npdu.octetCount() > 15 && frameType() == StandardFrame) + ) + { + print("Other issue"); + return false; + } + + return true; + } + + void CemiFrame::printIt() const + { #ifndef KNX_NO_PRINT - print("DPDU:"); - print(enum_name(frameType())); - print(" "); - print(enum_name(systemBroadcast())); - print(" "); - print(enum_name(ack())); - print(" "); - print(enum_name(repetition())); - print(" "); - print(enum_name(priority())); - print(" from "); - print_ia(sourceAddress()); - print(" to "); - print(enum_name(addressType())); - print(" "); - - if (addressType() == AddressType::IndividualAddress) - print_ia(destinationAddress()); - else - print_ga(destinationAddress()); + print("DPDU:"); + print(enum_name(frameType())); + print(" "); + print(enum_name(systemBroadcast())); + print(" "); + print(enum_name(ack())); + print(" "); + print(enum_name(repetition())); + print(" "); + print(enum_name(priority())); + print(" from "); + print_ia(sourceAddress()); + print(" to "); + print(enum_name(addressType())); + print(" "); + + if (addressType() == AddressType::IndividualAddress) + print_ia(destinationAddress()); + else + print_ga(destinationAddress()); #endif -} + } +} \ No newline at end of file diff --git a/src/knx/datalink_layer/cemi_frame.h b/src/knx/datalink_layer/cemi_frame.h index f29f049f..ff255b28 100644 --- a/src/knx/datalink_layer/cemi_frame.h +++ b/src/knx/datalink_layer/cemi_frame.h @@ -18,78 +18,81 @@ // Mesg Code and additional info length #define CEMI_HEADER_SIZE 2 -class CemiFrame : public IPrintable +namespace Knx { - friend class DataLinkLayer; + class CemiFrame : public IPrintable + { + friend class DataLinkLayer; - public: - CemiFrame(uint8_t* data, uint16_t length); - CemiFrame(uint8_t apduLength); - CemiFrame(const CemiFrame& other); - CemiFrame& operator=(CemiFrame other); + public: + CemiFrame(uint8_t* data, uint16_t length); + CemiFrame(uint8_t apduLength); + CemiFrame(const CemiFrame& other); + CemiFrame& operator=(CemiFrame other); - MessageCode messageCode() const; - void messageCode(MessageCode value); - uint16_t totalLenght() const; - uint16_t telegramLengthtTP() const; - void fillTelegramTP(uint8_t* data); - uint16_t telegramLengthtRF() const; - void fillTelegramRF(uint8_t* data); - uint8_t* data(); - uint16_t dataLength(); + MessageCode messageCode() const; + void messageCode(MessageCode value); + uint16_t totalLenght() const; + uint16_t telegramLengthtTP() const; + void fillTelegramTP(uint8_t* data); + uint16_t telegramLengthtRF() const; + void fillTelegramRF(uint8_t* data); + uint8_t* data(); + uint16_t dataLength(); - FrameFormat frameType() const; - void frameType(FrameFormat value); - Repetition repetition() const; - void repetition(Repetition value); - SystemBroadcast systemBroadcast() const; - void systemBroadcast(SystemBroadcast value); - Priority priority() const; - void priority(Priority value); - AckType ack() const; - void ack(AckType value); - Confirm confirm() const; - void confirm(Confirm value); - AddressType addressType() const; - void addressType(AddressType value); - uint8_t hopCount() const; - void hopCount(uint8_t value); - uint16_t sourceAddress() const; - void sourceAddress(uint16_t value); - uint16_t destinationAddress() const; - void destinationAddress(uint16_t value); + FrameFormat frameType() const; + void frameType(FrameFormat value); + Repetition repetition() const; + void repetition(Repetition value); + SystemBroadcast systemBroadcast() const; + void systemBroadcast(SystemBroadcast value); + Priority priority() const; + void priority(Priority value); + AckType ack() const; + void ack(AckType value); + Confirm confirm() const; + void confirm(Confirm value); + AddressType addressType() const; + void addressType(AddressType value); + uint8_t hopCount() const; + void hopCount(uint8_t value); + uint16_t sourceAddress() const; + void sourceAddress(uint16_t value); + uint16_t destinationAddress() const; + void destinationAddress(uint16_t value); - // only for RF medium - uint8_t* rfSerialOrDoA() const; - void rfSerialOrDoA(const uint8_t* rfSerialOrDoA); - uint8_t rfInfo() const; - void rfInfo(uint8_t rfInfo); - uint8_t rfLfn() const; - void rfLfn(uint8_t rfInfo); + // only for RF medium + uint8_t* rfSerialOrDoA() const; + void rfSerialOrDoA(const uint8_t* rfSerialOrDoA); + uint8_t rfInfo() const; + void rfInfo(uint8_t rfInfo); + uint8_t rfLfn() const; + void rfLfn(uint8_t rfInfo); - NPDU& npdu(); - TPDU& tpdu(); - APDU& apdu(); + NPDU& npdu(); + TPDU& tpdu(); + APDU& apdu(); - uint8_t calcCrcTP(uint8_t* buffer, uint16_t len); - bool valid() const; + uint8_t calcCrcTP(uint8_t* buffer, uint16_t len); + bool valid() const; - void printIt() const; + void printIt() const; - private: - uint8_t buffer[0xff + NPDU_LPDU_DIFF] = {0}; //only valid of add info is zero - uint8_t* _data = 0; - uint8_t* _ctrl1 = 0; - NPDU _npdu; - TPDU _tpdu; - APDU _apdu; - uint16_t _length = 0; // only set if created from byte array + private: + uint8_t buffer[0xff + NPDU_LPDU_DIFF] = {0}; //only valid of add info is zero + uint8_t* _data = 0; + uint8_t* _ctrl1 = 0; + NPDU _npdu; + TPDU _tpdu; + APDU _apdu; + uint16_t _length = 0; // only set if created from byte array #ifndef KNX_NO_RF - // FIXME: integrate this propery in _data - // only for RF medium - uint8_t* _rfSerialOrDoA = 0; - uint8_t _rfInfo = 0; - uint8_t _rfLfn = 0xFF; // RF Data Link layer frame number + // FIXME: integrate this propery in _data + // only for RF medium + uint8_t* _rfSerialOrDoA = 0; + uint8_t _rfInfo = 0; + uint8_t _rfLfn = 0xFF; // RF Data Link layer frame number #endif - uint8_t _sourceInterfaceIndex; -}; + uint8_t _sourceInterfaceIndex; + }; +} \ No newline at end of file diff --git a/src/knx/datalink_layer/data_link_layer.cpp b/src/knx/datalink_layer/data_link_layer.cpp index f5872b19..bdf9d1b3 100644 --- a/src/knx/datalink_layer/data_link_layer.cpp +++ b/src/knx/datalink_layer/data_link_layer.cpp @@ -8,305 +8,308 @@ #define LOGGER Logger::logger("DataLinkLayer") - -void DataLinkLayerCallbacks::activity(uint8_t info) +namespace Knx { - if (_activityCallback) - _activityCallback(info); -} -void DataLinkLayerCallbacks::setActivityCallback(ActivityCallback activityCallback) -{ - _activityCallback = activityCallback; -} + void DataLinkLayerCallbacks::activity(uint8_t info) + { + if (_activityCallback) + _activityCallback(info); + } -DataLinkLayer::DataLinkLayer(DeviceObject& devObj, NetworkLayerEntity& netLayerEntity, Platform& platform) : - _deviceObject(devObj), _networkLayerEntity(netLayerEntity), _platform(platform) -{ + void DataLinkLayerCallbacks::setActivityCallback(ActivityCallback activityCallback) + { + _activityCallback = activityCallback; + } + + DataLinkLayer::DataLinkLayer(DeviceObject& devObj, NetworkLayerEntity& netLayerEntity, Platform& platform) : + _deviceObject(devObj), _networkLayerEntity(netLayerEntity), _platform(platform) + { #ifdef KNX_ACTIVITYCALLBACK - _netIndex = netLayerEntity.getEntityIndex(); + _netIndex = netLayerEntity.getEntityIndex(); #endif -} + } #ifdef USE_CEMI_SERVER -void DataLinkLayer::cemiServer(CemiServer& cemiServer) -{ - _cemiServer = &cemiServer; -} + void DataLinkLayer::cemiServer(CemiServer& cemiServer) + { + _cemiServer = &cemiServer; + } #ifdef KNX_TUNNELING -void DataLinkLayer::dataRequestToTunnel(CemiFrame& frame) -{ - LOGGER.info("default dataRequestToTunnel"); -} + void DataLinkLayer::dataRequestToTunnel(CemiFrame& frame) + { + LOGGER.info("default dataRequestToTunnel"); + } -void DataLinkLayer::dataConfirmationToTunnel(CemiFrame& frame) -{ - LOGGER.info("default dataConfirmationToTunnel"); -} + void DataLinkLayer::dataConfirmationToTunnel(CemiFrame& frame) + { + LOGGER.info("default dataConfirmationToTunnel"); + } -void DataLinkLayer::dataIndicationToTunnel(CemiFrame& frame) -{ - LOGGER.info("default dataIndicationToTunnel"); -} + void DataLinkLayer::dataIndicationToTunnel(CemiFrame& frame) + { + LOGGER.info("default dataIndicationToTunnel"); + } -bool DataLinkLayer::isTunnelAddress(uint16_t addr) -{ - LOGGER.info("default IsTunnelAddress"); - return false; -} + bool DataLinkLayer::isTunnelAddress(uint16_t addr) + { + LOGGER.info("default IsTunnelAddress"); + return false; + } #endif -void DataLinkLayer::dataRequestFromTunnel(CemiFrame& frame) -{ - _cemiServer->dataConfirmationToTunnel(frame); + void DataLinkLayer::dataRequestFromTunnel(CemiFrame& frame) + { + _cemiServer->dataConfirmationToTunnel(frame); - frame.messageCode(L_data_ind); + frame.messageCode(L_data_ind); - // Send to local stack ( => cemiServer for potential other tunnel and network layer for routing) - frameReceived(frame); + // Send to local stack ( => cemiServer for potential other tunnel and network layer for routing) + frameReceived(frame); #ifdef KNX_TUNNELING - // TunnelOpti - // Optimize performance when receiving unicast data over tunnel wich is not meant to be used on the physical TP line - // dont send to knx when - // frame is individual adressed AND - // destionation == PA of Tunnel-Server OR - // destination == PA of a Tunnel OR (TODO) - // destination is not the TP/secondary line/segment but IP/primary (TODO) - - if (frame.addressType() == AddressType::IndividualAddress) - { - if (frame.destinationAddress() == _deviceObject.individualAddress()) - return; - - if (isRoutedPA(frame.destinationAddress())) - return; - - if (isTunnelingPA(frame.destinationAddress())) - return; - } + // TunnelOpti + // Optimize performance when receiving unicast data over tunnel wich is not meant to be used on the physical TP line + // dont send to knx when + // frame is individual adressed AND + // destionation == PA of Tunnel-Server OR + // destination == PA of a Tunnel OR (TODO) + // destination is not the TP/secondary line/segment but IP/primary (TODO) + + if (frame.addressType() == AddressType::IndividualAddress) + { + if (frame.destinationAddress() == _deviceObject.individualAddress()) + return; + + if (isRoutedPA(frame.destinationAddress())) + return; + + if (isTunnelingPA(frame.destinationAddress())) + return; + } #endif - // Send to KNX medium - sendFrame(frame); -} + // Send to KNX medium + sendFrame(frame); + } #endif -void DataLinkLayer::dataRequest(AckType ack, AddressType addrType, uint16_t destinationAddr, uint16_t sourceAddr, FrameFormat format, Priority priority, NPDU& npdu) -{ - // Normal data requests and broadcasts will always be transmitted as (domain) broadcast with domain address for open media (e.g. RF medium) - // The domain address "simulates" a closed medium (such as TP) on an open medium (such as RF or PL) - // See 3.2.5 p.22 - sendTelegram(npdu, ack, destinationAddr, addrType, sourceAddr, format, priority, Broadcast); -} + void DataLinkLayer::dataRequest(AckType ack, AddressType addrType, uint16_t destinationAddr, uint16_t sourceAddr, FrameFormat format, Priority priority, NPDU& npdu) + { + // Normal data requests and broadcasts will always be transmitted as (domain) broadcast with domain address for open media (e.g. RF medium) + // The domain address "simulates" a closed medium (such as TP) on an open medium (such as RF or PL) + // See 3.2.5 p.22 + sendTelegram(npdu, ack, destinationAddr, addrType, sourceAddr, format, priority, Broadcast); + } -void DataLinkLayer::systemBroadcastRequest(AckType ack, FrameFormat format, Priority priority, NPDU& npdu, uint16_t sourceAddr) -{ - // System Broadcast requests will always be transmitted as broadcast with KNX serial number for open media (e.g. RF medium) - // See 3.2.5 p.22 - sendTelegram(npdu, ack, 0, GroupAddress, sourceAddr, format, priority, SysBroadcast); -} + void DataLinkLayer::systemBroadcastRequest(AckType ack, FrameFormat format, Priority priority, NPDU& npdu, uint16_t sourceAddr) + { + // System Broadcast requests will always be transmitted as broadcast with KNX serial number for open media (e.g. RF medium) + // See 3.2.5 p.22 + sendTelegram(npdu, ack, 0, GroupAddress, sourceAddr, format, priority, SysBroadcast); + } -void DataLinkLayer::dataConReceived(CemiFrame& frame, bool success) -{ - MessageCode backupMsgCode = frame.messageCode(); - frame.messageCode(L_data_con); - frame.confirm(success ? ConfirmNoError : ConfirmError); - 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(); - SystemBroadcast systemBroadcast = frame.systemBroadcast(); + void DataLinkLayer::dataConReceived(CemiFrame& frame, bool success) + { + MessageCode backupMsgCode = frame.messageCode(); + frame.messageCode(L_data_con); + frame.confirm(success ? ConfirmNoError : ConfirmError); + 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(); + SystemBroadcast systemBroadcast = frame.systemBroadcast(); #ifdef USE_CEMI_SERVER - // if the confirmation was caused by a tunnel request then - // do not send it to the local stack - if (frame.sourceAddress() == _cemiServer->clientAddress()) - { - // Stop processing here and do NOT send it the local network layer - return; - } + // if the confirmation was caused by a tunnel request then + // do not send it to the local stack + if (frame.sourceAddress() == _cemiServer->clientAddress()) + { + // Stop processing here and do NOT send it the local network layer + return; + } #endif - if (addrType == GroupAddress && destination == 0) - if (systemBroadcast == SysBroadcast) - _networkLayerEntity.systemBroadcastConfirm(ack, type, priority, source, npdu, success); + if (addrType == GroupAddress && destination == 0) + if (systemBroadcast == SysBroadcast) + _networkLayerEntity.systemBroadcastConfirm(ack, type, priority, source, npdu, success); + else + _networkLayerEntity.broadcastConfirm(ack, type, priority, source, npdu, success); else - _networkLayerEntity.broadcastConfirm(ack, type, priority, source, npdu, success); - else - _networkLayerEntity.dataConfirm(ack, addrType, destination, type, priority, source, npdu, success); + _networkLayerEntity.dataConfirm(ack, addrType, destination, type, priority, source, npdu, success); - frame.messageCode(backupMsgCode); -} + frame.messageCode(backupMsgCode); + } -void DataLinkLayer::frameReceived(CemiFrame& frame) -{ - 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(); - uint16_t ownAddr = _deviceObject.individualAddress(); - SystemBroadcast systemBroadcast = frame.systemBroadcast(); + void DataLinkLayer::frameReceived(CemiFrame& frame) + { + 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(); + uint16_t ownAddr = _deviceObject.individualAddress(); + SystemBroadcast systemBroadcast = frame.systemBroadcast(); - LOGGER.info("frameReceived ", frame); + LOGGER.info("frameReceived ", frame); #ifdef USE_CEMI_SERVER - // Do not send our own message back to the tunnel + // Do not send our own message back to the tunnel #ifdef KNX_TUNNELING - //we dont need to check it here - // send inbound frames to the tunnel if we are the secondary (TP) interface - if ( _networkLayerEntity.getEntityIndex() == 1) - _cemiServer->dataIndicationToTunnel(frame); + //we dont need to check it here + // send inbound frames to the tunnel if we are the secondary (TP) interface + if ( _networkLayerEntity.getEntityIndex() == 1) + _cemiServer->dataIndicationToTunnel(frame); #else - if (frame.sourceAddress() != _cemiServer->clientAddress()) - { - _cemiServer->dataIndicationToTunnel(frame); - } + if (frame.sourceAddress() != _cemiServer->clientAddress()) + { + _cemiServer->dataIndicationToTunnel(frame); + } #endif #endif - // print("Frame received destination: "); - // print(destination, 16); - // println(); - // print("frameReceived: frame valid? :"); - // println(npdu.frame().valid() ? "true" : "false"); - if (source == ownAddr) - _deviceObject.individualAddressDuplication(true); - - if (addrType == GroupAddress && destination == 0) - { - if (systemBroadcast == SysBroadcast) - _networkLayerEntity.systemBroadcastIndication(ack, type, npdu, priority, source); + // print("Frame received destination: "); + // print(destination, 16); + // println(); + // print("frameReceived: frame valid? :"); + // println(npdu.frame().valid() ? "true" : "false"); + if (source == ownAddr) + _deviceObject.individualAddressDuplication(true); + + if (addrType == GroupAddress && destination == 0) + { + if (systemBroadcast == SysBroadcast) + _networkLayerEntity.systemBroadcastIndication(ack, type, npdu, priority, source); + else + _networkLayerEntity.broadcastIndication(ack, type, npdu, priority, source); + } else - _networkLayerEntity.broadcastIndication(ack, type, npdu, priority, source); - } - else - { - _networkLayerEntity.dataIndication(ack, addrType, destination, type, npdu, priority, source); + { + _networkLayerEntity.dataIndication(ack, addrType, destination, type, npdu, priority, source); + } } -} -bool DataLinkLayer::sendTelegram(NPDU& npdu, AckType ack, uint16_t destinationAddr, AddressType addrType, uint16_t sourceAddr, FrameFormat format, Priority priority, SystemBroadcast systemBroadcast, bool doNotRepeat) -{ - CemiFrame& frame = npdu.frame(); - // print("Send telegram frame valid ?: "); - // println(frame.valid()?"true":"false"); - frame.messageCode(L_data_ind); - frame.destinationAddress(destinationAddr); - frame.sourceAddress(sourceAddr); - frame.addressType(addrType); - frame.priority(priority); - frame.repetition(doNotRepeat ? NoRepetiion : RepetitionAllowed); - frame.systemBroadcast(systemBroadcast); - - if (npdu.octetCount() <= 15) - frame.frameType(StandardFrame); - else - frame.frameType(format); - - LOGGER.info("sendTelegram ", frame); - - if (!frame.valid()) + bool DataLinkLayer::sendTelegram(NPDU& npdu, AckType ack, uint16_t destinationAddr, AddressType addrType, uint16_t sourceAddr, FrameFormat format, Priority priority, SystemBroadcast systemBroadcast, bool doNotRepeat) { - LOGGER.warning("invalid frame"); - return false; - } + CemiFrame& frame = npdu.frame(); + // print("Send telegram frame valid ?: "); + // println(frame.valid()?"true":"false"); + frame.messageCode(L_data_ind); + frame.destinationAddress(destinationAddr); + frame.sourceAddress(sourceAddr); + frame.addressType(addrType); + frame.priority(priority); + frame.repetition(doNotRepeat ? NoRepetiion : RepetitionAllowed); + frame.systemBroadcast(systemBroadcast); + + if (npdu.octetCount() <= 15) + frame.frameType(StandardFrame); + else + frame.frameType(format); - bool sendTheFrame = true; - bool success = true; + LOGGER.info("sendTelegram ", frame); + if (!frame.valid()) + { + LOGGER.warning("invalid frame"); + return false; + } -#ifdef KNX_TUNNELING - // TunnelOpti - // Optimize performance when sending unicast data over tunnel wich is not meant to be used on the physical TP line - // dont send to knx when - // a) we are the secondary interface (e.g. TP) AND - // b) destination == PA of a Tunnel (TODO) + bool sendTheFrame = true; + bool success = true; - if (_networkLayerEntity.getEntityIndex() == 1 && addrType == AddressType::IndividualAddress) // don't send to tp if we are the secondary (TP) interface AND the destination is a tunnel-PA - { - if (isTunnelingPA(destinationAddr)) - sendTheFrame = false; - } + +#ifdef KNX_TUNNELING + // TunnelOpti + // Optimize performance when sending unicast data over tunnel wich is not meant to be used on the physical TP line + // dont send to knx when + // a) we are the secondary interface (e.g. TP) AND + // b) destination == PA of a Tunnel (TODO) + + if (_networkLayerEntity.getEntityIndex() == 1 && addrType == AddressType::IndividualAddress) // don't send to tp if we are the secondary (TP) interface AND the destination is a tunnel-PA + { + if (isTunnelingPA(destinationAddr)) + sendTheFrame = false; + } #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 - // Thus, reuse the modified cEMI frame as "frame" is only passed by reference here! - if (sendTheFrame) - success = sendFrame(frame); + // 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 + // Thus, reuse the modified cEMI frame as "frame" is only passed by reference here! + if (sendTheFrame) + success = sendFrame(frame); #ifdef USE_CEMI_SERVER - CemiFrame tmpFrame(frame.data(), frame.totalLenght()); - // We can just copy the pointer for rfSerialOrDoA as sendFrame() sets - // a pointer to const uint8_t data in either device object (serial) or - // RF medium object (domain address) + CemiFrame tmpFrame(frame.data(), frame.totalLenght()); + // We can just copy the pointer for rfSerialOrDoA as sendFrame() sets + // a pointer to const uint8_t data in either device object (serial) or + // RF medium object (domain address) #ifndef KNX_NO_RF - tmpFrame.rfSerialOrDoA(frame.rfSerialOrDoA()); - tmpFrame.rfInfo(frame.rfInfo()); - tmpFrame.rfLfn(frame.rfLfn()); + tmpFrame.rfSerialOrDoA(frame.rfSerialOrDoA()); + tmpFrame.rfInfo(frame.rfInfo()); + tmpFrame.rfLfn(frame.rfLfn()); #endif - tmpFrame.confirm(ConfirmNoError); + tmpFrame.confirm(ConfirmNoError); - if (_networkLayerEntity.getEntityIndex() == 1) // only send to tunnel if we are the secondary (TP) interface - _cemiServer->dataIndicationToTunnel(tmpFrame); + if (_networkLayerEntity.getEntityIndex() == 1) // only send to tunnel if we are the secondary (TP) interface + _cemiServer->dataIndicationToTunnel(tmpFrame); #endif - return success; -} + return success; + } -uint8_t* DataLinkLayer::frameData(CemiFrame& frame) -{ - return frame._data; -} + uint8_t* DataLinkLayer::frameData(CemiFrame& frame) + { + return frame._data; + } #ifdef KNX_TUNNELING -bool DataLinkLayer::isTunnelingPA(uint16_t pa) -{ - uint8_t numAddresses = 0; - uint16_t* addresses = _ipParameters->additionalIndivualAddresses(numAddresses); - - for (uint8_t i = 0; i < numAddresses; i++) + bool DataLinkLayer::isTunnelingPA(uint16_t pa) { - if (pa == addresses[i]) - return true; - } + uint8_t numAddresses = 0; + uint16_t* addresses = _ipParameters->additionalIndivualAddresses(numAddresses); - return false; -} + for (uint8_t i = 0; i < numAddresses; i++) + { + if (pa == addresses[i]) + return true; + } -bool DataLinkLayer::isRoutedPA(uint16_t pa) -{ - uint16_t ownpa = _deviceObject.individualAddress(); - uint16_t own_sm; + return false; + } - if ((ownpa & 0x0F00) == 0x0) - own_sm = 0xF000; - else - own_sm = 0xFF00; + bool DataLinkLayer::isRoutedPA(uint16_t pa) + { + uint16_t ownpa = _deviceObject.individualAddress(); + uint16_t own_sm; + + if ((ownpa & 0x0F00) == 0x0) + own_sm = 0xF000; + else + own_sm = 0xFF00; - return (pa & own_sm) != ownpa; -} + return (pa & own_sm) != ownpa; + } #endif +} \ No newline at end of file diff --git a/src/knx/datalink_layer/data_link_layer.h b/src/knx/datalink_layer/data_link_layer.h index f38167b7..9ea934e9 100644 --- a/src/knx/datalink_layer/data_link_layer.h +++ b/src/knx/datalink_layer/data_link_layer.h @@ -15,66 +15,69 @@ #include -class Platform; +namespace Knx +{ + class Platform; -typedef void (*ActivityCallback)(uint8_t info); + typedef void (*ActivityCallback)(uint8_t info); -class DataLinkLayerCallbacks -{ - protected: - ActivityCallback _activityCallback = nullptr; - public: - virtual ~DataLinkLayerCallbacks() = default; - virtual void activity(uint8_t info); - virtual void setActivityCallback(ActivityCallback activityCallback); -}; + class DataLinkLayerCallbacks + { + protected: + ActivityCallback _activityCallback = nullptr; + public: + virtual ~DataLinkLayerCallbacks() = default; + virtual void activity(uint8_t info); + virtual void setActivityCallback(ActivityCallback activityCallback); + }; -class DataLinkLayer -{ - public: - DataLinkLayer(DeviceObject& devObj, NetworkLayerEntity& netLayerEntity, - Platform& platform); + class DataLinkLayer + { + public: + DataLinkLayer(DeviceObject& devObj, NetworkLayerEntity& netLayerEntity, + Platform& platform); #ifdef USE_CEMI_SERVER - void cemiServer(CemiServer& cemiServer); + void cemiServer(CemiServer& cemiServer); - // from tunnel - void dataRequestFromTunnel(CemiFrame& frame); + // from tunnel + void dataRequestFromTunnel(CemiFrame& frame); #endif #ifdef KNX_TUNNELING - virtual void dataRequestToTunnel(CemiFrame& frame); - virtual void dataConfirmationToTunnel(CemiFrame& frame); - virtual void dataIndicationToTunnel(CemiFrame& frame); - virtual bool isTunnelAddress(uint16_t addr); - void ipParameterObject(IpParameterObject* object); + virtual void dataRequestToTunnel(CemiFrame& frame); + virtual void dataConfirmationToTunnel(CemiFrame& frame); + virtual void dataIndicationToTunnel(CemiFrame& frame); + virtual bool isTunnelAddress(uint16_t addr); + void ipParameterObject(IpParameterObject* object); #endif - // from network layer - void dataRequest(AckType ack, AddressType addrType, uint16_t destinationAddr, uint16_t sourceAddr, FrameFormat format, - Priority priority, NPDU& npdu); - void systemBroadcastRequest(AckType ack, FrameFormat format, Priority priority, NPDU& npdu, uint16_t sourceAddr); - virtual void loop() = 0; - virtual void enabled(bool value) = 0; - virtual bool enabled() const = 0; - virtual DptMedium mediumType() const = 0; + // from network layer + void dataRequest(AckType ack, AddressType addrType, uint16_t destinationAddr, uint16_t sourceAddr, FrameFormat format, + Priority priority, NPDU& npdu); + void systemBroadcastRequest(AckType ack, FrameFormat format, Priority priority, NPDU& npdu, uint16_t sourceAddr); + virtual void loop() = 0; + virtual void enabled(bool value) = 0; + virtual bool enabled() const = 0; + virtual DptMedium mediumType() const = 0; - protected: - void frameReceived(CemiFrame& frame); - void dataConReceived(CemiFrame& frame, bool success); - bool sendTelegram(NPDU& npdu, AckType ack, uint16_t destinationAddr, AddressType addrType, uint16_t sourceAddr, FrameFormat format, Priority priority, SystemBroadcast systemBroadcast, bool doNotRepeat = false); - virtual bool sendFrame(CemiFrame& frame) = 0; - uint8_t* frameData(CemiFrame& frame); - DeviceObject& _deviceObject; - NetworkLayerEntity& _networkLayerEntity; - Platform& _platform; + protected: + void frameReceived(CemiFrame& frame); + void dataConReceived(CemiFrame& frame, bool success); + bool sendTelegram(NPDU& npdu, AckType ack, uint16_t destinationAddr, AddressType addrType, uint16_t sourceAddr, FrameFormat format, Priority priority, SystemBroadcast systemBroadcast, bool doNotRepeat = false); + virtual bool sendFrame(CemiFrame& frame) = 0; + uint8_t* frameData(CemiFrame& frame); + DeviceObject& _deviceObject; + NetworkLayerEntity& _networkLayerEntity; + Platform& _platform; #ifdef USE_CEMI_SERVER - CemiServer* _cemiServer; + CemiServer* _cemiServer; #endif #ifdef KNX_ACTIVITYCALLBACK - uint8_t _netIndex = 0; + uint8_t _netIndex = 0; #endif #ifdef KNX_TUNNELING - bool isTunnelingPA(uint16_t pa); - bool isRoutedPA(uint16_t pa); - IpParameterObject* _ipParameters; + bool isTunnelingPA(uint16_t pa); + bool isRoutedPA(uint16_t pa); + IpParameterObject* _ipParameters; #endif -}; + }; +} \ No newline at end of file diff --git a/src/knx/group_object/datapoint_types.cpp b/src/knx/group_object/datapoint_types.cpp index 664d4df8..d10cc07f 100644 --- a/src/knx/group_object/datapoint_types.cpp +++ b/src/knx/group_object/datapoint_types.cpp @@ -12,54 +12,57 @@ #include -// Sign for a negative DPT9 float value +namespace Knx +{ + // Sign for a negative DPT9 float value #define DPT_FLOAT_NEG_SIGN 0x8000 -uint16_t dptToFloat(int32_t value) -{ - uint16_t exp = 0; + uint16_t dptToFloat(int32_t value) + { + uint16_t exp = 0; - if (value < -67108864 || value > 67076096) - return 0x7fff; + if (value < -67108864 || value > 67076096) + return 0x7fff; - if (value < 0) - { - while (value < -2048) + if (value < 0) { - value >>= 1; - ++exp; - } + while (value < -2048) + { + value >>= 1; + ++exp; + } - return DPT_FLOAT_NEG_SIGN | (((int32_t) value) & 2047) | (exp << 11); - } - else - { - while (value > 2047) - { - value >>= 1; - ++exp; + return DPT_FLOAT_NEG_SIGN | (((int32_t) value) & 2047) | (exp << 11); } + else + { + while (value > 2047) + { + value >>= 1; + ++exp; + } - return value | (exp << 11); + return value | (exp << 11); + } } -} -int32_t dptFromFloat(uint16_t dptValue) -{ - uint16_t exp = (dptValue >> 11) & 15; - int32_t value; + int32_t dptFromFloat(uint16_t dptValue) + { + uint16_t exp = (dptValue >> 11) & 15; + int32_t value; - if (dptValue == 0x7fff) - return INVALID_DPT_FLOAT; + if (dptValue == 0x7fff) + return INVALID_DPT_FLOAT; - if (dptValue >= 0x8000) - value = dptValue | (-1L & ~2047); - else - value = dptValue & 2047; + if (dptValue >= 0x8000) + value = dptValue | (-1L & ~2047); + else + value = dptValue & 2047; - for (; exp; --exp) - value <<= 1; + for (; exp; --exp) + value <<= 1; - return value; -} + return value; + } +} \ No newline at end of file diff --git a/src/knx/group_object/datapoint_types.h b/src/knx/group_object/datapoint_types.h index 1d4ff090..8fad921a 100644 --- a/src/knx/group_object/datapoint_types.h +++ b/src/knx/group_object/datapoint_types.h @@ -11,27 +11,31 @@ #pragma once #include -/** - * An invalid 2 uint8_t float (DPT9/EIS5). - * To be used for dptToFloat() and dptFromFloat(). - */ + +namespace Knx +{ + /** + * An invalid 2 uint8_t float (DPT9/EIS5). + * To be used for dptToFloat() and dptFromFloat(). + */ #define INVALID_DPT_FLOAT 2147483647U -/** - * Convert a value from uint32_t to 2 uint8_t float (DPT9/EIS5). The possible range - * of the values is -67108864 to 67076096. - * - * @param value - the value to convert. - * Use INVALID_DPT_FLOAT for the DPT9 "invalid data" value. - * @return The 2 uint8_t float (DPT9/EIS5). - */ -uint16_t dptToFloat(int32_t value); + /** + * Convert a value from uint32_t to 2 uint8_t float (DPT9/EIS5). The possible range + * of the values is -67108864 to 67076096. + * + * @param value - the value to convert. + * Use INVALID_DPT_FLOAT for the DPT9 "invalid data" value. + * @return The 2 uint8_t float (DPT9/EIS5). + */ + uint16_t dptToFloat(int32_t value); -/** - * Convert a value from 2 uint8_t float (DPT9/EIS5) to integer. - * - * @param dptValue - the 2 uint8_t float (DPT9/EIS5) to convert - * @return The value as integer, or INVALID_DPT_FLOAT for the - * DPT9 "invalid data" value. - */ -int32_t dptFromFloat(uint16_t dptValue); \ No newline at end of file + /** + * Convert a value from 2 uint8_t float (DPT9/EIS5) to integer. + * + * @param dptValue - the 2 uint8_t float (DPT9/EIS5) to convert + * @return The value as integer, or INVALID_DPT_FLOAT for the + * DPT9 "invalid data" value. + */ + int32_t dptFromFloat(uint16_t dptValue); +} \ No newline at end of file diff --git a/src/knx/group_object/dpt.cpp b/src/knx/group_object/dpt.cpp index af2491cc..b5b3093b 100644 --- a/src/knx/group_object/dpt.cpp +++ b/src/knx/group_object/dpt.cpp @@ -5,22 +5,25 @@ #define LOGGER Logger::logger("Dpt") -Dpt::Dpt() -{} - -Dpt::Dpt(short mainGroup, short subGroup, short index /* = 0 */) - : mainGroup(mainGroup), subGroup(subGroup), index(index) +namespace Knx { - if (subGroup == 0) - println("WARNING: You used and invalid Dpt *.0"); -} + Dpt::Dpt() + {} -bool Dpt::operator==(const Dpt& other) const -{ - return other.mainGroup == mainGroup && other.subGroup == subGroup && other.index == index; -} + Dpt::Dpt(short mainGroup, short subGroup, short index /* = 0 */) + : mainGroup(mainGroup), subGroup(subGroup), index(index) + { + if (subGroup == 0) + println("WARNING: You used and invalid Dpt *.0"); + } -bool Dpt::operator!=(const Dpt& other) const -{ - return !(other == *this); -} + bool Dpt::operator==(const Dpt& other) const + { + return other.mainGroup == mainGroup && other.subGroup == subGroup && other.index == index; + } + + bool Dpt::operator!=(const Dpt& other) const + { + return !(other == *this); + } +} \ No newline at end of file diff --git a/src/knx/group_object/dpt.h b/src/knx/group_object/dpt.h index 6c2f0be6..23308133 100644 --- a/src/knx/group_object/dpt.h +++ b/src/knx/group_object/dpt.h @@ -1,5 +1,7 @@ #pragma once +namespace Knx +{ #define DPT_Switch Dpt(1, 1) #define DPT_Bool Dpt(1, 2) #define DPT_Enable Dpt(1, 3) @@ -360,14 +362,15 @@ #define DPT_StatusSAB Dpt(241, 800) #define DPT_Colour_RGBW Dpt(251, 600) -class Dpt -{ - public: - Dpt(); - Dpt(short mainGroup, short subGroup, short index = 0); - unsigned short mainGroup; - unsigned short subGroup; - unsigned short index; - bool operator==(const Dpt& other) const; - bool operator!=(const Dpt& other) const; -}; + class Dpt + { + public: + Dpt(); + Dpt(short mainGroup, short subGroup, short index = 0); + unsigned short mainGroup; + unsigned short subGroup; + unsigned short index; + bool operator==(const Dpt& other) const; + bool operator!=(const Dpt& other) const; + }; +} \ No newline at end of file diff --git a/src/knx/group_object/dptconvert.cpp b/src/knx/group_object/dptconvert.cpp index 673ba7f6..7fb85cad 100644 --- a/src/knx/group_object/dptconvert.cpp +++ b/src/knx/group_object/dptconvert.cpp @@ -12,2044 +12,2047 @@ #define ENSURE_PAYLOAD(x) -int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) +namespace Knx { - if (payload_length > 0) + int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - // DPT 1.* - Binary - if (datatype.mainGroup == 1 && datatype.subGroup >= 1 && datatype.subGroup <= 23 && datatype.subGroup != 20 && !datatype.index) + if (payload_length > 0) { - return busValueToBinary(payload, payload_length, datatype, value); - } // DPT 2.* - Binary Control + // DPT 1.* - Binary + if (datatype.mainGroup == 1 && datatype.subGroup >= 1 && datatype.subGroup <= 23 && datatype.subGroup != 20 && !datatype.index) + { + return busValueToBinary(payload, payload_length, datatype, value); + } // DPT 2.* - Binary Control + + if (datatype.mainGroup == 2 && datatype.subGroup >= 1 && datatype.subGroup <= 12 && datatype.index <= 1) + return busValueToBinaryControl(payload, payload_length, datatype, value); + + // DPT 3.* - Step Control + if (datatype.mainGroup == 3 && datatype.subGroup >= 7 && datatype.subGroup <= 8 && datatype.index <= 1) + return busValueToStepControl(payload, payload_length, datatype, value); + + // DPT 4.* - Character + if (datatype.mainGroup == 4 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && !datatype.index) + return busValueToCharacter(payload, payload_length, datatype, value); + + // DPT 5.* - Unsigned 8 Bit Integer + if (datatype.mainGroup == 5 && ((datatype.subGroup >= 1 && datatype.subGroup <= 6 && datatype.subGroup != 2) || datatype.subGroup == 10) && !datatype.index) + return busValueToUnsigned8(payload, payload_length, datatype, value); + + // DPT 6.001/6.010 - Signed 8 Bit Integer + if (datatype.mainGroup == 6 && (datatype.subGroup == 1 || datatype.subGroup == 10) && !datatype.index) + return busValueToSigned8(payload, payload_length, datatype, value); + + // DPT 6.020 - Status with Mode + if (datatype.mainGroup == 6 && datatype.subGroup == 20 && datatype.index <= 5) + return busValueToStatusAndMode(payload, payload_length, datatype, value); + + // DPT 7.001/7.010/7.011/7.012/7.013/7.600 - Unsigned 16 Bit Integer + if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13) || (datatype.subGroup == 600)) && !datatype.index) + return busValueToUnsigned16(payload, payload_length, datatype, value); + + // DPT 7.002-DPT 7.007 - Time Period + if (datatype.mainGroup == 7 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index) + return busValueToTimePeriod(payload, payload_length, datatype, value); + + // DPT 8.001/8.010/8.011 - Signed 16 Bit Integer + if (datatype.mainGroup == 8 && (datatype.subGroup == 1 || datatype.subGroup == 10 || datatype.subGroup == 11) && !datatype.index) + return busValueToSigned16(payload, payload_length, datatype, value); + + // DPT 8.002-DPT 8.007 - Time Delta + if (datatype.mainGroup == 8 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index) + return busValueToTimeDelta(payload, payload_length, datatype, value); + + // DPT 9.* - 16 Bit Float + if (datatype.mainGroup == 9 && ((datatype.subGroup >= 1 && datatype.subGroup <= 11) || (datatype.subGroup >= 20 && datatype.subGroup <= 29)) && !datatype.index) + return busValueToFloat16(payload, payload_length, datatype, value); + + // DPT 10.* - Time and Weekday + if (datatype.mainGroup == 10 && datatype.subGroup == 1 && datatype.index <= 1) + return busValueToTime(payload, payload_length, datatype, value); + + // DPT 11.* - Date + if (datatype.mainGroup == 11 && datatype.subGroup == 1 && !datatype.index) + return busValueToDate(payload, payload_length, datatype, value); + + // DPT 12.* - Unsigned 32 Bit Integer + if (datatype.mainGroup == 12 && datatype.subGroup == 1 && !datatype.index) + return busValueToUnsigned32(payload, payload_length, datatype, value); + + // DPT 13.001/13.002/13.010-13.015 - Signed 32 Bit Integer + if (datatype.mainGroup == 13 && (datatype.subGroup == 1 || datatype.subGroup == 2 || (datatype.subGroup >= 10 && datatype.subGroup <= 15)) && !datatype.index) + return busValueToSigned32(payload, payload_length, datatype, value); + + // DPT 13.100 - Long Time Period + if (datatype.mainGroup == 13 && datatype.subGroup == 100 && !datatype.index) + return busValueToLongTimePeriod(payload, payload_length, datatype, value); + + // DPT 14.* - 32 Bit Float + if (datatype.mainGroup == 14 && datatype.subGroup <= 79 && !datatype.index) + return busValueToFloat32(payload, payload_length, datatype, value); + + // DPT 15.* - Access Data + if (datatype.mainGroup == 15 && !datatype.subGroup && datatype.index <= 5) + return busValueToAccess(payload, payload_length, datatype, value); + + // DPT 16.* - String + if (datatype.mainGroup == 16 && datatype.subGroup <= 1 && !datatype.index) + return busValueToString(payload, payload_length, datatype, value); + + // DPT 17.* - Scene Number + if (datatype.mainGroup == 17 && datatype.subGroup == 1 && !datatype.index) + return busValueToScene(payload, payload_length, datatype, value); + + // DPT 18.* - Scene Control + if (datatype.mainGroup == 18 && datatype.subGroup == 1 && datatype.index <= 1) + return busValueToSceneControl(payload, payload_length, datatype, value); + + // DPT 19.* - Date and Time + if (datatype.mainGroup == 19 && datatype.subGroup == 1 && (datatype.index <= 3 || datatype.index == 9 || datatype.index == 10)) + return busValueToDateTime(payload, payload_length, datatype, value); + + // DPT 26.* - Scene Info + if (datatype.mainGroup == 26 && datatype.subGroup == 1 && datatype.index <= 1) + return busValueToSceneInfo(payload, payload_length, datatype, value); + + // DPT 27.001 - 32 Bit field + if (datatype.mainGroup == 27 && datatype.subGroup == 1 && !datatype.index) + return busValueToSigned32(payload, payload_length, datatype, value); + + // DPT 28.* - Unicode String + if (datatype.mainGroup == 28 && datatype.subGroup == 1 && !datatype.index) + return busValueToUnicode(payload, payload_length, datatype, value); + + // DPT 29.* - Signed 64 Bit Integer + if (datatype.mainGroup == 29 && datatype.subGroup >= 10 && datatype.subGroup <= 12 && !datatype.index) + return busValueToSigned64(payload, payload_length, datatype, value); + + // DPT 219.* - Alarm Info + if (datatype.mainGroup == 219 && datatype.subGroup == 1 && datatype.index <= 10) + return busValueToAlarmInfo(payload, payload_length, datatype, value); + + // DPT 221.* - Serial Number + if (datatype.mainGroup == 221 && datatype.subGroup == 1 && datatype.index <= 1) + return busValueToSerialNumber(payload, payload_length, datatype, value); + + // DPT 217.* - Version + if (datatype.mainGroup == 217 && datatype.subGroup == 1 && datatype.index <= 2) + return busValueToVersion(payload, payload_length, datatype, value); + + // DPT 225.001/225.002 - Scaling Speed and Scaling Step Time + if (datatype.mainGroup == 225 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && datatype.index <= 1) + return busValueToScaling(payload, payload_length, datatype, value); + // DPT 225.003 - Next Tariff + if (datatype.mainGroup == 225 && datatype.subGroup == 3 && datatype.index <= 1) + return busValueToTariff(payload, payload_length, datatype, value); + + // DPT 231.* - Locale + if (datatype.mainGroup == 231 && datatype.subGroup == 1 && datatype.index <= 1) + return busValueToLocale(payload, payload_length, datatype, value); + + // DPT 232.600 - RGB + if (datatype.mainGroup == 232 && datatype.subGroup == 600 && !datatype.index) + return busValueToRGB(payload, payload_length, datatype, value); + + // DPT 234.* - Language and Region + if (datatype.mainGroup == 234 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && !datatype.index) + return busValueToLocale(payload, payload_length, datatype, value); + + // DPT 235.* - Active Energy + if (datatype.mainGroup == 235 && datatype.subGroup == 1 && datatype.index <= 3) + return busValueToActiveEnergy(payload, payload_length, datatype, value); + + // DPT 238.* - Scene Config + if (datatype.mainGroup == 238 && datatype.subGroup == 1 && datatype.index <= 2) + return busValueToSceneConfig(payload, payload_length, datatype, value); + + // DPT 239.* - Flagged Scaling + if (datatype.mainGroup == 239 && datatype.subGroup == 1 && datatype.index <= 1) + return busValueToFlaggedScaling(payload, payload_length, datatype, value); + + // DPT 251.600 - RGBW + if (datatype.mainGroup == 251 && datatype.subGroup == 600 && datatype.index <= 1) + return busValueToRGBW(payload, payload_length, datatype, value); + } + + return false; + } + + int KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + if (datatype.mainGroup == 1 && datatype.subGroup >= 1 && datatype.subGroup <= 23 && datatype.subGroup != 20 && !datatype.index) + return valueToBusValueBinary(value, payload, payload_length, datatype); + + // DPT 2.* - Binary Control if (datatype.mainGroup == 2 && datatype.subGroup >= 1 && datatype.subGroup <= 12 && datatype.index <= 1) - return busValueToBinaryControl(payload, payload_length, datatype, value); + return valueToBusValueBinaryControl(value, payload, payload_length, datatype); // DPT 3.* - Step Control if (datatype.mainGroup == 3 && datatype.subGroup >= 7 && datatype.subGroup <= 8 && datatype.index <= 1) - return busValueToStepControl(payload, payload_length, datatype, value); + return valueToBusValueStepControl(value, payload, payload_length, datatype); // DPT 4.* - Character if (datatype.mainGroup == 4 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && !datatype.index) - return busValueToCharacter(payload, payload_length, datatype, value); + return valueToBusValueCharacter(value, payload, payload_length, datatype); // DPT 5.* - Unsigned 8 Bit Integer if (datatype.mainGroup == 5 && ((datatype.subGroup >= 1 && datatype.subGroup <= 6 && datatype.subGroup != 2) || datatype.subGroup == 10) && !datatype.index) - return busValueToUnsigned8(payload, payload_length, datatype, value); + return valueToBusValueUnsigned8(value, payload, payload_length, datatype); // DPT 6.001/6.010 - Signed 8 Bit Integer if (datatype.mainGroup == 6 && (datatype.subGroup == 1 || datatype.subGroup == 10) && !datatype.index) - return busValueToSigned8(payload, payload_length, datatype, value); + return valueToBusValueSigned8(value, payload, payload_length, datatype); // DPT 6.020 - Status with Mode if (datatype.mainGroup == 6 && datatype.subGroup == 20 && datatype.index <= 5) - return busValueToStatusAndMode(payload, payload_length, datatype, value); + return valueToBusValueStatusAndMode(value, payload, payload_length, datatype); // DPT 7.001/7.010/7.011/7.012/7.013/7.600 - Unsigned 16 Bit Integer - if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13) || (datatype.subGroup == 600)) && !datatype.index) - return busValueToUnsigned16(payload, payload_length, datatype, value); + if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13) || datatype.subGroup == 600) && !datatype.index) + return valueToBusValueUnsigned16(value, payload, payload_length, datatype); // DPT 7.002-DPT 7.007 - Time Period if (datatype.mainGroup == 7 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index) - return busValueToTimePeriod(payload, payload_length, datatype, value); + return valueToBusValueTimePeriod(value, payload, payload_length, datatype); // DPT 8.001/8.010/8.011 - Signed 16 Bit Integer if (datatype.mainGroup == 8 && (datatype.subGroup == 1 || datatype.subGroup == 10 || datatype.subGroup == 11) && !datatype.index) - return busValueToSigned16(payload, payload_length, datatype, value); + return valueToBusValueSigned16(value, payload, payload_length, datatype); // DPT 8.002-DPT 8.007 - Time Delta if (datatype.mainGroup == 8 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index) - return busValueToTimeDelta(payload, payload_length, datatype, value); + return valueToBusValueTimeDelta(value, payload, payload_length, datatype); // DPT 9.* - 16 Bit Float - if (datatype.mainGroup == 9 && ((datatype.subGroup >= 1 && datatype.subGroup <= 11) || (datatype.subGroup >= 20 && datatype.subGroup <= 29)) && !datatype.index) - return busValueToFloat16(payload, payload_length, datatype, value); + if (datatype.mainGroup == 9 && ((datatype.subGroup >= 1 && datatype.subGroup <= 11 ) || (datatype.subGroup >= 20 && datatype.subGroup <= 29)) && !datatype.index) + return valueToBusValueFloat16(value, payload, payload_length, datatype); // DPT 10.* - Time and Weekday if (datatype.mainGroup == 10 && datatype.subGroup == 1 && datatype.index <= 1) - return busValueToTime(payload, payload_length, datatype, value); + return valueToBusValueTime(value, payload, payload_length, datatype); // DPT 11.* - Date if (datatype.mainGroup == 11 && datatype.subGroup == 1 && !datatype.index) - return busValueToDate(payload, payload_length, datatype, value); + return valueToBusValueDate(value, payload, payload_length, datatype); // DPT 12.* - Unsigned 32 Bit Integer if (datatype.mainGroup == 12 && datatype.subGroup == 1 && !datatype.index) - return busValueToUnsigned32(payload, payload_length, datatype, value); + return valueToBusValueUnsigned32(value, payload, payload_length, datatype); // DPT 13.001/13.002/13.010-13.015 - Signed 32 Bit Integer if (datatype.mainGroup == 13 && (datatype.subGroup == 1 || datatype.subGroup == 2 || (datatype.subGroup >= 10 && datatype.subGroup <= 15)) && !datatype.index) - return busValueToSigned32(payload, payload_length, datatype, value); + return valueToBusValueSigned32(value, payload, payload_length, datatype); // DPT 13.100 - Long Time Period if (datatype.mainGroup == 13 && datatype.subGroup == 100 && !datatype.index) - return busValueToLongTimePeriod(payload, payload_length, datatype, value); + return valueToBusValueLongTimePeriod(value, payload, payload_length, datatype); // DPT 14.* - 32 Bit Float if (datatype.mainGroup == 14 && datatype.subGroup <= 79 && !datatype.index) - return busValueToFloat32(payload, payload_length, datatype, value); + return valueToBusValueFloat32(value, payload, payload_length, datatype); // DPT 15.* - Access Data if (datatype.mainGroup == 15 && !datatype.subGroup && datatype.index <= 5) - return busValueToAccess(payload, payload_length, datatype, value); + return valueToBusValueAccess(value, payload, payload_length, datatype); // DPT 16.* - String if (datatype.mainGroup == 16 && datatype.subGroup <= 1 && !datatype.index) - return busValueToString(payload, payload_length, datatype, value); + return valueToBusValueString(value, payload, payload_length, datatype); // DPT 17.* - Scene Number if (datatype.mainGroup == 17 && datatype.subGroup == 1 && !datatype.index) - return busValueToScene(payload, payload_length, datatype, value); + return valueToBusValueScene(value, payload, payload_length, datatype); // DPT 18.* - Scene Control if (datatype.mainGroup == 18 && datatype.subGroup == 1 && datatype.index <= 1) - return busValueToSceneControl(payload, payload_length, datatype, value); + return valueToBusValueSceneControl(value, payload, payload_length, datatype); // DPT 19.* - Date and Time if (datatype.mainGroup == 19 && datatype.subGroup == 1 && (datatype.index <= 3 || datatype.index == 9 || datatype.index == 10)) - return busValueToDateTime(payload, payload_length, datatype, value); + return valueToBusValueDateTime(value, payload, payload_length, datatype); // DPT 26.* - Scene Info if (datatype.mainGroup == 26 && datatype.subGroup == 1 && datatype.index <= 1) - return busValueToSceneInfo(payload, payload_length, datatype, value); + return valueToBusValueSceneInfo(value, payload, payload_length, datatype); - // DPT 27.001 - 32 Bit field + // DPT 27.001 - 32 Bit Field if (datatype.mainGroup == 27 && datatype.subGroup == 1 && !datatype.index) - return busValueToSigned32(payload, payload_length, datatype, value); + return valueToBusValueUnsigned32(value, payload, payload_length, datatype); // DPT 28.* - Unicode String if (datatype.mainGroup == 28 && datatype.subGroup == 1 && !datatype.index) - return busValueToUnicode(payload, payload_length, datatype, value); + return valueToBusValueUnicode(value, payload, payload_length, datatype); // DPT 29.* - Signed 64 Bit Integer if (datatype.mainGroup == 29 && datatype.subGroup >= 10 && datatype.subGroup <= 12 && !datatype.index) - return busValueToSigned64(payload, payload_length, datatype, value); + return valueToBusValueSigned64(value, payload, payload_length, datatype); // DPT 219.* - Alarm Info if (datatype.mainGroup == 219 && datatype.subGroup == 1 && datatype.index <= 10) - return busValueToAlarmInfo(payload, payload_length, datatype, value); + return valueToBusValueAlarmInfo(value, payload, payload_length, datatype); // DPT 221.* - Serial Number if (datatype.mainGroup == 221 && datatype.subGroup == 1 && datatype.index <= 1) - return busValueToSerialNumber(payload, payload_length, datatype, value); + return valueToBusValueSerialNumber(value, payload, payload_length, datatype); // DPT 217.* - Version if (datatype.mainGroup == 217 && datatype.subGroup == 1 && datatype.index <= 2) - return busValueToVersion(payload, payload_length, datatype, value); + return valueToBusValueVersion(value, payload, payload_length, datatype); // DPT 225.001/225.002 - Scaling Speed and Scaling Step Time if (datatype.mainGroup == 225 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && datatype.index <= 1) - return busValueToScaling(payload, payload_length, datatype, value); + return valueToBusValueScaling(value, payload, payload_length, datatype); // DPT 225.003 - Next Tariff if (datatype.mainGroup == 225 && datatype.subGroup == 3 && datatype.index <= 1) - return busValueToTariff(payload, payload_length, datatype, value); + return valueToBusValueTariff(value, payload, payload_length, datatype); // DPT 231.* - Locale if (datatype.mainGroup == 231 && datatype.subGroup == 1 && datatype.index <= 1) - return busValueToLocale(payload, payload_length, datatype, value); + return valueToBusValueLocale(value, payload, payload_length, datatype); // DPT 232.600 - RGB if (datatype.mainGroup == 232 && datatype.subGroup == 600 && !datatype.index) - return busValueToRGB(payload, payload_length, datatype, value); + return valueToBusValueRGB(value, payload, payload_length, datatype); // DPT 234.* - Language and Region if (datatype.mainGroup == 234 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && !datatype.index) - return busValueToLocale(payload, payload_length, datatype, value); + return valueToBusValueLocale(value, payload, payload_length, datatype); // DPT 235.* - Active Energy if (datatype.mainGroup == 235 && datatype.subGroup == 1 && datatype.index <= 3) - return busValueToActiveEnergy(payload, payload_length, datatype, value); + return valueToBusValueActiveEnergy(value, payload, payload_length, datatype); // DPT 238.* - Scene Config if (datatype.mainGroup == 238 && datatype.subGroup == 1 && datatype.index <= 2) - return busValueToSceneConfig(payload, payload_length, datatype, value); + return valueToBusValueSceneConfig(value, payload, payload_length, datatype); // DPT 239.* - Flagged Scaling if (datatype.mainGroup == 239 && datatype.subGroup == 1 && datatype.index <= 1) - return busValueToFlaggedScaling(payload, payload_length, datatype, value); + return valueToBusValueFlaggedScaling(value, payload, payload_length, datatype); // DPT 251.600 - RGBW if (datatype.mainGroup == 251 && datatype.subGroup == 600 && datatype.index <= 1) - return busValueToRGBW(payload, payload_length, datatype, value); - } - - return false; -} - -int KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - if (datatype.mainGroup == 1 && datatype.subGroup >= 1 && datatype.subGroup <= 23 && datatype.subGroup != 20 && !datatype.index) - return valueToBusValueBinary(value, payload, payload_length, datatype); - - // DPT 2.* - Binary Control - if (datatype.mainGroup == 2 && datatype.subGroup >= 1 && datatype.subGroup <= 12 && datatype.index <= 1) - return valueToBusValueBinaryControl(value, payload, payload_length, datatype); - - // DPT 3.* - Step Control - if (datatype.mainGroup == 3 && datatype.subGroup >= 7 && datatype.subGroup <= 8 && datatype.index <= 1) - return valueToBusValueStepControl(value, payload, payload_length, datatype); - - // DPT 4.* - Character - if (datatype.mainGroup == 4 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && !datatype.index) - return valueToBusValueCharacter(value, payload, payload_length, datatype); - - // DPT 5.* - Unsigned 8 Bit Integer - if (datatype.mainGroup == 5 && ((datatype.subGroup >= 1 && datatype.subGroup <= 6 && datatype.subGroup != 2) || datatype.subGroup == 10) && !datatype.index) - return valueToBusValueUnsigned8(value, payload, payload_length, datatype); - - // DPT 6.001/6.010 - Signed 8 Bit Integer - if (datatype.mainGroup == 6 && (datatype.subGroup == 1 || datatype.subGroup == 10) && !datatype.index) - return valueToBusValueSigned8(value, payload, payload_length, datatype); - - // DPT 6.020 - Status with Mode - if (datatype.mainGroup == 6 && datatype.subGroup == 20 && datatype.index <= 5) - return valueToBusValueStatusAndMode(value, payload, payload_length, datatype); - - // DPT 7.001/7.010/7.011/7.012/7.013/7.600 - Unsigned 16 Bit Integer - if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13) || datatype.subGroup == 600) && !datatype.index) - return valueToBusValueUnsigned16(value, payload, payload_length, datatype); - - // DPT 7.002-DPT 7.007 - Time Period - if (datatype.mainGroup == 7 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index) - return valueToBusValueTimePeriod(value, payload, payload_length, datatype); - - // DPT 8.001/8.010/8.011 - Signed 16 Bit Integer - if (datatype.mainGroup == 8 && (datatype.subGroup == 1 || datatype.subGroup == 10 || datatype.subGroup == 11) && !datatype.index) - return valueToBusValueSigned16(value, payload, payload_length, datatype); - - // DPT 8.002-DPT 8.007 - Time Delta - if (datatype.mainGroup == 8 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index) - return valueToBusValueTimeDelta(value, payload, payload_length, datatype); - - // DPT 9.* - 16 Bit Float - if (datatype.mainGroup == 9 && ((datatype.subGroup >= 1 && datatype.subGroup <= 11 ) || (datatype.subGroup >= 20 && datatype.subGroup <= 29)) && !datatype.index) - return valueToBusValueFloat16(value, payload, payload_length, datatype); - - // DPT 10.* - Time and Weekday - if (datatype.mainGroup == 10 && datatype.subGroup == 1 && datatype.index <= 1) - return valueToBusValueTime(value, payload, payload_length, datatype); - - // DPT 11.* - Date - if (datatype.mainGroup == 11 && datatype.subGroup == 1 && !datatype.index) - return valueToBusValueDate(value, payload, payload_length, datatype); + return valueToBusValueRGBW(value, payload, payload_length, datatype); - // DPT 12.* - Unsigned 32 Bit Integer - if (datatype.mainGroup == 12 && datatype.subGroup == 1 && !datatype.index) - return valueToBusValueUnsigned32(value, payload, payload_length, datatype); - - // DPT 13.001/13.002/13.010-13.015 - Signed 32 Bit Integer - if (datatype.mainGroup == 13 && (datatype.subGroup == 1 || datatype.subGroup == 2 || (datatype.subGroup >= 10 && datatype.subGroup <= 15)) && !datatype.index) - return valueToBusValueSigned32(value, payload, payload_length, datatype); - - // DPT 13.100 - Long Time Period - if (datatype.mainGroup == 13 && datatype.subGroup == 100 && !datatype.index) - return valueToBusValueLongTimePeriod(value, payload, payload_length, datatype); - - // DPT 14.* - 32 Bit Float - if (datatype.mainGroup == 14 && datatype.subGroup <= 79 && !datatype.index) - return valueToBusValueFloat32(value, payload, payload_length, datatype); - - // DPT 15.* - Access Data - if (datatype.mainGroup == 15 && !datatype.subGroup && datatype.index <= 5) - return valueToBusValueAccess(value, payload, payload_length, datatype); + return false; + } - // DPT 16.* - String - if (datatype.mainGroup == 16 && datatype.subGroup <= 1 && !datatype.index) - return valueToBusValueString(value, payload, payload_length, datatype); + int busValueToBinary(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) + { + ASSERT_PAYLOAD(1); + value = bitFromPayload(payload, 7); + return true; + } - // DPT 17.* - Scene Number - if (datatype.mainGroup == 17 && datatype.subGroup == 1 && !datatype.index) - return valueToBusValueScene(value, payload, payload_length, datatype); + int busValueToBinaryControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) + { + ASSERT_PAYLOAD(1); - // DPT 18.* - Scene Control - if (datatype.mainGroup == 18 && datatype.subGroup == 1 && datatype.index <= 1) - return valueToBusValueSceneControl(value, payload, payload_length, datatype); + switch (datatype.index) + { + case 0: + value = bitFromPayload(payload, 6); + return true; - // DPT 19.* - Date and Time - if (datatype.mainGroup == 19 && datatype.subGroup == 1 && (datatype.index <= 3 || datatype.index == 9 || datatype.index == 10)) - return valueToBusValueDateTime(value, payload, payload_length, datatype); + case 1: + value = bitFromPayload(payload, 7); + return true; + } - // DPT 26.* - Scene Info - if (datatype.mainGroup == 26 && datatype.subGroup == 1 && datatype.index <= 1) - return valueToBusValueSceneInfo(value, payload, payload_length, datatype); + return false; + } - // DPT 27.001 - 32 Bit Field - if (datatype.mainGroup == 27 && datatype.subGroup == 1 && !datatype.index) - return valueToBusValueUnsigned32(value, payload, payload_length, datatype); + int busValueToStepControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) + { + ASSERT_PAYLOAD(1); - // DPT 28.* - Unicode String - if (datatype.mainGroup == 28 && datatype.subGroup == 1 && !datatype.index) - return valueToBusValueUnicode(value, payload, payload_length, datatype); + switch (datatype.index) + { + case 0: + value = bitFromPayload(payload, 4); + return true; - // DPT 29.* - Signed 64 Bit Integer - if (datatype.mainGroup == 29 && datatype.subGroup >= 10 && datatype.subGroup <= 12 && !datatype.index) - return valueToBusValueSigned64(value, payload, payload_length, datatype); + case 1: + { + const unsigned char stepCode = unsigned8FromPayload(payload, 0) & 0x07; + value = stepCode; + return true; + } + } - // DPT 219.* - Alarm Info - if (datatype.mainGroup == 219 && datatype.subGroup == 1 && datatype.index <= 10) - return valueToBusValueAlarmInfo(value, payload, payload_length, datatype); + return false; + } + int busValueToCharacter(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) + { + ASSERT_PAYLOAD(1); + int8_t charValue = signed8FromPayload(payload, 0); - // DPT 221.* - Serial Number - if (datatype.mainGroup == 221 && datatype.subGroup == 1 && datatype.index <= 1) - return valueToBusValueSerialNumber(value, payload, payload_length, datatype); + if (datatype.subGroup == 1 && (charValue & 0x80)) + return false; - // DPT 217.* - Version - if (datatype.mainGroup == 217 && datatype.subGroup == 1 && datatype.index <= 2) - return valueToBusValueVersion(value, payload, payload_length, datatype); + if (datatype.subGroup == 2) + { + value = (uint8_t)charValue; + return true; + } - // DPT 225.001/225.002 - Scaling Speed and Scaling Step Time - if (datatype.mainGroup == 225 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && datatype.index <= 1) - return valueToBusValueScaling(value, payload, payload_length, datatype); + value = charValue; + return true; + } - // DPT 225.003 - Next Tariff - if (datatype.mainGroup == 225 && datatype.subGroup == 3 && datatype.index <= 1) - return valueToBusValueTariff(value, payload, payload_length, datatype); + int busValueToUnsigned8(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) + { + ASSERT_PAYLOAD(1); - // DPT 231.* - Locale - if (datatype.mainGroup == 231 && datatype.subGroup == 1 && datatype.index <= 1) - return valueToBusValueLocale(value, payload, payload_length, datatype); + switch (datatype.subGroup) + { + case 1: + value = (uint8_t)round(unsigned8FromPayload(payload, 0) * 100.0 / 255.0); + return true; - // DPT 232.600 - RGB - if (datatype.mainGroup == 232 && datatype.subGroup == 600 && !datatype.index) - return valueToBusValueRGB(value, payload, payload_length, datatype); + case 3: + value = (uint8_t)round(unsigned8FromPayload(payload, 0) * 360.0 / 255.0); + return true; - // DPT 234.* - Language and Region - if (datatype.mainGroup == 234 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && !datatype.index) - return valueToBusValueLocale(value, payload, payload_length, datatype); + case 6: + { + uint8_t numValue = unsigned8FromPayload(payload, 0); - // DPT 235.* - Active Energy - if (datatype.mainGroup == 235 && datatype.subGroup == 1 && datatype.index <= 3) - return valueToBusValueActiveEnergy(value, payload, payload_length, datatype); + if (numValue == 0xFF) + return false; - // DPT 238.* - Scene Config - if (datatype.mainGroup == 238 && datatype.subGroup == 1 && datatype.index <= 2) - return valueToBusValueSceneConfig(value, payload, payload_length, datatype); + value = numValue; + return true; + } + } - // DPT 239.* - Flagged Scaling - if (datatype.mainGroup == 239 && datatype.subGroup == 1 && datatype.index <= 1) - return valueToBusValueFlaggedScaling(value, payload, payload_length, datatype); + value = unsigned8FromPayload(payload, 0); + return true; + } - // DPT 251.600 - RGBW - if (datatype.mainGroup == 251 && datatype.subGroup == 600 && datatype.index <= 1) - return valueToBusValueRGBW(value, payload, payload_length, datatype); + int busValueToSigned8(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) + { + ASSERT_PAYLOAD(1); + value = (uint8_t)(unsigned8FromPayload(payload, 0)); + return true; + } - return false; -} + int busValueToStatusAndMode(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) + { + ASSERT_PAYLOAD(1); -int busValueToBinary(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(1); - value = bitFromPayload(payload, 7); - return true; -} + if (datatype.index < 5) + { + value = bitFromPayload(payload, datatype.index); + return true; + } + else if (datatype.index == 5) + { + value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x07); + return true; + } -int busValueToBinaryControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(1); + return false; + } - switch (datatype.index) + int busValueToUnsigned16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - case 0: - value = bitFromPayload(payload, 6); - return true; - - case 1: - value = bitFromPayload(payload, 7); - return true; + ASSERT_PAYLOAD(2); + value = unsigned16FromPayload(payload, 0); + return true; } - return false; -} + int busValueToTimePeriod(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) + { + ASSERT_PAYLOAD(2); -int busValueToStepControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(1); + int64_t duration = unsigned16FromPayload(payload, 0); + value = duration; + return true; + } - switch (datatype.index) + int busValueToSigned16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - case 0: - value = bitFromPayload(payload, 4); - return true; + ASSERT_PAYLOAD(2); - case 1: + if (datatype.subGroup == 10) { - const unsigned char stepCode = unsigned8FromPayload(payload, 0) & 0x07; - value = stepCode; + value = signed16FromPayload(payload, 0) / 100.0; return true; } - } - - return false; -} -int busValueToCharacter(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(1); - int8_t charValue = signed8FromPayload(payload, 0); - if (datatype.subGroup == 1 && (charValue & 0x80)) - return false; + value = signed16FromPayload(payload, 0); + return true; + } - if (datatype.subGroup == 2) + int busValueToTimeDelta(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - value = (uint8_t)charValue; + ASSERT_PAYLOAD(2); + + int64_t duration = signed16FromPayload(payload, 0); + value = duration; return true; } - value = charValue; - return true; -} + int busValueToFloat16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) + { + ASSERT_PAYLOAD(2); -int busValueToUnsigned8(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(1); + if (unsigned16FromPayload(payload, 0) == 0x7FFF) + return false; - switch (datatype.subGroup) - { - case 1: - value = (uint8_t)round(unsigned8FromPayload(payload, 0) * 100.0 / 255.0); - return true; + value = float16FromPayload(payload, 0); + return true; + } - case 3: - value = (uint8_t)round(unsigned8FromPayload(payload, 0) * 360.0 / 255.0); - return true; + int busValueToTime(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) + { + ASSERT_PAYLOAD(3); - case 6: + switch (datatype.index) { - uint8_t numValue = unsigned8FromPayload(payload, 0); + case 0: + value = (uint8_t)((unsigned8FromPayload(payload, 0) >> 5) & 0x07); + return true; - if (numValue == 0xFF) - return false; + case 1: + { + unsigned char hours = unsigned8FromPayload(payload, 0) & 0x1F; + unsigned char weekDay = (unsigned8FromPayload(payload, 0) & 0xE0) >> 5; + unsigned char minutes = unsigned8FromPayload(payload, 1) & 0x3F; + unsigned char seconds = unsigned8FromPayload(payload, 2) & 0x3F; - value = numValue; - return true; + if (hours > 23 || minutes > 59 || seconds > 59) + return false; + + struct tm tmp = {0}; + tmp.tm_hour = hours; + tmp.tm_wday = weekDay; + tmp.tm_min = minutes; + tmp.tm_sec = seconds; + value = tmp; + return true; + } } + + return false; } - value = unsigned8FromPayload(payload, 0); - return true; -} + int busValueToDate(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) + { + ASSERT_PAYLOAD(3); + unsigned short year = unsigned8FromPayload(payload, 2) & 0x7F; + unsigned char month = unsigned8FromPayload(payload, 1) & 0x0F; + unsigned char day = unsigned8FromPayload(payload, 0) & 0x1F; -int busValueToSigned8(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(1); - value = (uint8_t)(unsigned8FromPayload(payload, 0)); - return true; -} + if (year > 99 || month < 1 || month > 12 || day < 1) + return false; -int busValueToStatusAndMode(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(1); + struct tm tmp = {0}; + year += year >= 90 ? 1900 : 2000; + tmp.tm_mday = day; + tmp.tm_year = year; + tmp.tm_mon = month; + value = tmp; + return true; + } - if (datatype.index < 5) + int busValueToUnsigned32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - value = bitFromPayload(payload, datatype.index); + ASSERT_PAYLOAD(4); + value = unsigned32FromPayload(payload, 0); return true; } - else if (datatype.index == 5) + + int busValueToSigned32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x07); + ASSERT_PAYLOAD(4); + value = signed32FromPayload(payload, 0); return true; } - return false; -} - -int busValueToUnsigned16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(2); - value = unsigned16FromPayload(payload, 0); - return true; -} - -int busValueToTimePeriod(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(2); - - int64_t duration = unsigned16FromPayload(payload, 0); - value = duration; - return true; -} - -int busValueToSigned16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(2); - - if (datatype.subGroup == 10) + int busValueToLongTimePeriod(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - value = signed16FromPayload(payload, 0) / 100.0; + ASSERT_PAYLOAD(4); + value = signed32FromPayload(payload, 0); return true; } - value = signed16FromPayload(payload, 0); - return true; -} - -int busValueToTimeDelta(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(2); - - int64_t duration = signed16FromPayload(payload, 0); - value = duration; - return true; -} + int busValueToFloat32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) + { + ASSERT_PAYLOAD(4); + value = float32FromPayload(payload, 0); + return true; + } -int busValueToFloat16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(2); + int busValueToAccess(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) + { + ASSERT_PAYLOAD(4); - if (unsigned16FromPayload(payload, 0) == 0x7FFF) - return false; + switch (datatype.index) + { + case 0: + { + int32_t digits = 0; - value = float16FromPayload(payload, 0); - return true; -} + for (int n = 0, factor = 100000; n < 6; ++n, factor /= 10) + { + unsigned char digit = bcdFromPayload(payload, n); -int busValueToTime(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(3); + if (digit > 9) + return false; - switch (datatype.index) - { - case 0: - value = (uint8_t)((unsigned8FromPayload(payload, 0) >> 5) & 0x07); - return true; + digits += digit * factor; + } - case 1: - { - unsigned char hours = unsigned8FromPayload(payload, 0) & 0x1F; - unsigned char weekDay = (unsigned8FromPayload(payload, 0) & 0xE0) >> 5; - unsigned char minutes = unsigned8FromPayload(payload, 1) & 0x3F; - unsigned char seconds = unsigned8FromPayload(payload, 2) & 0x3F; + value = digits; + return true; + } - if (hours > 23 || minutes > 59 || seconds > 59) - return false; + case 1: + case 2: + case 3: + case 4: + value = bitFromPayload(payload, 23 + datatype.index); + return true; - struct tm tmp = {0}; - tmp.tm_hour = hours; - tmp.tm_wday = weekDay; - tmp.tm_min = minutes; - tmp.tm_sec = seconds; - value = tmp; - return true; + case 5: + value = bcdFromPayload(payload, 7); + return true; } - } - return false; -} - -int busValueToDate(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(3); - unsigned short year = unsigned8FromPayload(payload, 2) & 0x7F; - unsigned char month = unsigned8FromPayload(payload, 1) & 0x0F; - unsigned char day = unsigned8FromPayload(payload, 0) & 0x1F; - - if (year > 99 || month < 1 || month > 12 || day < 1) return false; + } - struct tm tmp = {0}; - year += year >= 90 ? 1900 : 2000; - tmp.tm_mday = day; - tmp.tm_year = year; - tmp.tm_mon = month; - value = tmp; - return true; -} - -int busValueToUnsigned32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(4); - value = unsigned32FromPayload(payload, 0); - return true; -} + int busValueToString(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) + { + ASSERT_PAYLOAD(14); -int busValueToSigned32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(4); - value = signed32FromPayload(payload, 0); - return true; -} + for (int n = 0; n < 14; ++n) + { + auto value = signed8FromPayload(payload, n); -int busValueToLongTimePeriod(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(4); - value = signed32FromPayload(payload, 0); - return true; -} + if (!datatype.subGroup && (value & 0x80)) + return false; + } -int busValueToFloat32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(4); - value = float32FromPayload(payload, 0); - return true; -} + value = (const char*) payload; + return true; + } -int busValueToAccess(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(4); + int busValueToScene(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) + { + ASSERT_PAYLOAD(1); + value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x3F); + return true; + } - switch (datatype.index) + int busValueToSceneControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - case 0: - { - int32_t digits = 0; + ASSERT_PAYLOAD(1); - for (int n = 0, factor = 100000; n < 6; ++n, factor /= 10) + switch (datatype.index) + { + case 0: { - unsigned char digit = bcdFromPayload(payload, n); - - if (digit > 9) - return false; - - digits += digit * factor; + value = bitFromPayload(payload, 0); + return true; } - value = digits; - return true; + case 1: + { + value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x3F); + return true; + } } - case 1: - case 2: - case 3: - case 4: - value = bitFromPayload(payload, 23 + datatype.index); - return true; - - case 5: - value = bcdFromPayload(payload, 7); - return true; + return false; } - return false; -} - -int busValueToString(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(14); - - for (int n = 0; n < 14; ++n) + int busValueToSceneInfo(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - auto value = signed8FromPayload(payload, n); - - if (!datatype.subGroup && (value & 0x80)) - return false; - } + ASSERT_PAYLOAD(1); - value = (const char*) payload; - return true; -} - -int busValueToScene(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(1); - value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x3F); - return true; -} - -int busValueToSceneControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(1); - - switch (datatype.index) - { - case 0: + switch (datatype.index) { - value = bitFromPayload(payload, 0); - return true; - } + case 0: + { + value = bitFromPayload(payload, 1); + return true; + } - case 1: - { - value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x3F); - return true; + case 1: + { + value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x3F); + return true; + } } - } - return false; -} - -int busValueToSceneInfo(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(1); + return false; + } - switch (datatype.index) + int busValueToSceneConfig(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - case 0: - { - value = bitFromPayload(payload, 1); - return true; - } + ASSERT_PAYLOAD(1); - case 1: + switch (datatype.index) { - value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x3F); - return true; - } - } + case 0: + { + value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x3F); + return true; + } - return false; -} + case 1: + case 2: + { + value = bitFromPayload(payload, 2 - datatype.index); + return true; + } + } -int busValueToSceneConfig(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(1); + return false; + } - switch (datatype.index) + int busValueToDateTime(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - case 0: + ASSERT_PAYLOAD(8); + + if (datatype.index == 3) { - value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x3F); + value = bitFromPayload(payload, 48); return true; } - case 1: - case 2: + if (!bitFromPayload(payload, 48)) { - value = bitFromPayload(payload, 2 - datatype.index); - return true; + switch (datatype.index) + { + case 0: + { + if (bitFromPayload(payload, 51) || bitFromPayload(payload, 52)) + return false; + + unsigned short year = unsigned8FromPayload(payload, 0) + 1900; + unsigned short month = unsigned8FromPayload(payload, 1) & 0x0F; + unsigned short day = unsigned8FromPayload(payload, 2) & 0x1F; + unsigned short hours = unsigned8FromPayload(payload, 3) & 0x1F; + unsigned short minutes = unsigned8FromPayload(payload, 4) & 0x3F; + unsigned short seconds = unsigned8FromPayload(payload, 5) & 0x3F; + + if ((month < 1 || month > 12 || day < 1)) + return false; + + if ((hours > 24 || minutes > 59 || seconds > 59)) + return false; + + struct tm tmp = {0}; + tmp.tm_sec = seconds; + tmp.tm_min = minutes; + tmp.tm_hour = hours; + tmp.tm_mday = day; + tmp.tm_mon = month; + tmp.tm_year = year; + value = tmp; + return true; + } + + case 1: + { + if (bitFromPayload(payload, 53)) + return false; + + value = (uint8_t)((unsigned8FromPayload(payload, 3) >> 5) & 0x07); + return true; + } + + case 2: + { + if (bitFromPayload(payload, 50)) + return false; + + value = bitFromPayload(payload, 49); + return true; + } + + case 9: + { + value = bitFromPayload(payload, 55); + return true; + } + + case 10: + { + value = bitFromPayload(payload, 56); + return true; + } + } } - } - return false; -} + return false; + } -int busValueToDateTime(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(8); + int busValueToUnicode(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) + { + //TODO + return false; + } - if (datatype.index == 3) + int busValueToSigned64(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - value = bitFromPayload(payload, 48); + ASSERT_PAYLOAD(8); + value = signed64FromPayload(payload, 0); return true; } - if (!bitFromPayload(payload, 48)) + int busValueToAlarmInfo(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { + ASSERT_PAYLOAD(6); + switch (datatype.index) { - case 0: - { - if (bitFromPayload(payload, 51) || bitFromPayload(payload, 52)) - return false; - - unsigned short year = unsigned8FromPayload(payload, 0) + 1900; - unsigned short month = unsigned8FromPayload(payload, 1) & 0x0F; - unsigned short day = unsigned8FromPayload(payload, 2) & 0x1F; - unsigned short hours = unsigned8FromPayload(payload, 3) & 0x1F; - unsigned short minutes = unsigned8FromPayload(payload, 4) & 0x3F; - unsigned short seconds = unsigned8FromPayload(payload, 5) & 0x3F; - - if ((month < 1 || month > 12 || day < 1)) - return false; - - if ((hours > 24 || minutes > 59 || seconds > 59)) - return false; - - struct tm tmp = {0}; - tmp.tm_sec = seconds; - tmp.tm_min = minutes; - tmp.tm_hour = hours; - tmp.tm_mday = day; - tmp.tm_mon = month; - tmp.tm_year = year; - value = tmp; - return true; - } - case 1: { - if (bitFromPayload(payload, 53)) + unsigned char prio = unsigned8FromPayload(payload, 1); + + if (prio > 3) return false; - value = (uint8_t)((unsigned8FromPayload(payload, 3) >> 5) & 0x07); + value = prio; return true; } + case 0: case 2: - { - if (bitFromPayload(payload, 50)) - return false; - - value = bitFromPayload(payload, 49); + case 3: + value = unsigned8FromPayload(payload, datatype.index); return true; - } - case 9: - { - value = bitFromPayload(payload, 55); + case 4: + case 5: + case 6: + case 7: + value = bitFromPayload(payload, 43 - datatype.index); return true; - } + case 8: + case 9: case 10: - { - value = bitFromPayload(payload, 56); + value = bitFromPayload(payload, 55 - datatype.index); return true; - } } + + return false; } - return false; -} + int busValueToSerialNumber(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) + { + ASSERT_PAYLOAD(6); -int busValueToUnicode(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - //TODO - return false; -} + switch (datatype.index) + { + case 0: + value = unsigned16FromPayload(payload, 0); + return true; -int busValueToSigned64(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(8); - value = signed64FromPayload(payload, 0); - return true; -} + case 1: + value = unsigned32FromPayload(payload, 2); + return true; + } -int busValueToAlarmInfo(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(6); + return false; + } - switch (datatype.index) + int busValueToVersion(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - case 1: + ASSERT_PAYLOAD(2); + + switch (datatype.index) { - unsigned char prio = unsigned8FromPayload(payload, 1); + case 0: + value = (uint8_t)((unsigned8FromPayload(payload, 0) >> 3) & 0x1F); + return true; - if (prio > 3) - return false; + case 1: + value = (uint16_t)((unsigned16FromPayload(payload, 0) >> 6) & 0x1F); + return true; - value = prio; - return true; + case 2: + value = (uint8_t)(unsigned8FromPayload(payload, 1) & 0x3F); + return true; } - case 0: - case 2: - case 3: - value = unsigned8FromPayload(payload, datatype.index); - return true; - - case 4: - case 5: - case 6: - case 7: - value = bitFromPayload(payload, 43 - datatype.index); - return true; - - case 8: - case 9: - case 10: - value = bitFromPayload(payload, 55 - datatype.index); - return true; + return false; } - return false; -} - -int busValueToSerialNumber(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(6); - - switch (datatype.index) + int busValueToScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - case 0: - value = unsigned16FromPayload(payload, 0); - return true; + ASSERT_PAYLOAD(3); - case 1: - value = unsigned32FromPayload(payload, 2); - return true; - } + switch (datatype.index) + { + case 0: + value = unsigned16FromPayload(payload, 0); + return true; - return false; -} + case 1: + value = (uint8_t)(unsigned8FromPayload(payload, 2) * 100.0 / 255.0); + return true; + } -int busValueToVersion(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(2); + return false; + } - switch (datatype.index) + int busValueToTariff(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - case 0: - value = (uint8_t)((unsigned8FromPayload(payload, 0) >> 3) & 0x1F); - return true; - - case 1: - value = (uint16_t)((unsigned16FromPayload(payload, 0) >> 6) & 0x1F); - return true; + ASSERT_PAYLOAD(3); - case 2: - value = (uint8_t)(unsigned8FromPayload(payload, 1) & 0x3F); - return true; - } + switch (datatype.index) + { + case 0: + value = unsigned16FromPayload(payload, 0); + return true; - return false; -} + case 1: + { + uint8_t tariff = unsigned8FromPayload(payload, 2); -int busValueToScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(3); + if (tariff > 254) + return false; - switch (datatype.index) - { - case 0: - value = unsigned16FromPayload(payload, 0); - return true; + value = tariff; + return true; + } + } - case 1: - value = (uint8_t)(unsigned8FromPayload(payload, 2) * 100.0 / 255.0); - return true; + return false; } - return false; -} - -int busValueToTariff(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(3); - - switch (datatype.index) + int busValueToLocale(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - case 0: - value = unsigned16FromPayload(payload, 0); - return true; + ASSERT_PAYLOAD(datatype.mainGroup == 231 ? 4 : 2); - case 1: + if (!datatype.index || (datatype.mainGroup == 231 && datatype.index == 1)) { - uint8_t tariff = unsigned8FromPayload(payload, 2); - - if (tariff > 254) - return false; - - value = tariff; + char code[2]; + code[0] = unsigned8FromPayload(payload, datatype.index * 2); + code[1] = unsigned8FromPayload(payload, datatype.index * 2 + 1); + value = code; return true; } - } - return false; -} - -int busValueToLocale(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(datatype.mainGroup == 231 ? 4 : 2); + return false; + } - if (!datatype.index || (datatype.mainGroup == 231 && datatype.index == 1)) + int busValueToRGB(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - char code[2]; - code[0] = unsigned8FromPayload(payload, datatype.index * 2); - code[1] = unsigned8FromPayload(payload, datatype.index * 2 + 1); - value = code; + ASSERT_PAYLOAD(3); + uint32_t rgb = unsigned16FromPayload(payload, 0) * 256 + unsigned8FromPayload(payload, 2); + value = rgb; return true; } - return false; -} - -int busValueToRGB(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(3); - uint32_t rgb = unsigned16FromPayload(payload, 0) * 256 + unsigned8FromPayload(payload, 2); - value = rgb; - return true; -} - -int busValueToRGBW(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(6); - - switch (datatype.index) + int busValueToRGBW(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - case 0: // The RGBW value - { - uint32_t rgbw = unsigned32FromPayload(payload, 0); - value = rgbw; - } + ASSERT_PAYLOAD(6); - return true; + switch (datatype.index) + { + case 0: // The RGBW value + { + uint32_t rgbw = unsigned32FromPayload(payload, 0); + value = rgbw; + } - case 1: // The mask bits only - value = unsigned8FromPayload(payload, 5); return true; - } - return false; -} + case 1: // The mask bits only + value = unsigned8FromPayload(payload, 5); + return true; + } -int busValueToFlaggedScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(2); + return false; + } - switch (datatype.index) + int busValueToFlaggedScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - case 0: - value = (uint8_t)(unsigned8FromPayload(payload, 0) * 100.0 / 255.0); - return true; + ASSERT_PAYLOAD(2); - case 1: - value = bitFromPayload(payload, 15); - return true; - } + switch (datatype.index) + { + case 0: + value = (uint8_t)(unsigned8FromPayload(payload, 0) * 100.0 / 255.0); + return true; - return false; -} + case 1: + value = bitFromPayload(payload, 15); + return true; + } -int busValueToActiveEnergy(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) -{ - ASSERT_PAYLOAD(6); + return false; + } - switch (datatype.index) + int busValueToActiveEnergy(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { - case 0: - value = signed32FromPayload(payload, 0); - return true; + ASSERT_PAYLOAD(6); - case 1: - value = unsigned8FromPayload(payload, 4); - return true; + switch (datatype.index) + { + case 0: + value = signed32FromPayload(payload, 0); + return true; - case 2: - case 3: - value = bitFromPayload(payload, datatype.index + 44); - return true; - } + case 1: + value = unsigned8FromPayload(payload, 4); + return true; - return false; -} + case 2: + case 3: + value = bitFromPayload(payload, datatype.index + 44); + return true; + } -//------------------------------------------------------------------------------------------------------------------------------------- + return false; + } -int valueToBusValueBinary(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - bitToPayload(payload, payload_length, 7, value); - return true; -} + //------------------------------------------------------------------------------------------------------------------------------------- -int valueToBusValueBinaryControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - switch (datatype.index) + int valueToBusValueBinary(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - case 0: - bitToPayload(payload, payload_length, 6, value); - break; - - case 1: - bitToPayload(payload, payload_length, 7, value); - break; - - default: - return false; + bitToPayload(payload, payload_length, 7, value); + return true; } - return true; -} - -int valueToBusValueStepControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - switch (datatype.index) + int valueToBusValueBinaryControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - case 0: - bitToPayload(payload, payload_length, 4, value); - break; - - case 1: + switch (datatype.index) { - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(7)) - return false; + case 0: + bitToPayload(payload, payload_length, 6, value); + break; - unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0x07); + case 1: + bitToPayload(payload, payload_length, 7, value); + break; + + default: + return false; } - break; - default: - return false; + return true; } - return true; -} - -int valueToBusValueCharacter(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - if ((uint64_t)value > INT64_C(255) || (datatype.subGroup == 1 && (uint64_t)value > INT64_C(127))) - return false; - - unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF); - return true; -} - -int valueToBusValueUnsigned8(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - if ((int64_t)value < INT64_C(0)) - return false; - - switch (datatype.subGroup) + int valueToBusValueStepControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - case 1: + switch (datatype.index) { - if ((double)value > 100.0) - return false; - - unsigned8ToPayload(payload, payload_length, 0, round((double)value * 255.0 / 100.0), 0xFF); - break; - } + case 0: + bitToPayload(payload, payload_length, 4, value); + break; - case 3: - { - if ((double)value > 360.0) - return false; + case 1: + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(7)) + return false; - unsigned8ToPayload(payload, payload_length, 0, round((double)value * 255.0 / 360.0), 0xFF); + unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0x07); + } break; - } - case 6: - { - if ((int64_t)value > INT64_C(254)) + default: return false; - - unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF); - break; } - default: - { - if ((int64_t)value > INT64_C(255)) - return false; - - unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF); - } + return true; } - return true; -} - -int valueToBusValueSigned8(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - if ((int64_t)value < INT64_C(-128) || (int64_t)value > INT64_C(127)) - return false; + int valueToBusValueCharacter(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + if ((uint64_t)value > INT64_C(255) || (datatype.subGroup == 1 && (uint64_t)value > INT64_C(127))) + return false; - signed8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF); - return true; -} + unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF); + return true; + } -int valueToBusValueStatusAndMode(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - if (datatype.index < 5) - bitToPayload(payload, payload_length, datatype.index, value); - else if (datatype.index == 5) + int valueToBusValueUnsigned8(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(7)) + if ((int64_t)value < INT64_C(0)) return false; - unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0x07); - } - else - return false; + switch (datatype.subGroup) + { + case 1: + { + if ((double)value > 100.0) + return false; - return true; -} + unsigned8ToPayload(payload, payload_length, 0, round((double)value * 255.0 / 100.0), 0xFF); + break; + } -int valueToBusValueUnsigned16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(65535)) - return false; + case 3: + { + if ((double)value > 360.0) + return false; - unsigned16ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFFFF); - return true; -} + unsigned8ToPayload(payload, payload_length, 0, round((double)value * 255.0 / 360.0), 0xFF); + break; + } -int valueToBusValueTimePeriod(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - struct tm tmp = value; - time_t timeSinceEpoch = mktime(&tmp); + case 6: + { + if ((int64_t)value > INT64_C(254)) + return false; - if (timeSinceEpoch < INT64_C(0) || timeSinceEpoch > INT64_C(65535)) - return false; + unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF); + break; + } - unsigned16ToPayload(payload, payload_length, 0, timeSinceEpoch, 0xFFFF); - return true; -} + default: + { + if ((int64_t)value > INT64_C(255)) + return false; -int valueToBusValueSigned16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - if ((int64_t)value < INT64_C(-32768) || (int64_t)value > INT64_C(32767)) - return false; + unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF); + } + } + + return true; + } - if (datatype.subGroup == 10) + int valueToBusValueSigned8(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - if ((double)value < -327.68 || (double)value > 327.67) + if ((int64_t)value < INT64_C(-128) || (int64_t)value > INT64_C(127)) return false; - signed16ToPayload(payload, payload_length, 0, (int16_t)((double)value * 100.0), 0xFFFF); + signed8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF); + return true; } - else - signed16ToPayload(payload, payload_length, 0, (uint64_t)value, 0xffff); - - return true; -} - -int valueToBusValueTimeDelta(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - struct tm tmp = value; - time_t timeSinceEpoch = mktime(&tmp); - - if (timeSinceEpoch < INT64_C(-32768) || timeSinceEpoch > INT64_C(32767)) - return false; - - signed16ToPayload(payload, payload_length, 0, timeSinceEpoch, 0xFFFF); - return true; -} - -int valueToBusValueFloat16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - double numValue = value; - - // bigger values like 670760.0 result in 0x7FFF which denotes invalid data. - // I'm not sure if the GO shouldn't be updated to this value instead - if (numValue > 670433.28) - return false; - if (numValue < -671088.64) - return false; - - switch (datatype.subGroup) + int valueToBusValueStatusAndMode(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - case 1: - if (numValue < -273.0) + if (datatype.index < 5) + bitToPayload(payload, payload_length, datatype.index, value); + else if (datatype.index == 5) + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(7)) return false; - break; + unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0x07); + } + else + return false; - case 2: - case 3: - case 10: - case 11: - case 20: - case 21: - case 22: - case 23: - case 24: - case 25: - if (numValue < -670760.0) - return false; + return true; + } - break; + int valueToBusValueUnsigned16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(65535)) + return false; - case 4: - case 5: - case 6: - case 7: - case 8: - case 28: - if (numValue < 0.0) - return false; + unsigned16ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFFFF); + return true; + } - break; + int valueToBusValueTimePeriod(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + struct tm tmp = value; + time_t timeSinceEpoch = mktime(&tmp); - case 27: - if (numValue < -459.6) - return false; + if (timeSinceEpoch < INT64_C(0) || timeSinceEpoch > INT64_C(65535)) + return false; - break; + unsigned16ToPayload(payload, payload_length, 0, timeSinceEpoch, 0xFFFF); + return true; } - float16ToPayload(payload, payload_length, 0, numValue, 0xFFFF); - return true; -} - -int valueToBusValueTime(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - switch (datatype.index) + int valueToBusValueSigned16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - case 0: + if ((int64_t)value < INT64_C(-32768) || (int64_t)value > INT64_C(32767)) + return false; + + if (datatype.subGroup == 10) { - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(7)) + if ((double)value < -327.68 || (double)value > 327.67) return false; - ENSURE_PAYLOAD(3); - unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value << 5, 0xE0); - break; + signed16ToPayload(payload, payload_length, 0, (int16_t)((double)value * 100.0), 0xFFFF); } + else + signed16ToPayload(payload, payload_length, 0, (uint64_t)value, 0xffff); - case 1: - { - struct tm tmp = value; - unsigned8ToPayload(payload, payload_length, 0, tmp.tm_hour, 0x1F); - unsigned8ToPayload(payload, payload_length, 1, tmp.tm_min, 0x3F); - unsigned8ToPayload(payload, payload_length, 2, tmp.tm_sec, 0x3F); - break; - } + return true; + } + + int valueToBusValueTimeDelta(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + struct tm tmp = value; + time_t timeSinceEpoch = mktime(&tmp); - default: + if (timeSinceEpoch < INT64_C(-32768) || timeSinceEpoch > INT64_C(32767)) return false; - } - return true; -} + signed16ToPayload(payload, payload_length, 0, timeSinceEpoch, 0xFFFF); + return true; + } -int valueToBusValueDate(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - struct tm tmp = value; + int valueToBusValueFloat16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + double numValue = value; - if (tmp.tm_year < 1990 || tmp.tm_year > 2089) - return false; + // bigger values like 670760.0 result in 0x7FFF which denotes invalid data. + // I'm not sure if the GO shouldn't be updated to this value instead + if (numValue > 670433.28) + return false; - unsigned8ToPayload(payload, payload_length, 0, tmp.tm_mday, 0x1F); - unsigned8ToPayload(payload, payload_length, 1, tmp.tm_mon, 0x0F); - unsigned8ToPayload(payload, payload_length, 2, tmp.tm_year % 100, 0x7F); - return true; -} + if (numValue < -671088.64) + return false; -int valueToBusValueUnsigned32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(4294967295)) - return false; + switch (datatype.subGroup) + { + case 1: + if (numValue < -273.0) + return false; - unsigned32ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFFFFFFFF); - return true; -} + break; -int valueToBusValueSigned32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - if ((int64_t)value < INT64_C(-2147483648) || (int64_t)value > INT64_C(2147483647)) - return false; + case 2: + case 3: + case 10: + case 11: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + if (numValue < -670760.0) + return false; - signed32ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFFFFFFFF); - return true; -} + break; -int valueToBusValueLongTimePeriod(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - if ((int64_t)value < INT64_C(-2147483648) || (int64_t)value > INT64_C(2147483647)) - return false; + case 4: + case 5: + case 6: + case 7: + case 8: + case 28: + if (numValue < 0.0) + return false; - signed32ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFFFFFFFF); - return true; -} + break; -int valueToBusValueFloat32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - double numValue = value; + case 27: + if (numValue < -459.6) + return false; - if (numValue < (-8388608.0 * pow(2, 255)) || numValue > (8388607.0 * pow(2, 255))) - return false; + break; + } - float32ToPayload(payload, payload_length, 0, numValue, 0xFFFFFFFF); - return true; -} + float16ToPayload(payload, payload_length, 0, numValue, 0xFFFF); + return true; + } -int valueToBusValueAccess(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - switch (datatype.index) + int valueToBusValueTime(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - case 0: + switch (datatype.index) { - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(999999)) - return false; + case 0: + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(7)) + return false; - ENSURE_PAYLOAD(4); + ENSURE_PAYLOAD(3); + unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value << 5, 0xE0); + break; + } - for (int n = 0, factor = 100000; n < 6; ++n, factor /= 10) - bcdToPayload(payload, payload_length, n, ((uint64_t)value / factor) % 10); + case 1: + { + struct tm tmp = value; + unsigned8ToPayload(payload, payload_length, 0, tmp.tm_hour, 0x1F); + unsigned8ToPayload(payload, payload_length, 1, tmp.tm_min, 0x3F); + unsigned8ToPayload(payload, payload_length, 2, tmp.tm_sec, 0x3F); + break; + } - break; + default: + return false; } - case 1: - case 2: - case 3: - case 4: - bitToPayload(payload, payload_length, 23 + datatype.index, value); - break; + return true; + } - case 5: - { - if ((uint64_t)value > INT64_C(15)) - return false; + int valueToBusValueDate(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + struct tm tmp = value; - bcdToPayload(payload, payload_length, 7, (uint64_t)value); - break; - } + if (tmp.tm_year < 1990 || tmp.tm_year > 2089) + return false; - default: + unsigned8ToPayload(payload, payload_length, 0, tmp.tm_mday, 0x1F); + unsigned8ToPayload(payload, payload_length, 1, tmp.tm_mon, 0x0F); + unsigned8ToPayload(payload, payload_length, 2, tmp.tm_year % 100, 0x7F); + return true; + } + + int valueToBusValueUnsigned32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(4294967295)) return false; + + unsigned32ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFFFFFFFF); + return true; } - return true; -} + int valueToBusValueSigned32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + if ((int64_t)value < INT64_C(-2147483648) || (int64_t)value > INT64_C(2147483647)) + return false; -int valueToBusValueString(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - const char* strValue = value; - uint8_t val = strValue[0]; + signed32ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFFFFFFFF); + return true; + } - for (int n = 0; n < 14; n++) + int valueToBusValueLongTimePeriod(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - if (val) - val = strValue[n]; //string terminator 0x00 will stop further assignments and init the remainig payload with zero + if ((int64_t)value < INT64_C(-2147483648) || (int64_t)value > INT64_C(2147483647)) + return false; - unsigned8ToPayload(payload, payload_length, n, val, 0xff); + signed32ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFFFFFFFF); + return true; } - return true; -} + int valueToBusValueFloat32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + double numValue = value; -int valueToBusValueScene(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(63)) - return false; + if (numValue < (-8388608.0 * pow(2, 255)) || numValue > (8388607.0 * pow(2, 255))) + return false; - unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF); - return true; -} + float32ToPayload(payload, payload_length, 0, numValue, 0xFFFFFFFF); + return true; + } -int valueToBusValueSceneControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - switch (datatype.index) + int valueToBusValueAccess(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - case 0: - bitToPayload(payload, payload_length, 0, value); - break; - - case 1: + switch (datatype.index) { - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(63)) - return false; + case 0: + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(999999)) + return false; - unsigned8ToPayload(payload, payload_length, 0, (int64_t)value, 0x3F); - break; - } + ENSURE_PAYLOAD(4); - default: - return false; - } + for (int n = 0, factor = 100000; n < 6; ++n, factor /= 10) + bcdToPayload(payload, payload_length, n, ((uint64_t)value / factor) % 10); - return true; -} + break; + } -int valueToBusValueSceneInfo(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - switch (datatype.index) - { - case 0: - bitToPayload(payload, payload_length, 1, value); - break; + case 1: + case 2: + case 3: + case 4: + bitToPayload(payload, payload_length, 23 + datatype.index, value); + break; - case 1: - { - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(63)) - return false; + case 5: + { + if ((uint64_t)value > INT64_C(15)) + return false; - unsigned8ToPayload(payload, payload_length, 0, (int64_t)value, 0x3F); - break; + bcdToPayload(payload, payload_length, 7, (uint64_t)value); + break; + } + + default: + return false; } - default: - return false; + return true; } - return true; -} - -int valueToBusValueSceneConfig(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - switch (datatype.index) + int valueToBusValueString(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - case 0: + const char* strValue = value; + uint8_t val = strValue[0]; + + for (int n = 0; n < 14; n++) { - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(63)) - return false; + if (val) + val = strValue[n]; //string terminator 0x00 will stop further assignments and init the remainig payload with zero - unsigned8ToPayload(payload, payload_length, 0, (int64_t)value, 0x3F); - break; + unsigned8ToPayload(payload, payload_length, n, val, 0xff); } - case 1: - case 2: - bitToPayload(payload, payload_length, 2 - datatype.index, value); - break; + return true; + } - default: + int valueToBusValueScene(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(63)) return false; - } - return true; -} + unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF); + return true; + } -int valueToBusValueDateTime(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - switch (datatype.index) + int valueToBusValueSceneControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - case 0: + switch (datatype.index) { - struct tm local = value; - time_t time = mktime(&local); + case 0: + bitToPayload(payload, payload_length, 0, value); + break; - if (!time) //TODO add check if date or time is invalid - return false; + case 1: + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(63)) + return false; - ENSURE_PAYLOAD(8); - struct tm tmp = value; - bitToPayload(payload, payload_length, 51, false); - bitToPayload(payload, payload_length, 52, false); - unsigned8ToPayload(payload, payload_length, 0, tmp.tm_year - 1900, 0xFF); - unsigned8ToPayload(payload, payload_length, 1, tmp.tm_mon, 0x0F); - unsigned8ToPayload(payload, payload_length, 2, tmp.tm_mday, 0x1F); - - bitToPayload(payload, payload_length, 54, false); - unsigned8ToPayload(payload, payload_length, 3, tmp.tm_hour, 0x1F); - unsigned8ToPayload(payload, payload_length, 4, tmp.tm_min, 0x3F); - unsigned8ToPayload(payload, payload_length, 5, tmp.tm_sec, 0x3F); - break; + unsigned8ToPayload(payload, payload_length, 0, (int64_t)value, 0x3F); + break; + } + + default: + return false; } - case 1: + return true; + } + + int valueToBusValueSceneInfo(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + switch (datatype.index) { - ENSURE_PAYLOAD(8); + case 0: + bitToPayload(payload, payload_length, 1, value); + break; - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(7)) - bitToPayload(payload, payload_length, 53, true); - else + case 1: { - bitToPayload(payload, payload_length, 53, false); - unsigned8ToPayload(payload, payload_length, 3, (int64_t)value << 5, 0xE0); + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(63)) + return false; + + unsigned8ToPayload(payload, payload_length, 0, (int64_t)value, 0x3F); + break; } - break; + default: + return false; } - case 2: - { - ENSURE_PAYLOAD(8); - bitToPayload(payload, payload_length, 49, value); - bitToPayload(payload, payload_length, 50, false); - break; - } + return true; + } - case 3: + int valueToBusValueSceneConfig(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + switch (datatype.index) { - ENSURE_PAYLOAD(8); - bitToPayload(payload, payload_length, 48, value); - break; - } + case 0: + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(63)) + return false; - case 9: - { - ENSURE_PAYLOAD(8); - bitToPayload(payload, payload_length, 55, value); - break; - } + unsigned8ToPayload(payload, payload_length, 0, (int64_t)value, 0x3F); + break; + } - case 10: - { - bitToPayload(payload, payload_length, 56, value); - break; + case 1: + case 2: + bitToPayload(payload, payload_length, 2 - datatype.index, value); + break; + + default: + return false; } - default: - return false; + return true; } - return true; -} - -int valueToBusValueUnicode(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - //TODO - return false; -} - -int valueToBusValueSigned64(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - signed64ToPayload(payload, payload_length, 0, (int64_t)value, UINT64_C(0xFFFFFFFFFFFFFFFF)); - return true; -} - -int valueToBusValueAlarmInfo(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - switch (datatype.index) + int valueToBusValueDateTime(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - case 1: + switch (datatype.index) { - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(3)) - return false; + case 0: + { + struct tm local = value; + time_t time = mktime(&local); - ENSURE_PAYLOAD(6); - unsigned8ToPayload(payload, payload_length, 1, (int64_t)value, 0xFF); - break; - } + if (!time) //TODO add check if date or time is invalid + return false; - case 0: - case 2: - case 3: - { - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(255)) - return false; + ENSURE_PAYLOAD(8); + struct tm tmp = value; + bitToPayload(payload, payload_length, 51, false); + bitToPayload(payload, payload_length, 52, false); + unsigned8ToPayload(payload, payload_length, 0, tmp.tm_year - 1900, 0xFF); + unsigned8ToPayload(payload, payload_length, 1, tmp.tm_mon, 0x0F); + unsigned8ToPayload(payload, payload_length, 2, tmp.tm_mday, 0x1F); + + bitToPayload(payload, payload_length, 54, false); + unsigned8ToPayload(payload, payload_length, 3, tmp.tm_hour, 0x1F); + unsigned8ToPayload(payload, payload_length, 4, tmp.tm_min, 0x3F); + unsigned8ToPayload(payload, payload_length, 5, tmp.tm_sec, 0x3F); + break; + } - ENSURE_PAYLOAD(6); - unsigned8ToPayload(payload, payload_length, datatype.index, (int64_t)value, 0xFF); - break; - } + case 1: + { + ENSURE_PAYLOAD(8); - case 4: - case 5: - case 6: - case 7: - { - ENSURE_PAYLOAD(6); - bitToPayload(payload, payload_length, 43 - datatype.index, value); - break; - } + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(7)) + bitToPayload(payload, payload_length, 53, true); + else + { + bitToPayload(payload, payload_length, 53, false); + unsigned8ToPayload(payload, payload_length, 3, (int64_t)value << 5, 0xE0); + } - case 8: - case 9: - case 10: - { - ENSURE_PAYLOAD(6); - bitToPayload(payload, payload_length, 55 - datatype.index, value); - break; - } + break; + } - default: - return false; - } + case 2: + { + ENSURE_PAYLOAD(8); + bitToPayload(payload, payload_length, 49, value); + bitToPayload(payload, payload_length, 50, false); + break; + } - return true; -} + case 3: + { + ENSURE_PAYLOAD(8); + bitToPayload(payload, payload_length, 48, value); + break; + } -int valueToBusValueSerialNumber(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - switch (datatype.index) - { - case 0: - { - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(65535)) - return false; + case 9: + { + ENSURE_PAYLOAD(8); + bitToPayload(payload, payload_length, 55, value); + break; + } - ENSURE_PAYLOAD(6); - unsigned16ToPayload(payload, payload_length, 0, (int64_t)value, 0xFFFF); - break; - } + case 10: + { + bitToPayload(payload, payload_length, 56, value); + break; + } - case 1: - { - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(4294967295)) + default: return false; - - ENSURE_PAYLOAD(6); - unsigned32ToPayload(payload, payload_length, 2, (int64_t)value, 0xFFFF); - break; } - default: - return false; + return true; } - return true; -} + int valueToBusValueUnicode(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + //TODO + return false; + } -int valueToBusValueVersion(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - switch (datatype.index) + int valueToBusValueSigned64(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - case 0: + signed64ToPayload(payload, payload_length, 0, (int64_t)value, UINT64_C(0xFFFFFFFFFFFFFFFF)); + return true; + } + + int valueToBusValueAlarmInfo(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + switch (datatype.index) { - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(31)) - return false; + case 1: + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(3)) + return false; - ENSURE_PAYLOAD(2); - unsigned8ToPayload(payload, payload_length, 0, (int64_t)value << 3, 0xF8); - break; - } + ENSURE_PAYLOAD(6); + unsigned8ToPayload(payload, payload_length, 1, (int64_t)value, 0xFF); + break; + } - case 1: - { - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(31)) - return false; + case 0: + case 2: + case 3: + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(255)) + return false; - unsigned16ToPayload(payload, payload_length, 0, (int64_t)value << 6, 0x07C0); - break; - } + ENSURE_PAYLOAD(6); + unsigned8ToPayload(payload, payload_length, datatype.index, (int64_t)value, 0xFF); + break; + } - case 2: - { - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(63)) - return false; + case 4: + case 5: + case 6: + case 7: + { + ENSURE_PAYLOAD(6); + bitToPayload(payload, payload_length, 43 - datatype.index, value); + break; + } - unsigned8ToPayload(payload, payload_length, 1, (int64_t)value, 0x3F); - break; + case 8: + case 9: + case 10: + { + ENSURE_PAYLOAD(6); + bitToPayload(payload, payload_length, 55 - datatype.index, value); + break; + } + + default: + return false; } - default: - return false; + return true; } - return true; -} - -int valueToBusValueScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - switch (datatype.index) + int valueToBusValueSerialNumber(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - case 0: + switch (datatype.index) { - uint32_t duration = value; + case 0: + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(65535)) + return false; - if (duration > INT64_C(65535)) - return false; + ENSURE_PAYLOAD(6); + unsigned16ToPayload(payload, payload_length, 0, (int64_t)value, 0xFFFF); + break; + } - ENSURE_PAYLOAD(3); - unsigned16ToPayload(payload, payload_length, 0, duration, 0xFFFF); - return true; - } + case 1: + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(4294967295)) + return false; - case 1: - { - if ((double)value < 0.0 || (double)value > 100.0) - return false; + ENSURE_PAYLOAD(6); + unsigned32ToPayload(payload, payload_length, 2, (int64_t)value, 0xFFFF); + break; + } - unsigned8ToPayload(payload, payload_length, 2, round((double)value * 255.0 / 100.0), 0xff); - break; + default: + return false; } - } - return true; -} + return true; + } -int valueToBusValueTariff(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - switch (datatype.index) + int valueToBusValueVersion(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - case 0: + switch (datatype.index) { - uint32_t duration = value; + case 0: + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(31)) + return false; - if (duration > INT64_C(65535)) - return false; + ENSURE_PAYLOAD(2); + unsigned8ToPayload(payload, payload_length, 0, (int64_t)value << 3, 0xF8); + break; + } - ENSURE_PAYLOAD(3); - unsigned16ToPayload(payload, payload_length, 0, duration, 0xFFFF); - return true; - } + case 1: + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(31)) + return false; - case 1: - { - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(254)) - return false; + unsigned16ToPayload(payload, payload_length, 0, (int64_t)value << 6, 0x07C0); + break; + } - unsigned8ToPayload(payload, payload_length, 2, (int64_t)value, 0xff); - break; + case 2: + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(63)) + return false; + + unsigned8ToPayload(payload, payload_length, 1, (int64_t)value, 0x3F); + break; + } + + default: + return false; } + + return true; } - return true; -} + int valueToBusValueScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + switch (datatype.index) + { + case 0: + { + uint32_t duration = value; -int valueToBusValueLocale(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - int strl = strlen(value); + if (duration > INT64_C(65535)) + return false; - if (strl != 2) - return false; + ENSURE_PAYLOAD(3); + unsigned16ToPayload(payload, payload_length, 0, duration, 0xFFFF); + return true; + } + + case 1: + { + if ((double)value < 0.0 || (double)value > 100.0) + return false; + + unsigned8ToPayload(payload, payload_length, 2, round((double)value * 255.0 / 100.0), 0xff); + break; + } + } - if (!datatype.index || (datatype.mainGroup == 231 && datatype.index == 1)) - { - ENSURE_PAYLOAD(datatype.mainGroup == 231 ? 4 : 2); - unsigned8ToPayload(payload, payload_length, datatype.index * 2, ((const char*)value)[0], 0xff); - unsigned8ToPayload(payload, payload_length, datatype.index * 2 + 1, ((const char*)value)[1], 0xff); return true; } - return false; -} + int valueToBusValueTariff(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + switch (datatype.index) + { + case 0: + { + uint32_t duration = value; -int valueToBusValueRGB(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(16777215)) - return false; + if (duration > INT64_C(65535)) + return false; - unsigned int rgb = (int64_t)value; + ENSURE_PAYLOAD(3); + unsigned16ToPayload(payload, payload_length, 0, duration, 0xFFFF); + return true; + } - unsigned16ToPayload(payload, payload_length, 0, rgb / 256, 0xffff); - unsigned8ToPayload(payload, payload_length, 2, rgb % 256, 0xff); - return true; -} + case 1: + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(254)) + return false; -int valueToBusValueRGBW(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - switch (datatype.index) - { - case 0: // RGBW - { - uint32_t rgbw = (uint32_t)value; - unsigned32ToPayload(payload, payload_length, 0, rgbw, 0xffffffff); // RGBW + unsigned8ToPayload(payload, payload_length, 2, (int64_t)value, 0xff); + break; + } } - break; - case 1: // Mask bits - unsigned8ToPayload(payload, payload_length, 5, (uint8_t)value, 0x0f); - break; + return true; } - return true; -} - -int valueToBusValueFlaggedScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - switch (datatype.index) + int valueToBusValueLocale(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - case 0: - { - if ((double)value < 0.0 || (double)value > 100.0) - return false; + int strl = strlen(value); - ENSURE_PAYLOAD(2); - unsigned8ToPayload(payload, payload_length, 0, round((double)value * 255.0 / 100.0), 0xff); - break; + if (strl != 2) + return false; + + if (!datatype.index || (datatype.mainGroup == 231 && datatype.index == 1)) + { + ENSURE_PAYLOAD(datatype.mainGroup == 231 ? 4 : 2); + unsigned8ToPayload(payload, payload_length, datatype.index * 2, ((const char*)value)[0], 0xff); + unsigned8ToPayload(payload, payload_length, datatype.index * 2 + 1, ((const char*)value)[1], 0xff); + return true; } - case 1: - bitToPayload(payload, payload_length, 15, value); - break; + return false; + } - default: + int valueToBusValueRGB(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(16777215)) return false; - } - return true; -} + unsigned int rgb = (int64_t)value; -int valueToBusValueActiveEnergy(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) -{ - switch (datatype.index) + unsigned16ToPayload(payload, payload_length, 0, rgb / 256, 0xffff); + unsigned8ToPayload(payload, payload_length, 2, rgb % 256, 0xff); + return true; + } + + int valueToBusValueRGBW(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - case 0: + switch (datatype.index) { - if ((int64_t)value < INT64_C(-2147483648) || (int64_t)value > INT64_C(2147483647)) - return false; - - ENSURE_PAYLOAD(6); - signed32ToPayload(payload, payload_length, 0, (int64_t)value, 0xffffffff); + case 0: // RGBW + { + uint32_t rgbw = (uint32_t)value; + unsigned32ToPayload(payload, payload_length, 0, rgbw, 0xffffffff); // RGBW + } break; + + case 1: // Mask bits + unsigned8ToPayload(payload, payload_length, 5, (uint8_t)value, 0x0f); + break; } - case 1: + return true; + } + + int valueToBusValueFlaggedScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + switch (datatype.index) { - if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(254)) - return false; + case 0: + { + if ((double)value < 0.0 || (double)value > 100.0) + return false; - ENSURE_PAYLOAD(6); - unsigned8ToPayload(payload, payload_length, 4, (int64_t)value, 0xff); - break; - } + ENSURE_PAYLOAD(2); + unsigned8ToPayload(payload, payload_length, 0, round((double)value * 255.0 / 100.0), 0xff); + break; + } - case 2: - case 3: - bitToPayload(payload, payload_length, datatype.index + 44, value); - break; + case 1: + bitToPayload(payload, payload_length, 15, value); + break; - default: - return false; + default: + return false; + } + + return true; } - return true; -} + int valueToBusValueActiveEnergy(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) + { + switch (datatype.index) + { + case 0: + { + if ((int64_t)value < INT64_C(-2147483648) || (int64_t)value > INT64_C(2147483647)) + return false; -// Helper functions -bool bitFromPayload(const uint8_t* payload, int index) -{ - int bit = payload[index / 8] & (1 << (7 - (index % 8))); - return bit ? true : false; -} -uint8_t unsigned8FromPayload(const uint8_t* payload, int index) -{ - return (uint8_t)payload[index]; -} -int8_t signed8FromPayload(const uint8_t* payload, int index) -{ - return (int8_t)payload[index]; -} -uint16_t unsigned16FromPayload(const uint8_t* payload, int index) -{ - return ((((uint16_t)payload[index]) << 8) & 0xFF00) | (((uint16_t)payload[index + 1]) & 0x00FF); -} -int16_t signed16FromPayload(const uint8_t* payload, int index) -{ - return ((((uint16_t)payload[index]) << 8) & 0xFF00) | (((uint16_t)payload[index + 1]) & 0x00FF); -} -uint32_t unsigned32FromPayload(const uint8_t* payload, int index) -{ - return ((((uint32_t)payload[index]) << 24) & 0xFF000000) | - ((((uint32_t)payload[index + 1]) << 16) & 0x00FF0000) | - ((((uint32_t)payload[index + 2]) << 8) & 0x0000FF00) | - (((uint32_t)payload[index + 3]) & 0x000000FF); -} -int32_t signed32FromPayload(const uint8_t* payload, int index) -{ - return (int32_t)unsigned32FromPayload(payload, index); -} -uint64_t unsigned64FromPayload(const uint8_t* payload, int index) -{ - return ((((uint64_t)payload[index]) << 56) & 0xFF00000000000000) | - ((((uint64_t)payload[index + 1]) << 48) & 0x00FF000000000000) | - ((((uint64_t)payload[index + 2]) << 40) & 0x0000FF0000000000) | - ((((uint64_t)payload[index + 3]) << 32) & 0x000000FF00000000) | - ((((uint64_t)payload[index + 4]) << 24) & 0x00000000FF000000) | - ((((uint64_t)payload[index + 5]) << 16) & 0x0000000000FF0000) | - ((((uint64_t)payload[index + 6]) << 8) & 0x000000000000FF00) | - (((uint64_t)payload[index + 7]) & 0x00000000000000FF); -} -double float16FromPayload(const uint8_t* payload, int index) -{ - uint16_t mantissa = unsigned16FromPayload(payload, index) & 0x87FF; + ENSURE_PAYLOAD(6); + signed32ToPayload(payload, payload_length, 0, (int64_t)value, 0xffffffff); + break; + } - if (mantissa & 0x8000) - return ((~mantissa & 0x07FF) + 1.0) * -0.01 * (1 << ((payload[index] >> 3) & 0x0F)); + case 1: + { + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(254)) + return false; - return mantissa * 0.01 * (1 << ((payload[index] >> 3) & 0x0F)); -} -float float32FromPayload(const uint8_t* payload, int index) -{ - union - { - float f; - uint32_t i; - } area; - area.i = unsigned32FromPayload(payload, index); - return area.f; -} -double float64FromPayload(const uint8_t* payload, int index) -{ - union - { - double f; - uint64_t i; - } area; - area.i = unsigned64FromPayload(payload, index); - return area.f; -} -int64_t signed64FromPayload(const uint8_t* payload, int index) -{ - return ((((uint64_t)payload[index]) << 56) & UINT64_C(0xFF00000000000000)) | - ((((uint64_t)payload[index + 1]) << 48) & UINT64_C(0x00FF000000000000)) | - ((((uint64_t)payload[index + 2]) << 40) & UINT64_C(0x0000FF0000000000)) | - ((((uint64_t)payload[index + 3]) << 32) & UINT64_C(0x000000FF00000000)) | - ((((uint64_t)payload[index + 4]) << 24) & UINT64_C(0x00000000FF000000)) | - ((((uint64_t)payload[index + 5]) << 16) & UINT64_C(0x0000000000FF0000)) | - ((((uint64_t)payload[index + 6]) << 8) & UINT64_C(0x000000000000FF00)) | - (((uint64_t)payload[index + 7]) & UINT64_C(0x00000000000000FF)); -} -uint8_t bcdFromPayload(const uint8_t* payload, int index) -{ - if (index % 2) - return (uint8_t)(payload[index / 2] & 0x0F); + ENSURE_PAYLOAD(6); + unsigned8ToPayload(payload, payload_length, 4, (int64_t)value, 0xff); + break; + } - return (uint8_t)((payload[index / 2] >> 4) & 0x0F); -} + case 2: + case 3: + bitToPayload(payload, payload_length, datatype.index + 44, value); + break; -void bitToPayload(uint8_t* payload, size_t payload_length, int index, bool value) -{ - ENSURE_PAYLOAD(index / 8 + 1); - payload[index / 8] = (payload[index / 8] & ~(1 << (7 - (index % 8)))) | (value ? (1 << (7 - (index % 8))) : 0); -} -void unsigned8ToPayload(uint8_t* payload, size_t payload_length, int index, uint8_t value, uint8_t mask) -{ - ENSURE_PAYLOAD(index + 1); - payload[index] = (payload[index] & ~mask) | (value & mask); -} -void signed8ToPayload(uint8_t* payload, size_t payload_length, int index, int8_t value, uint8_t mask) -{ - ENSURE_PAYLOAD(index + 1); - payload[index] = (payload[index] & ~mask) | (value & mask); -} -void unsigned16ToPayload(uint8_t* payload, size_t payload_length, int index, uint16_t value, uint16_t mask) -{ - ENSURE_PAYLOAD(index + 2); - payload[index] = (payload[index] & (~mask >> 8)) | ((value >> 8) & (mask >> 8)); - payload[index + 1] = (payload[index + 1] & ~mask) | (value & mask); -} -void signed16ToPayload(uint8_t* payload, size_t payload_length, int index, int16_t value, uint16_t mask) -{ - ENSURE_PAYLOAD(index + 2); - payload[index] = (payload[index] & (~mask >> 8)) | ((value >> 8) & (mask >> 8)); - payload[index + 1] = (payload[index + 1] & ~mask) | (value & mask); -} -void unsigned32ToPayload(uint8_t* payload, size_t payload_length, int index, uint32_t value, uint32_t mask) -{ - ENSURE_PAYLOAD(index + 4); - payload[index] = (payload[index] & (~mask >> 24)) | ((value >> 24) & (mask >> 24)); - payload[index + 1] = (payload[index + 1] & (~mask >> 16)) | ((value >> 16) & (mask >> 16)); - payload[index + 2] = (payload[index + 2] & (~mask >> 8)) | ((value >> 8) & (mask >> 8)); - payload[index + 3] = (payload[index + 3] & ~mask) | (value & mask); -} -void signed32ToPayload(uint8_t* payload, size_t payload_length, int index, int32_t value, uint32_t mask) -{ - ENSURE_PAYLOAD(index + 4); - payload[index] = (payload[index] & (~mask >> 24)) | ((value >> 24) & (mask >> 24)); - payload[index + 1] = (payload[index + 1] & (~mask >> 16)) | ((value >> 16) & (mask >> 16)); - payload[index + 2] = (payload[index + 2] & (~mask >> 8)) | ((value >> 8) & (mask >> 8)); - payload[index + 3] = (payload[index + 3] & ~mask) | (value & mask); -} - -void float16ToPayload(uint8_t* payload, size_t payload_length, int index, double value, uint16_t mask) -{ - bool wasNegative = false; + default: + return false; + } - if (value < 0) + return true; + } + + // Helper functions + bool bitFromPayload(const uint8_t* payload, int index) + { + int bit = payload[index / 8] & (1 << (7 - (index % 8))); + return bit ? true : false; + } + uint8_t unsigned8FromPayload(const uint8_t* payload, int index) + { + return (uint8_t)payload[index]; + } + int8_t signed8FromPayload(const uint8_t* payload, int index) + { + return (int8_t)payload[index]; + } + uint16_t unsigned16FromPayload(const uint8_t* payload, int index) { - wasNegative = true; - value *= -1; + return ((((uint16_t)payload[index]) << 8) & 0xFF00) | (((uint16_t)payload[index + 1]) & 0x00FF); } + int16_t signed16FromPayload(const uint8_t* payload, int index) + { + return ((((uint16_t)payload[index]) << 8) & 0xFF00) | (((uint16_t)payload[index + 1]) & 0x00FF); + } + uint32_t unsigned32FromPayload(const uint8_t* payload, int index) + { + return ((((uint32_t)payload[index]) << 24) & 0xFF000000) | + ((((uint32_t)payload[index + 1]) << 16) & 0x00FF0000) | + ((((uint32_t)payload[index + 2]) << 8) & 0x0000FF00) | + (((uint32_t)payload[index + 3]) & 0x000000FF); + } + int32_t signed32FromPayload(const uint8_t* payload, int index) + { + return (int32_t)unsigned32FromPayload(payload, index); + } + uint64_t unsigned64FromPayload(const uint8_t* payload, int index) + { + return ((((uint64_t)payload[index]) << 56) & 0xFF00000000000000) | + ((((uint64_t)payload[index + 1]) << 48) & 0x00FF000000000000) | + ((((uint64_t)payload[index + 2]) << 40) & 0x0000FF0000000000) | + ((((uint64_t)payload[index + 3]) << 32) & 0x000000FF00000000) | + ((((uint64_t)payload[index + 4]) << 24) & 0x00000000FF000000) | + ((((uint64_t)payload[index + 5]) << 16) & 0x0000000000FF0000) | + ((((uint64_t)payload[index + 6]) << 8) & 0x000000000000FF00) | + (((uint64_t)payload[index + 7]) & 0x00000000000000FF); + } + double float16FromPayload(const uint8_t* payload, int index) + { + uint16_t mantissa = unsigned16FromPayload(payload, index) & 0x87FF; - value *= 100.0; - unsigned short exponent = 0; + if (mantissa & 0x8000) + return ((~mantissa & 0x07FF) + 1.0) * -0.01 * (1 << ((payload[index] >> 3) & 0x0F)); - if (value > 2048) - exponent = ceil(log2(value) - 11.0); + return mantissa * 0.01 * (1 << ((payload[index] >> 3) & 0x0F)); + } + float float32FromPayload(const uint8_t* payload, int index) + { + union + { + float f; + uint32_t i; + } area; + area.i = unsigned32FromPayload(payload, index); + return area.f; + } + double float64FromPayload(const uint8_t* payload, int index) + { + union + { + double f; + uint64_t i; + } area; + area.i = unsigned64FromPayload(payload, index); + return area.f; + } + int64_t signed64FromPayload(const uint8_t* payload, int index) + { + return ((((uint64_t)payload[index]) << 56) & UINT64_C(0xFF00000000000000)) | + ((((uint64_t)payload[index + 1]) << 48) & UINT64_C(0x00FF000000000000)) | + ((((uint64_t)payload[index + 2]) << 40) & UINT64_C(0x0000FF0000000000)) | + ((((uint64_t)payload[index + 3]) << 32) & UINT64_C(0x000000FF00000000)) | + ((((uint64_t)payload[index + 4]) << 24) & UINT64_C(0x00000000FF000000)) | + ((((uint64_t)payload[index + 5]) << 16) & UINT64_C(0x0000000000FF0000)) | + ((((uint64_t)payload[index + 6]) << 8) & UINT64_C(0x000000000000FF00)) | + (((uint64_t)payload[index + 7]) & UINT64_C(0x00000000000000FF)); + } + uint8_t bcdFromPayload(const uint8_t* payload, int index) + { + if (index % 2) + return (uint8_t)(payload[index / 2] & 0x0F); - short mantissa = roundf(value / (1 << exponent)); + return (uint8_t)((payload[index / 2] >> 4) & 0x0F); + } - // above calculation causes mantissa overflow for values of the form 2^n, where n>11 - if (mantissa >= 0x800) + void bitToPayload(uint8_t* payload, size_t payload_length, int index, bool value) + { + ENSURE_PAYLOAD(index / 8 + 1); + payload[index / 8] = (payload[index / 8] & ~(1 << (7 - (index % 8)))) | (value ? (1 << (7 - (index % 8))) : 0); + } + void unsigned8ToPayload(uint8_t* payload, size_t payload_length, int index, uint8_t value, uint8_t mask) + { + ENSURE_PAYLOAD(index + 1); + payload[index] = (payload[index] & ~mask) | (value & mask); + } + void signed8ToPayload(uint8_t* payload, size_t payload_length, int index, int8_t value, uint8_t mask) + { + ENSURE_PAYLOAD(index + 1); + payload[index] = (payload[index] & ~mask) | (value & mask); + } + void unsigned16ToPayload(uint8_t* payload, size_t payload_length, int index, uint16_t value, uint16_t mask) + { + ENSURE_PAYLOAD(index + 2); + payload[index] = (payload[index] & (~mask >> 8)) | ((value >> 8) & (mask >> 8)); + payload[index + 1] = (payload[index + 1] & ~mask) | (value & mask); + } + void signed16ToPayload(uint8_t* payload, size_t payload_length, int index, int16_t value, uint16_t mask) + { + ENSURE_PAYLOAD(index + 2); + payload[index] = (payload[index] & (~mask >> 8)) | ((value >> 8) & (mask >> 8)); + payload[index + 1] = (payload[index + 1] & ~mask) | (value & mask); + } + void unsigned32ToPayload(uint8_t* payload, size_t payload_length, int index, uint32_t value, uint32_t mask) + { + ENSURE_PAYLOAD(index + 4); + payload[index] = (payload[index] & (~mask >> 24)) | ((value >> 24) & (mask >> 24)); + payload[index + 1] = (payload[index + 1] & (~mask >> 16)) | ((value >> 16) & (mask >> 16)); + payload[index + 2] = (payload[index + 2] & (~mask >> 8)) | ((value >> 8) & (mask >> 8)); + payload[index + 3] = (payload[index + 3] & ~mask) | (value & mask); + } + void signed32ToPayload(uint8_t* payload, size_t payload_length, int index, int32_t value, uint32_t mask) { - exponent++; - mantissa = roundf(value / (1 << exponent)); + ENSURE_PAYLOAD(index + 4); + payload[index] = (payload[index] & (~mask >> 24)) | ((value >> 24) & (mask >> 24)); + payload[index + 1] = (payload[index + 1] & (~mask >> 16)) | ((value >> 16) & (mask >> 16)); + payload[index + 2] = (payload[index + 2] & (~mask >> 8)) | ((value >> 8) & (mask >> 8)); + payload[index + 3] = (payload[index + 3] & ~mask) | (value & mask); } - if (wasNegative) - mantissa *= -1; + void float16ToPayload(uint8_t* payload, size_t payload_length, int index, double value, uint16_t mask) + { + bool wasNegative = false; - // println(mantissa); + if (value < 0) + { + wasNegative = true; + value *= -1; + } - signed16ToPayload(payload, payload_length, index, mantissa, mask); - unsigned8ToPayload(payload, payload_length, index, exponent << 3, 0x78 & (mask >> 8)); -} -void float32ToPayload(uint8_t* payload, size_t payload_length, int index, double value, uint32_t mask) -{ - union - { - float f; - uint32_t i; - } num; - num.f = value; - unsigned32ToPayload(payload, payload_length, index, num.i, mask); -} -void signed64ToPayload(uint8_t* payload, size_t payload_length, int index, int64_t value, uint64_t mask) -{ - ENSURE_PAYLOAD(index + 8); - payload[index] = (payload[index] & (~mask >> 56)) | ((value >> 56) & (mask >> 56)); - payload[index + 1] = (payload[index + 1] & (~mask >> 48)) | ((value >> 48) & (mask >> 48)); - payload[index + 2] = (payload[index + 2] & (~mask >> 40)) | ((value >> 40) & (mask >> 40)); - payload[index + 3] = (payload[index + 3] & (~mask >> 32)) | ((value >> 32) & (mask >> 32)); - payload[index + 4] = (payload[index + 4] & (~mask >> 24)) | ((value >> 24) & (mask >> 24)); - payload[index + 5] = (payload[index + 5] & (~mask >> 16)) | ((value >> 16) & (mask >> 16)); - payload[index + 6] = (payload[index + 6] & (~mask >> 8)) | ((value >> 8) & (mask >> 8)); - payload[index + 7] = (payload[index + 7] & ~mask) | (value & mask); -} -void bcdToPayload(uint8_t* payload, size_t payload_length, int index, uint8_t value) -{ - ENSURE_PAYLOAD(index / 2 + 1); + value *= 100.0; + unsigned short exponent = 0; + + if (value > 2048) + exponent = ceil(log2(value) - 11.0); + + short mantissa = roundf(value / (1 << exponent)); + + // above calculation causes mantissa overflow for values of the form 2^n, where n>11 + if (mantissa >= 0x800) + { + exponent++; + mantissa = roundf(value / (1 << exponent)); + } + + if (wasNegative) + mantissa *= -1; + + // println(mantissa); - if (index % 2) - payload[index / 2] = (payload[index / 2] & 0xF0) | (value & 0x0F); - else - payload[index / 2] = (payload[index / 2] & 0x0F) | ((value << 4) & 0xF0); -} + signed16ToPayload(payload, payload_length, index, mantissa, mask); + unsigned8ToPayload(payload, payload_length, index, exponent << 3, 0x78 & (mask >> 8)); + } + void float32ToPayload(uint8_t* payload, size_t payload_length, int index, double value, uint32_t mask) + { + union + { + float f; + uint32_t i; + } num; + num.f = value; + unsigned32ToPayload(payload, payload_length, index, num.i, mask); + } + void signed64ToPayload(uint8_t* payload, size_t payload_length, int index, int64_t value, uint64_t mask) + { + ENSURE_PAYLOAD(index + 8); + payload[index] = (payload[index] & (~mask >> 56)) | ((value >> 56) & (mask >> 56)); + payload[index + 1] = (payload[index + 1] & (~mask >> 48)) | ((value >> 48) & (mask >> 48)); + payload[index + 2] = (payload[index + 2] & (~mask >> 40)) | ((value >> 40) & (mask >> 40)); + payload[index + 3] = (payload[index + 3] & (~mask >> 32)) | ((value >> 32) & (mask >> 32)); + payload[index + 4] = (payload[index + 4] & (~mask >> 24)) | ((value >> 24) & (mask >> 24)); + payload[index + 5] = (payload[index + 5] & (~mask >> 16)) | ((value >> 16) & (mask >> 16)); + payload[index + 6] = (payload[index + 6] & (~mask >> 8)) | ((value >> 8) & (mask >> 8)); + payload[index + 7] = (payload[index + 7] & ~mask) | (value & mask); + } + void bcdToPayload(uint8_t* payload, size_t payload_length, int index, uint8_t value) + { + ENSURE_PAYLOAD(index / 2 + 1); + + if (index % 2) + payload[index / 2] = (payload[index / 2] & 0xF0) | (value & 0x0F); + else + payload[index / 2] = (payload[index / 2] & 0x0F) | ((value << 4) & 0xF0); + } +} \ No newline at end of file diff --git a/src/knx/group_object/dptconvert.h b/src/knx/group_object/dptconvert.h index 7a34d8b7..2e3addd1 100644 --- a/src/knx/group_object/dptconvert.h +++ b/src/knx/group_object/dptconvert.h @@ -33,117 +33,121 @@ #include -/** - * Converts the KNX Payload given by the specific DPT and puts the value in the KNXValue struc - */ -int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -/** - * Converts the KNXValue struct to the KNX Payload as the specific DPT - */ -int KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); +namespace Knx +{ + /** + * Converts the KNX Payload given by the specific DPT and puts the value in the KNXValue struc + */ + int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -//KNX to internal -int busValueToBinary(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToBinaryControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToStepControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToCharacter(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToUnsigned8(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToSigned8(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToStatusAndMode(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToUnsigned16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToTimePeriod(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToSigned16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToTimeDelta(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToFloat16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToTime(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToDate(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToUnsigned32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToSigned32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToLongTimePeriod(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToFloat32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToAccess(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToString(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToScene(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToSceneControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToSceneInfo(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToSceneConfig(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToDateTime(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToUnicode(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToSigned64(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToAlarmInfo(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToSerialNumber(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToVersion(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToTariff(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToLocale(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToRGB(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToRGBW(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToFlaggedScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -int busValueToActiveEnergy(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + /** + * Converts the KNXValue struct to the KNX Payload as the specific DPT + */ + int KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -//Internal to KNX -int valueToBusValueBinary(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueBinaryControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueStepControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueCharacter(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueUnsigned8(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueSigned8(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueStatusAndMode(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueUnsigned16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueTimePeriod(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueSigned16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueTimeDelta(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueFloat16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueTime(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueDate(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueUnsigned32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueSigned32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueLongTimePeriod(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueFloat32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueAccess(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueString(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueScene(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueSceneControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueSceneInfo(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueSceneConfig(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueDateTime(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueUnicode(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueSigned64(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueAlarmInfo(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueSerialNumber(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueVersion(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueTariff(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueLocale(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueRGB(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueRGBW(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueFlaggedScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -int valueToBusValueActiveEnergy(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + //KNX to internal + int busValueToBinary(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToBinaryControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToStepControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToCharacter(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToUnsigned8(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToSigned8(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToStatusAndMode(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToUnsigned16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToTimePeriod(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToSigned16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToTimeDelta(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToFloat16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToTime(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToDate(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToUnsigned32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToSigned32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToLongTimePeriod(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToFloat32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToAccess(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToString(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToScene(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToSceneControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToSceneInfo(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToSceneConfig(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToDateTime(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToUnicode(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToSigned64(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToAlarmInfo(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToSerialNumber(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToVersion(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToTariff(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToLocale(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToRGB(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToRGBW(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToFlaggedScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); + int busValueToActiveEnergy(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); -//Payload manipulation -bool bitFromPayload(const uint8_t* payload, int index); -uint8_t unsigned8FromPayload(const uint8_t* payload, int index); -int8_t signed8FromPayload(const uint8_t* payload, int index); -uint16_t unsigned16FromPayload(const uint8_t* payload, int index); -int16_t signed16FromPayload(const uint8_t* payload, int index); -uint32_t unsigned32FromPayload(const uint8_t* payload, int index); -int32_t signed32FromPayload(const uint8_t* payload, int index); -uint64_t unsigned64FromPayload(const uint8_t* payload, int index); -double float16FromPayload(const uint8_t* payload, int index); -float float32FromPayload(const uint8_t* payload, int index); -double float64FromPayload(const uint8_t* payload, int index); -int64_t signed64FromPayload(const uint8_t* payload, int index); -uint8_t bcdFromPayload(const uint8_t* payload, int index); + //Internal to KNX + int valueToBusValueBinary(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueBinaryControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueStepControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueCharacter(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueUnsigned8(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueSigned8(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueStatusAndMode(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueUnsigned16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueTimePeriod(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueSigned16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueTimeDelta(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueFloat16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueTime(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueDate(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueUnsigned32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueSigned32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueLongTimePeriod(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueFloat32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueAccess(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueString(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueScene(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueSceneControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueSceneInfo(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueSceneConfig(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueDateTime(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueUnicode(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueSigned64(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueAlarmInfo(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueSerialNumber(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueVersion(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueTariff(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueLocale(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueRGB(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueRGBW(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueFlaggedScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); + int valueToBusValueActiveEnergy(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); -void bitToPayload(uint8_t* payload, size_t payload_length, int index, bool value); -void unsigned8ToPayload(uint8_t* payload, size_t payload_length, int index, uint8_t value, uint8_t mask); //mask 0xFF -void signed8ToPayload(uint8_t* payload, size_t payload_length, int index, int8_t value, uint8_t mask); //mask 0xFF -void unsigned16ToPayload(uint8_t* payload, size_t payload_length, int index, uint16_t value, uint16_t mask); //mask 0xFFFF -void signed16ToPayload(uint8_t* payload, size_t payload_length, int index, int16_t value, uint16_t mask); //mask 0xFFFF -void unsigned32ToPayload(uint8_t* payload, size_t payload_length, int index, uint32_t value, uint32_t mask); //mask = 0xFFFFFFFF -void signed32ToPayload(uint8_t* payload, size_t payload_length, int index, int32_t value, uint32_t mask); //mask = 0xFFFFFFFF -void float16ToPayload(uint8_t* payload, size_t payload_length, int index, double value, uint16_t mask); //mask = 0xFFFF -void float32ToPayload(uint8_t* payload, size_t payload_length, int index, double value, uint32_t mask); //mask = 0xFFFFFFFF -void signed64ToPayload(uint8_t* payload, size_t payload_length, int index, int64_t value, uint64_t mask); //mask = UINT64_C(0xFFFFFFFFFFFFFFFF) -void bcdToPayload(uint8_t* payload, size_t payload_length, int index, uint8_t value); + //Payload manipulation + bool bitFromPayload(const uint8_t* payload, int index); + uint8_t unsigned8FromPayload(const uint8_t* payload, int index); + int8_t signed8FromPayload(const uint8_t* payload, int index); + uint16_t unsigned16FromPayload(const uint8_t* payload, int index); + int16_t signed16FromPayload(const uint8_t* payload, int index); + uint32_t unsigned32FromPayload(const uint8_t* payload, int index); + int32_t signed32FromPayload(const uint8_t* payload, int index); + uint64_t unsigned64FromPayload(const uint8_t* payload, int index); + double float16FromPayload(const uint8_t* payload, int index); + float float32FromPayload(const uint8_t* payload, int index); + double float64FromPayload(const uint8_t* payload, int index); + int64_t signed64FromPayload(const uint8_t* payload, int index); + uint8_t bcdFromPayload(const uint8_t* payload, int index); + + void bitToPayload(uint8_t* payload, size_t payload_length, int index, bool value); + void unsigned8ToPayload(uint8_t* payload, size_t payload_length, int index, uint8_t value, uint8_t mask); //mask 0xFF + void signed8ToPayload(uint8_t* payload, size_t payload_length, int index, int8_t value, uint8_t mask); //mask 0xFF + void unsigned16ToPayload(uint8_t* payload, size_t payload_length, int index, uint16_t value, uint16_t mask); //mask 0xFFFF + void signed16ToPayload(uint8_t* payload, size_t payload_length, int index, int16_t value, uint16_t mask); //mask 0xFFFF + void unsigned32ToPayload(uint8_t* payload, size_t payload_length, int index, uint32_t value, uint32_t mask); //mask = 0xFFFFFFFF + void signed32ToPayload(uint8_t* payload, size_t payload_length, int index, int32_t value, uint32_t mask); //mask = 0xFFFFFFFF + void float16ToPayload(uint8_t* payload, size_t payload_length, int index, double value, uint16_t mask); //mask = 0xFFFF + void float32ToPayload(uint8_t* payload, size_t payload_length, int index, double value, uint32_t mask); //mask = 0xFFFFFFFF + void signed64ToPayload(uint8_t* payload, size_t payload_length, int index, int64_t value, uint64_t mask); //mask = UINT64_C(0xFFFFFFFFFFFFFFFF) + void bcdToPayload(uint8_t* payload, size_t payload_length, int index, uint8_t value); +} \ No newline at end of file diff --git a/src/knx/group_object/group_object.cpp b/src/knx/group_object/group_object.cpp index 05dc9c6d..35254c50 100644 --- a/src/knx/group_object/group_object.cpp +++ b/src/knx/group_object/group_object.cpp @@ -6,6 +6,9 @@ #include + +namespace Knx +{ #ifdef SMALL_GROUPOBJECT GroupObjectUpdatedHandler GroupObject::_updateHandlerStatic = 0; #endif @@ -342,4 +345,5 @@ bool GroupObject::valueCompare(const KNXValue& value, const Dpt& type) } return false; +} } \ No newline at end of file diff --git a/src/knx/group_object/group_object.h b/src/knx/group_object/group_object.h index 1048008c..81bcde5c 100644 --- a/src/knx/group_object/group_object.h +++ b/src/knx/group_object/group_object.h @@ -6,275 +6,278 @@ #include #include -class GroupObjectTableObject; - -enum ComFlag : uint8_t -{ - Updated = 0, //!< Group object was updated - ReadRequest = 1, //!< Read was requested but was not processed - WriteRequest = 2, //!< Write was requested but was not processed - Transmitting = 3, //!< Group Object is processed a the moment (read or write) - Ok = 4, //!< read or write request were send successfully - Error = 5, //!< there was an error on processing a request - Uninitialized = 6 //!< uninitialized Group Object, its value is not valid -}; - -class GroupObject; - #ifndef HAS_FUNCTIONAL #if defined(__linux__) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_STM32) || defined (ARDUINO_ARCH_SAMD) || defined (ARDUINO_ARCH_RP2040) #define HAS_FUNCTIONAL 1 + #include #else #define HAS_FUNCTIONAL 0 #endif #endif +namespace Knx +{ + class GroupObject; + #if HAS_FUNCTIONAL - #include typedef std::function GroupObjectUpdatedHandler; #else typedef void (*GroupObjectUpdatedHandler)(GroupObject& go); #endif -/** - * This class represents a single group object. In german they are called "Kommunikationsobjekt" or "KO". - */ -class GroupObject -{ - friend class GroupObjectTableObject; + class GroupObjectTableObject; + + enum ComFlag : uint8_t + { + Updated = 0, //!< Group object was updated + ReadRequest = 1, //!< Read was requested but was not processed + WriteRequest = 2, //!< Write was requested but was not processed + Transmitting = 3, //!< Group Object is processed a the moment (read or write) + Ok = 4, //!< read or write request were send successfully + Error = 5, //!< there was an error on processing a request + Uninitialized = 6 //!< uninitialized Group Object, its value is not valid + }; + + /** + * This class represents a single group object. In german they are called "Kommunikationsobjekt" or "KO". + */ + class GroupObject + { + friend class GroupObjectTableObject; - public: - /** - * The constructor. - */ - GroupObject(); - /** - * The destructor. - */ - virtual ~GroupObject(); - // config flags from ETS - /** - * Check if the update flag (U) was set. (A-flag in german) - */ - bool responseUpdateEnable(); - /** - * Check if the transmit flag (T) was set. (UE-flag in german) - */ - bool transmitEnable(); - /** - * Check if the initialisation flag (I) was set. - */ - bool valueReadOnInit(); - /** - * Check if the write flag (W) was set. (S-flag in german) - */ - bool writeEnable(); - /** - * Check if the read flag (R) was set. (L-flag in german) - */ - bool readEnable(); - /** - * Check if the communication flag (C) was set. (K-flag in german) - */ - bool communicationEnable(); + public: + /** + * The constructor. + */ + GroupObject(); + /** + * The destructor. + */ + virtual ~GroupObject(); + // config flags from ETS + /** + * Check if the update flag (U) was set. (A-flag in german) + */ + bool responseUpdateEnable(); + /** + * Check if the transmit flag (T) was set. (UE-flag in german) + */ + bool transmitEnable(); + /** + * Check if the initialisation flag (I) was set. + */ + bool valueReadOnInit(); + /** + * Check if the write flag (W) was set. (S-flag in german) + */ + bool writeEnable(); + /** + * Check if the read flag (R) was set. (L-flag in german) + */ + bool readEnable(); + /** + * Check if the communication flag (C) was set. (K-flag in german) + */ + bool communicationEnable(); - /** - * Get the priority of the group object. - */ - Priority priority(); + /** + * Get the priority of the group object. + */ + Priority priority(); - /** - * Return the current state of the group object. See ::ComFlag - */ - ComFlag commFlag(); - /** - * Set the current state of the group object. Application code should only use this to set the state to ::Ok after - * reading a ::Updated to mark the changed group object as processed. This is optional. - */ - void commFlag(ComFlag value); + /** + * Return the current state of the group object. See ::ComFlag + */ + ComFlag commFlag(); + /** + * Set the current state of the group object. Application code should only use this to set the state to ::Ok after + * reading a ::Updated to mark the changed group object as processed. This is optional. + */ + void commFlag(ComFlag value); - /** - * Check if the group object contains a valid value assigned from bus or from application program - */ - bool initialized(); + /** + * Check if the group object contains a valid value assigned from bus or from application program + */ + bool initialized(); - /** - * Request the read of a communication object. Calling this function triggers the - * sending of a read-group-value telegram, to read the value of the communication - * object from the bus. - * - * When the answer is received, the communication object's value will be updated. - * - * This sets the state of the group objecte to ::ReadRequest - */ - void requestObjectRead(); - /** - * Mark a communication object as written. Calling this - * function triggers the sending of a write-group-value telegram. - * - * This sets the state of the group object to ::WriteRequest - */ - void objectWritten(); + /** + * Request the read of a communication object. Calling this function triggers the + * sending of a read-group-value telegram, to read the value of the communication + * object from the bus. + * + * When the answer is received, the communication object's value will be updated. + * + * This sets the state of the group objecte to ::ReadRequest + */ + void requestObjectRead(); + /** + * Mark a communication object as written. Calling this + * function triggers the sending of a write-group-value telegram. + * + * This sets the state of the group object to ::WriteRequest + */ + void objectWritten(); - /** - * returns the size of the group object in Byte. For Group objects with size smaller than 1 byte (for example Dpt 1) this method - * will return 1. - */ - size_t valueSize(); - /** - * returns the size of the group object in Byte as it is in a telegram. For Group objects with size smaller than 1 byte (for example Dpt 1) this method - * will return 0. - */ - size_t sizeInTelegram(); - /** - * returns the size of the group object in the heap memory of the group object. The function returns the same value as goSize(), - * exept fot the 14 byte string type to reserve one byte of a \0 terminator character. - */ - size_t sizeInMemory() const; - /** - * returns the pointer to the value of the group object. This can be used if a datapoint type is not supported or if you want do - * your own conversion. - */ - uint8_t* valueRef(); - /** - * returns the Application Service Access Point of the group object. In reality this is just the number of the group object. - * (in german "KO-Nr") - */ - uint16_t asap(); + /** + * returns the size of the group object in Byte. For Group objects with size smaller than 1 byte (for example Dpt 1) this method + * will return 1. + */ + size_t valueSize(); + /** + * returns the size of the group object in Byte as it is in a telegram. For Group objects with size smaller than 1 byte (for example Dpt 1) this method + * will return 0. + */ + size_t sizeInTelegram(); + /** + * returns the size of the group object in the heap memory of the group object. The function returns the same value as goSize(), + * exept fot the 14 byte string type to reserve one byte of a \0 terminator character. + */ + size_t sizeInMemory() const; + /** + * returns the pointer to the value of the group object. This can be used if a datapoint type is not supported or if you want do + * your own conversion. + */ + uint8_t* valueRef(); + /** + * returns the Application Service Access Point of the group object. In reality this is just the number of the group object. + * (in german "KO-Nr") + */ + uint16_t asap(); #ifndef SMALL_GROUPOBJECT - /** - * register a callback for this group object. The registered callback will be called if the group object was changed from the bus. - */ - void callback(GroupObjectUpdatedHandler handler); - /** - * returns the registered callback - */ - GroupObjectUpdatedHandler callback(); + /** + * register a callback for this group object. The registered callback will be called if the group object was changed from the bus. + */ + void callback(GroupObjectUpdatedHandler handler); + /** + * returns the registered callback + */ + GroupObjectUpdatedHandler callback(); #endif - /** - * return the current value of the group object. - * @param type the datapoint type used for the conversion. If this doesn't fit to the group object the returned value is invalid. - */ - KNXValue value(const Dpt& type); - /** - * set the current value of the group object and changes the state of the group object to ::WriteRequest. - * @param value the value the group object is set to - * @param type the datapoint type used for the conversion. - * - * The parameters must fit the group object. Otherwise it will stay unchanged. - */ - void value(const KNXValue& value, const Dpt& type); + /** + * return the current value of the group object. + * @param type the datapoint type used for the conversion. If this doesn't fit to the group object the returned value is invalid. + */ + KNXValue value(const Dpt& type); + /** + * set the current value of the group object and changes the state of the group object to ::WriteRequest. + * @param value the value the group object is set to + * @param type the datapoint type used for the conversion. + * + * The parameters must fit the group object. Otherwise it will stay unchanged. + */ + void value(const KNXValue& value, const Dpt& type); - /** - * Check if the value (after conversion to dpt) will differ from current value of the group object and changes the state of the group object to ::WriteRequest if different. - * Use this method only, when the value should not be sent if it was not changed, otherwise value(const KNXValue&, const Dpt&) will do the same (without overhead for comparing) - * @param value the value the group object is set to - * @param type the datapoint type used for the conversion. - * - * The parameters must fit the group object. Otherwise it will stay unchanged. - * - * @returns true if the value of the group object has changed - */ - bool valueCompare(const KNXValue& value, const Dpt& type); + /** + * Check if the value (after conversion to dpt) will differ from current value of the group object and changes the state of the group object to ::WriteRequest if different. + * Use this method only, when the value should not be sent if it was not changed, otherwise value(const KNXValue&, const Dpt&) will do the same (without overhead for comparing) + * @param value the value the group object is set to + * @param type the datapoint type used for the conversion. + * + * The parameters must fit the group object. Otherwise it will stay unchanged. + * + * @returns true if the value of the group object has changed + */ + bool valueCompare(const KNXValue& value, const Dpt& type); - /** - * set the current value of the group object. - * @param value the value the group object is set to - * @param type the datapoint type used for the conversion. - * - * The parameters must fit the group object. Otherwise it will stay unchanged. - */ - void valueNoSend(const KNXValue& value, const Dpt& type); + /** + * set the current value of the group object. + * @param value the value the group object is set to + * @param type the datapoint type used for the conversion. + * + * The parameters must fit the group object. Otherwise it will stay unchanged. + */ + void valueNoSend(const KNXValue& value, const Dpt& type); - /** - * Check if the value (after conversion to dpt) will differ from current value of the group object and update if necessary. - * Use this method only, when the value change is relevant, otherwise valueNoSend(const KNXValue&, const Dpt&) will do the same (without overhead for comparing) - * @param value the value the group object is set to - * @param type the datapoint type used for the conversion. - * - * The parameters must fit the group object. Otherwise it will stay unchanged. - * - * @returns true if the value of the group object has changed - */ - bool valueNoSendCompare(const KNXValue& value, const Dpt& type); + /** + * Check if the value (after conversion to dpt) will differ from current value of the group object and update if necessary. + * Use this method only, when the value change is relevant, otherwise valueNoSend(const KNXValue&, const Dpt&) will do the same (without overhead for comparing) + * @param value the value the group object is set to + * @param type the datapoint type used for the conversion. + * + * The parameters must fit the group object. Otherwise it will stay unchanged. + * + * @returns true if the value of the group object has changed + */ + bool valueNoSendCompare(const KNXValue& value, const Dpt& type); - /** - * set the current value of the group object. - * @param value the value the group object is set to - * @param type the datapoint type used for the conversion. - * - * The parameters must fit the group object. Otherwise it will stay unchanged. - * - * @returns true if the value of the group object was changed successfully. - */ - bool tryValue(KNXValue& value, const Dpt& type); + /** + * set the current value of the group object. + * @param value the value the group object is set to + * @param type the datapoint type used for the conversion. + * + * The parameters must fit the group object. Otherwise it will stay unchanged. + * + * @returns true if the value of the group object was changed successfully. + */ + bool tryValue(KNXValue& value, const Dpt& type); #ifndef SMALL_GROUPOBJECT - /** - * return the current value of the group object. The datapoint type must be set with dataPointType(). Otherwise the returned - * value is invalid. - */ - KNXValue value(); - /** - * set the current value of the group object and changes the state of the group object to ::WriteRequest. - * @param value the value the group object is set to - * - * The parameters must fit the group object and dhe datapoint type must be set with dataPointType(). Otherwise it will stay unchanged. - */ - void value(const KNXValue& value); - /** - * set the current value of the group object. - * @param value the value the group object is set to - * - * The parameters must fit the group object and dhe datapoint type must be set with dataPointType(). Otherwise it will stay unchanged. - */ - void valueNoSend(const KNXValue& value); - /** - * set the current value of the group object. - * @param value the value the group object is set to - * - * The parameters must fit the group object and dhe datapoint type must be set with dataPointType(). Otherwise it will stay unchanged. - * - * @returns true if the value of the group object was changed successfully. - */ - bool tryValue(KNXValue& value); + /** + * return the current value of the group object. The datapoint type must be set with dataPointType(). Otherwise the returned + * value is invalid. + */ + KNXValue value(); + /** + * set the current value of the group object and changes the state of the group object to ::WriteRequest. + * @param value the value the group object is set to + * + * The parameters must fit the group object and dhe datapoint type must be set with dataPointType(). Otherwise it will stay unchanged. + */ + void value(const KNXValue& value); + /** + * set the current value of the group object. + * @param value the value the group object is set to + * + * The parameters must fit the group object and dhe datapoint type must be set with dataPointType(). Otherwise it will stay unchanged. + */ + void valueNoSend(const KNXValue& value); + /** + * set the current value of the group object. + * @param value the value the group object is set to + * + * The parameters must fit the group object and dhe datapoint type must be set with dataPointType(). Otherwise it will stay unchanged. + * + * @returns true if the value of the group object was changed successfully. + */ + bool tryValue(KNXValue& value); - /** - * returns the currently configured datapoint type. - */ - Dpt dataPointType(); - /** - * sets the datapoint type of the group object. - */ - void dataPointType(Dpt value); + /** + * returns the currently configured datapoint type. + */ + Dpt dataPointType(); + /** + * sets the datapoint type of the group object. + */ + void dataPointType(Dpt value); #else - /** - * Alternative callback processing: register one global callback for all group object. - * The registered callback will be called if any group object was changed from the bus. - * The callback method has to dispatch to the correct handler for this group object. - */ - static GroupObjectUpdatedHandler classCallback(); - static void classCallback(GroupObjectUpdatedHandler handler); - static void processClassCallback(GroupObject& ko); + /** + * Alternative callback processing: register one global callback for all group object. + * The registered callback will be called if any group object was changed from the bus. + * The callback method has to dispatch to the correct handler for this group object. + */ + static GroupObjectUpdatedHandler classCallback(); + static void classCallback(GroupObjectUpdatedHandler handler); + static void processClassCallback(GroupObject& ko); #endif - private: - // class members - static GroupObjectTableObject* _table; + private: + // class members + static GroupObjectTableObject* _table; #ifdef SMALL_GROUPOBJECT - static GroupObjectUpdatedHandler _updateHandlerStatic; + static GroupObjectUpdatedHandler _updateHandlerStatic; #endif - size_t asapValueSize(uint8_t code) const; - size_t goSize(); - uint16_t _asap = 0; - bool _uninitialized : 1; - ComFlag _commFlag : 7; - uint8_t* _data = 0; - uint8_t _dataLength = 0; + size_t asapValueSize(uint8_t code) const; + size_t goSize(); + uint16_t _asap = 0; + bool _uninitialized : 1; + ComFlag _commFlag : 7; + uint8_t* _data = 0; + uint8_t _dataLength = 0; #ifndef SMALL_GROUPOBJECT - GroupObjectUpdatedHandler _updateHandler; - Dpt _datapointType; + GroupObjectUpdatedHandler _updateHandler; + Dpt _datapointType; #endif -}; + }; +} \ No newline at end of file diff --git a/src/knx/group_object/knx_value.cpp b/src/knx/group_object/knx_value.cpp index b671d119..76f105af 100644 --- a/src/knx/group_object/knx_value.cpp +++ b/src/knx/group_object/knx_value.cpp @@ -4,622 +4,625 @@ #include #include -KNXValue::KNXValue(bool value) +namespace Knx { - _value.boolValue = value; - _type = BoolType; -} - -KNXValue::KNXValue(uint8_t value) -{ - _value.ucharValue = value; - _type = UCharType; -} - -KNXValue::KNXValue(uint16_t value) -{ - _value.ushortValue = value; - _type = UShortType; -} + KNXValue::KNXValue(bool value) + { + _value.boolValue = value; + _type = BoolType; + } -KNXValue::KNXValue(uint32_t value) -{ - _value.uintValue = value; - _type = UIntType; -} + KNXValue::KNXValue(uint8_t value) + { + _value.ucharValue = value; + _type = UCharType; + } -KNXValue::KNXValue(uint64_t value) -{ - _value.ulongValue = value; - _type = ULongType; -} + KNXValue::KNXValue(uint16_t value) + { + _value.ushortValue = value; + _type = UShortType; + } -KNXValue::KNXValue(int8_t value) -{ - _value.charValue = value; - _type = CharType; -} + KNXValue::KNXValue(uint32_t value) + { + _value.uintValue = value; + _type = UIntType; + } -KNXValue::KNXValue(int16_t value) -{ - _value.shortValue = value; - _type = ShortType; -} + KNXValue::KNXValue(uint64_t value) + { + _value.ulongValue = value; + _type = ULongType; + } -KNXValue::KNXValue(int32_t value) -{ - _value.intValue = value; - _type = IntType; -} + KNXValue::KNXValue(int8_t value) + { + _value.charValue = value; + _type = CharType; + } -KNXValue::KNXValue(int64_t value) -{ - _value.longValue = value; - _type = LongType; -} + KNXValue::KNXValue(int16_t value) + { + _value.shortValue = value; + _type = ShortType; + } -KNXValue::KNXValue(double value) -{ - _value.doubleValue = value; - _type = DoubleType; -} + KNXValue::KNXValue(int32_t value) + { + _value.intValue = value; + _type = IntType; + } -KNXValue::KNXValue(const char* value) -{ - _value.stringValue = value; - _type = StringType; -} + KNXValue::KNXValue(int64_t value) + { + _value.longValue = value; + _type = LongType; + } -KNXValue::KNXValue(struct tm value) -{ - _value.timeValue = value; - _type = TimeType; -} + KNXValue::KNXValue(double value) + { + _value.doubleValue = value; + _type = DoubleType; + } -KNXValue::operator bool() const -{ - return boolValue(); -} + KNXValue::KNXValue(const char* value) + { + _value.stringValue = value; + _type = StringType; + } -KNXValue::operator uint8_t() const -{ - return ucharValue(); -} + KNXValue::KNXValue(struct tm value) + { + _value.timeValue = value; + _type = TimeType; + } -KNXValue::operator uint16_t() const -{ - return ushortValue(); -} + KNXValue::operator bool() const + { + return boolValue(); + } -KNXValue::operator uint32_t() const -{ - return uintValue(); -} + KNXValue::operator uint8_t() const + { + return ucharValue(); + } -KNXValue::operator uint64_t() const -{ - return ulongValue(); -} + KNXValue::operator uint16_t() const + { + return ushortValue(); + } -KNXValue::operator int8_t() const -{ - return charValue(); -} + KNXValue::operator uint32_t() const + { + return uintValue(); + } -KNXValue::operator int16_t() const -{ - return shortValue(); -} + KNXValue::operator uint64_t() const + { + return ulongValue(); + } -KNXValue::operator int32_t() const -{ - return intValue(); -} + KNXValue::operator int8_t() const + { + return charValue(); + } -KNXValue::operator int64_t() const -{ - return longValue(); -} + KNXValue::operator int16_t() const + { + return shortValue(); + } -KNXValue::operator double() const -{ - return doubleValue(); -} + KNXValue::operator int32_t() const + { + return intValue(); + } -KNXValue::operator const char* () const -{ - return stringValue(); -} + KNXValue::operator int64_t() const + { + return longValue(); + } -KNXValue::operator struct tm() const -{ - return timeValue(); -} + KNXValue::operator double() const + { + return doubleValue(); + } -KNXValue& KNXValue::operator=(const bool value) -{ - _value.boolValue = value; - _type = BoolType; - return *this; -} + KNXValue::operator const char* () const + { + return stringValue(); + } -KNXValue& KNXValue::operator=(const uint8_t value) -{ - _value.ucharValue = value; - _type = UCharType; - return *this; -} + KNXValue::operator struct tm() const + { + return timeValue(); + } -KNXValue& KNXValue::operator=(const uint16_t value) -{ - _value.ushortValue = value; - _type = UShortType; - return *this; -} + KNXValue& KNXValue::operator=(const bool value) + { + _value.boolValue = value; + _type = BoolType; + return *this; + } -KNXValue& KNXValue::operator=(const uint32_t value) -{ - _value.uintValue = value; - _type = UIntType; - return *this; -} + KNXValue& KNXValue::operator=(const uint8_t value) + { + _value.ucharValue = value; + _type = UCharType; + return *this; + } -KNXValue& KNXValue::operator=(const uint64_t value) -{ - _value.ulongValue = value; - _type = ULongType; - return *this; -} + KNXValue& KNXValue::operator=(const uint16_t value) + { + _value.ushortValue = value; + _type = UShortType; + return *this; + } -KNXValue& KNXValue::operator=(const int8_t value) -{ - _value.charValue = value; - _type = CharType; - return *this; -} + KNXValue& KNXValue::operator=(const uint32_t value) + { + _value.uintValue = value; + _type = UIntType; + return *this; + } -KNXValue& KNXValue::operator=(const int16_t value) -{ - _value.shortValue = value; - _type = ShortType; - return *this; -} + KNXValue& KNXValue::operator=(const uint64_t value) + { + _value.ulongValue = value; + _type = ULongType; + return *this; + } -KNXValue& KNXValue::operator=(const int32_t value) -{ - _value.intValue = value; - _type = IntType; - return *this; -} + KNXValue& KNXValue::operator=(const int8_t value) + { + _value.charValue = value; + _type = CharType; + return *this; + } -KNXValue& KNXValue::operator=(const int64_t value) -{ - _value.longValue = value; - _type = LongType; - return *this; -} + KNXValue& KNXValue::operator=(const int16_t value) + { + _value.shortValue = value; + _type = ShortType; + return *this; + } -KNXValue& KNXValue::operator=(const double value) -{ - _value.doubleValue = value; - _type = DoubleType; - return *this; -} + KNXValue& KNXValue::operator=(const int32_t value) + { + _value.intValue = value; + _type = IntType; + return *this; + } -KNXValue& KNXValue::operator=(const char* value) -{ - _value.stringValue = value; - _type = StringType; - return *this; -} + KNXValue& KNXValue::operator=(const int64_t value) + { + _value.longValue = value; + _type = LongType; + return *this; + } -KNXValue& KNXValue::operator=(const struct tm value) -{ - _value.timeValue = value; - _type = TimeType; - return *this; -} + KNXValue& KNXValue::operator=(const double value) + { + _value.doubleValue = value; + _type = DoubleType; + return *this; + } -bool KNXValue::boolValue() const -{ - switch (_type) + KNXValue& KNXValue::operator=(const char* value) { - case BoolType: - return _value.boolValue; + _value.stringValue = value; + _type = StringType; + return *this; + } - case UCharType: - case UShortType: - case UIntType: - case ULongType: - case CharType: - case ShortType: - case IntType: - case LongType: - case TimeType: - return longValue() != 0; + KNXValue& KNXValue::operator=(const struct tm value) + { + _value.timeValue = value; + _type = TimeType; + return *this; + } - case DoubleType: - return _value.doubleValue != 0; + bool KNXValue::boolValue() const + { + switch (_type) + { + case BoolType: + return _value.boolValue; + + case UCharType: + case UShortType: + case UIntType: + case ULongType: + case CharType: + case ShortType: + case IntType: + case LongType: + case TimeType: + return longValue() != 0; + + case DoubleType: + return _value.doubleValue != 0; + + case StringType: + return strcmp(_value.stringValue, "true") == 0 || strcmp(_value.stringValue, "True") == 0 || longValue() != 0 || doubleValue() != 0; + } - case StringType: - return strcmp(_value.stringValue, "true") == 0 || strcmp(_value.stringValue, "True") == 0 || longValue() != 0 || doubleValue() != 0; + return 0; } - return 0; -} - -uint8_t KNXValue::ucharValue() const -{ - switch (_type) + uint8_t KNXValue::ucharValue() const { - case UCharType: - return _value.ucharValue; - - case BoolType: - case UShortType: - case UIntType: - case ULongType: - case TimeType: - return (uint8_t)ulongValue(); + switch (_type) + { + case UCharType: + return _value.ucharValue; + + case BoolType: + case UShortType: + case UIntType: + case ULongType: + case TimeType: + return (uint8_t)ulongValue(); + + case CharType: + case ShortType: + case IntType: + case LongType: + case DoubleType: + case StringType: + return (uint8_t)longValue(); + } - case CharType: - case ShortType: - case IntType: - case LongType: - case DoubleType: - case StringType: - return (uint8_t)longValue(); + return 0; } - return 0; -} - -uint16_t KNXValue::ushortValue() const -{ - switch (_type) + uint16_t KNXValue::ushortValue() const { - case UShortType: - return _value.ushortValue; - - case BoolType: - case UCharType: - case UIntType: - case ULongType: - case TimeType: - return (uint16_t)ulongValue(); + switch (_type) + { + case UShortType: + return _value.ushortValue; + + case BoolType: + case UCharType: + case UIntType: + case ULongType: + case TimeType: + return (uint16_t)ulongValue(); + + case CharType: + case ShortType: + case IntType: + case LongType: + case DoubleType: + case StringType: + return (uint16_t)longValue(); + } - case CharType: - case ShortType: - case IntType: - case LongType: - case DoubleType: - case StringType: - return (uint16_t)longValue(); + return 0; } - return 0; -} - -uint32_t KNXValue::uintValue() const -{ - switch (_type) + uint32_t KNXValue::uintValue() const { - case UIntType: - return _value.uintValue; - - case BoolType: - case UCharType: - case UShortType: - case ULongType: - case TimeType: - return (uint32_t)ulongValue(); + switch (_type) + { + case UIntType: + return _value.uintValue; + + case BoolType: + case UCharType: + case UShortType: + case ULongType: + case TimeType: + return (uint32_t)ulongValue(); + + case CharType: + case ShortType: + case IntType: + case LongType: + case DoubleType: + case StringType: + return (uint32_t)longValue(); + } - case CharType: - case ShortType: - case IntType: - case LongType: - case DoubleType: - case StringType: - return (uint32_t)longValue(); + return 0; } - return 0; -} - -uint64_t KNXValue::ulongValue() const -{ - switch (_type) + uint64_t KNXValue::ulongValue() const { - case ULongType: - return _value.ulongValue; + switch (_type) + { + case ULongType: + return _value.ulongValue; - case BoolType: - return _value.boolValue ? 1 : 0; + case BoolType: + return _value.boolValue ? 1 : 0; - case UCharType: - return (uint64_t)_value.ucharValue; + case UCharType: + return (uint64_t)_value.ucharValue; - case UShortType: - return (uint64_t)_value.ushortValue; + case UShortType: + return (uint64_t)_value.ushortValue; - case UIntType: - return (uint64_t)_value.uintValue; + case UIntType: + return (uint64_t)_value.uintValue; - case TimeType: - { - struct tm* timeptr = const_cast(&_value.timeValue); - return (uint64_t)mktime(timeptr); - } + case TimeType: + { + struct tm* timeptr = const_cast(&_value.timeValue); + return (uint64_t)mktime(timeptr); + } - case CharType: - return (uint64_t)_value.charValue; + case CharType: + return (uint64_t)_value.charValue; - case ShortType: - return (uint64_t)_value.shortValue; + case ShortType: + return (uint64_t)_value.shortValue; - case IntType: - return (uint64_t)_value.intValue; + case IntType: + return (uint64_t)_value.intValue; - case LongType: - return (uint64_t)_value.longValue; + case LongType: + return (uint64_t)_value.longValue; - case DoubleType: - return (uint64_t)_value.doubleValue; + case DoubleType: + return (uint64_t)_value.doubleValue; - case StringType: + case StringType: #ifndef KNX_NO_STRTOx_CONVERSION - return (uint64_t)strtoul(_value.stringValue, NULL, 0); + return (uint64_t)strtoul(_value.stringValue, NULL, 0); #else - return 0; + return 0; #endif - } + } - return 0; -} + return 0; + } -int8_t KNXValue::charValue() const -{ - switch (_type) + int8_t KNXValue::charValue() const { - case CharType: - return _value.charValue; - - case BoolType: - case UCharType: - case UShortType: - case UIntType: - case ULongType: - case TimeType: - return (int8_t)ulongValue(); + switch (_type) + { + case CharType: + return _value.charValue; + + case BoolType: + case UCharType: + case UShortType: + case UIntType: + case ULongType: + case TimeType: + return (int8_t)ulongValue(); + + case ShortType: + case IntType: + case LongType: + case DoubleType: + case StringType: + return (int8_t)longValue(); + } - case ShortType: - case IntType: - case LongType: - case DoubleType: - case StringType: - return (int8_t)longValue(); + return 0; } - return 0; -} - -int16_t KNXValue::shortValue() const -{ - switch (_type) + int16_t KNXValue::shortValue() const { - case ShortType: - return _value.shortValue; - - case BoolType: - case UCharType: - case UShortType: - case UIntType: - case ULongType: - case TimeType: - return (int16_t)ulongValue(); + switch (_type) + { + case ShortType: + return _value.shortValue; + + case BoolType: + case UCharType: + case UShortType: + case UIntType: + case ULongType: + case TimeType: + return (int16_t)ulongValue(); + + case CharType: + case IntType: + case LongType: + case DoubleType: + case StringType: + return (int16_t)longValue(); + } - case CharType: - case IntType: - case LongType: - case DoubleType: - case StringType: - return (int16_t)longValue(); + return 0; } - return 0; -} - -int32_t KNXValue::intValue() const -{ - switch (_type) + int32_t KNXValue::intValue() const { - case IntType: - return _value.ulongValue; - - case BoolType: - case UCharType: - case UShortType: - case UIntType: - case ULongType: - case TimeType: - return (int32_t)ulongValue(); + switch (_type) + { + case IntType: + return _value.ulongValue; + + case BoolType: + case UCharType: + case UShortType: + case UIntType: + case ULongType: + case TimeType: + return (int32_t)ulongValue(); + + case CharType: + case ShortType: + case LongType: + case DoubleType: + case StringType: + return (int32_t)longValue(); + } - case CharType: - case ShortType: - case LongType: - case DoubleType: - case StringType: - return (int32_t)longValue(); + return 0; } - return 0; -} - -int64_t KNXValue::longValue() const -{ - switch (_type) + int64_t KNXValue::longValue() const { - case LongType: - return _value.longValue; + switch (_type) + { + case LongType: + return _value.longValue; - case BoolType: - return _value.boolValue ? 1 : 0; + case BoolType: + return _value.boolValue ? 1 : 0; - case UCharType: - return (int64_t)_value.ucharValue; + case UCharType: + return (int64_t)_value.ucharValue; - case UShortType: - return (int64_t)_value.ushortValue; + case UShortType: + return (int64_t)_value.ushortValue; - case UIntType: - return (int64_t)_value.uintValue; + case UIntType: + return (int64_t)_value.uintValue; - case ULongType: - return (int64_t)_value.uintValue; + case ULongType: + return (int64_t)_value.uintValue; - case TimeType: - return (int64_t)ulongValue(); + case TimeType: + return (int64_t)ulongValue(); - case CharType: - return (int64_t)_value.charValue; + case CharType: + return (int64_t)_value.charValue; - case ShortType: - return (int64_t)_value.shortValue; + case ShortType: + return (int64_t)_value.shortValue; - case IntType: - return (int64_t)_value.intValue; + case IntType: + return (int64_t)_value.intValue; - case DoubleType: - return (int64_t)_value.doubleValue; + case DoubleType: + return (int64_t)_value.doubleValue; - case StringType: + case StringType: #ifndef KNX_NO_STRTOx_CONVERSION - return strtol(_value.stringValue, NULL, 0); + return strtol(_value.stringValue, NULL, 0); #else - return 0; + return 0; #endif - } + } - return 0; -} + return 0; + } -double KNXValue::doubleValue() const -{ - switch (_type) + double KNXValue::doubleValue() const { - case DoubleType: - return _value.doubleValue; + switch (_type) + { + case DoubleType: + return _value.doubleValue; - case BoolType: - return _value.boolValue ? 1 : 0; + case BoolType: + return _value.boolValue ? 1 : 0; - case UCharType: - return _value.ucharValue; + case UCharType: + return _value.ucharValue; - case UShortType: - return _value.ushortValue; + case UShortType: + return _value.ushortValue; - case UIntType: - return _value.uintValue; + case UIntType: + return _value.uintValue; - case ULongType: - return _value.uintValue; + case ULongType: + return _value.uintValue; - case TimeType: - return ulongValue(); + case TimeType: + return ulongValue(); - case CharType: - return _value.charValue; + case CharType: + return _value.charValue; - case ShortType: - return _value.shortValue; + case ShortType: + return _value.shortValue; - case IntType: - return _value.intValue; + case IntType: + return _value.intValue; - case LongType: - return _value.longValue; + case LongType: + return _value.longValue; - case StringType: + case StringType: #ifndef KNX_NO_STRTOx_CONVERSION - return strtod(_value.stringValue, NULL); + return strtod(_value.stringValue, NULL); #else - return 0; + return 0; #endif - } + } - return 0; -} + return 0; + } -const char* KNXValue::stringValue() const -{ - switch (_type) + const char* KNXValue::stringValue() const { - case DoubleType: - case BoolType: - case UCharType: - case UShortType: - case UIntType: - case ULongType: - case TimeType: - case CharType: - case ShortType: - case IntType: - case LongType: - return ""; // we would have to manage the memory for the string otherwise. Maybe later. + switch (_type) + { + case DoubleType: + case BoolType: + case UCharType: + case UShortType: + case UIntType: + case ULongType: + case TimeType: + case CharType: + case ShortType: + case IntType: + case LongType: + return ""; // we would have to manage the memory for the string otherwise. Maybe later. + + case StringType: + return _value.stringValue; + } - case StringType: - return _value.stringValue; + return 0; } - return 0; -} - -struct tm KNXValue::timeValue() const -{ - switch (_type) - { - case TimeType: - return _value.timeValue; - - case BoolType: - case UCharType: - case UShortType: - case UIntType: - case ULongType: - case CharType: - case ShortType: - case IntType: - case LongType: - case DoubleType: - case StringType: + struct tm KNXValue::timeValue() const + { + switch (_type) { - time_t timeVal = ulongValue(); - struct tm timeStruct; - gmtime_r(&timeVal, &timeStruct); - return timeStruct; + case TimeType: + return _value.timeValue; + + case BoolType: + case UCharType: + case UShortType: + case UIntType: + case ULongType: + case CharType: + case ShortType: + case IntType: + case LongType: + case DoubleType: + case StringType: + { + time_t timeVal = ulongValue(); + struct tm timeStruct; + gmtime_r(&timeVal, &timeStruct); + return timeStruct; + } } - } - struct tm tmp = {0}; + struct tm tmp = {0}; - return tmp; -} + return tmp; + } -KNXValue::KNXValue(float value) -{ - _value.doubleValue = value; - _type = DoubleType; -} + KNXValue::KNXValue(float value) + { + _value.doubleValue = value; + _type = DoubleType; + } -KNXValue& KNXValue::operator=(const float value) -{ - _value.doubleValue = value; - _type = DoubleType; - return *this; -} + KNXValue& KNXValue::operator=(const float value) + { + _value.doubleValue = value; + _type = DoubleType; + return *this; + } -KNXValue::operator float() const -{ - return doubleValue(); + KNXValue::operator float() const + { + return doubleValue(); + } } \ No newline at end of file diff --git a/src/knx/group_object/knx_value.h b/src/knx/group_object/knx_value.h index 34435633..42a834b2 100644 --- a/src/knx/group_object/knx_value.h +++ b/src/knx/group_object/knx_value.h @@ -3,97 +3,100 @@ #include #include -class KNXValue +namespace Knx { - public: - KNXValue(bool value); - KNXValue(uint8_t value); - KNXValue(uint16_t value); - KNXValue(uint32_t value); - KNXValue(uint64_t value); - KNXValue(int8_t value); - KNXValue(int16_t value); - KNXValue(int32_t value); - KNXValue(int64_t value); - KNXValue(double value); - KNXValue(const char* value); - KNXValue(struct tm value); - KNXValue(float value); + class KNXValue + { + public: + KNXValue(bool value); + KNXValue(uint8_t value); + KNXValue(uint16_t value); + KNXValue(uint32_t value); + KNXValue(uint64_t value); + KNXValue(int8_t value); + KNXValue(int16_t value); + KNXValue(int32_t value); + KNXValue(int64_t value); + KNXValue(double value); + KNXValue(const char* value); + KNXValue(struct tm value); + KNXValue(float value); - operator bool() const; - operator uint8_t() const; - operator uint16_t() const; - operator uint32_t() const; - operator uint64_t() const; - operator int8_t() const; - operator int16_t() const; - operator int32_t() const; - operator int64_t() const; - operator double() const; - operator const char* () const; - operator struct tm() const; - operator float() const; + operator bool() const; + operator uint8_t() const; + operator uint16_t() const; + operator uint32_t() const; + operator uint64_t() const; + operator int8_t() const; + operator int16_t() const; + operator int32_t() const; + operator int64_t() const; + operator double() const; + operator const char* () const; + operator struct tm() const; + operator float() const; - KNXValue& operator=(const bool value); - KNXValue& operator=(const uint8_t value); - KNXValue& operator=(const uint16_t value); - KNXValue& operator=(const uint32_t value); - KNXValue& operator=(const uint64_t value); - KNXValue& operator=(const int8_t value); - KNXValue& operator=(const int16_t value); - KNXValue& operator=(const int32_t value); - KNXValue& operator=(const int64_t value); - KNXValue& operator=(const double value); - KNXValue& operator=(const char* value); - KNXValue& operator=(const struct tm value); - KNXValue& operator=(const float value); + KNXValue& operator=(const bool value); + KNXValue& operator=(const uint8_t value); + KNXValue& operator=(const uint16_t value); + KNXValue& operator=(const uint32_t value); + KNXValue& operator=(const uint64_t value); + KNXValue& operator=(const int8_t value); + KNXValue& operator=(const int16_t value); + KNXValue& operator=(const int32_t value); + KNXValue& operator=(const int64_t value); + KNXValue& operator=(const double value); + KNXValue& operator=(const char* value); + KNXValue& operator=(const struct tm value); + KNXValue& operator=(const float value); - private: - bool boolValue() const; - uint8_t ucharValue() const; - uint16_t ushortValue() const; - uint32_t uintValue() const; - uint64_t ulongValue() const; - int8_t charValue() const; - int16_t shortValue() const; - int32_t intValue() const; - int64_t longValue() const; - double doubleValue() const; - const char* stringValue() const; - struct tm timeValue() const; + private: + bool boolValue() const; + uint8_t ucharValue() const; + uint16_t ushortValue() const; + uint32_t uintValue() const; + uint64_t ulongValue() const; + int8_t charValue() const; + int16_t shortValue() const; + int32_t intValue() const; + int64_t longValue() const; + double doubleValue() const; + const char* stringValue() const; + struct tm timeValue() const; - union Value - { - bool boolValue; - uint8_t ucharValue; - uint16_t ushortValue; - uint32_t uintValue; - uint64_t ulongValue; - int8_t charValue; - int16_t shortValue; - int32_t intValue; - int64_t longValue; - double doubleValue; - const char* stringValue; - struct tm timeValue; - }; - enum ValueType - { - BoolType, - UCharType, - UShortType, - UIntType, - ULongType, - CharType, - ShortType, - IntType, - LongType, - DoubleType, - StringType, - TimeType, - }; + union Value + { + bool boolValue; + uint8_t ucharValue; + uint16_t ushortValue; + uint32_t uintValue; + uint64_t ulongValue; + int8_t charValue; + int16_t shortValue; + int32_t intValue; + int64_t longValue; + double doubleValue; + const char* stringValue; + struct tm timeValue; + }; + enum ValueType + { + BoolType, + UCharType, + UShortType, + UIntType, + ULongType, + CharType, + ShortType, + IntType, + LongType, + DoubleType, + StringType, + TimeType, + }; - ValueType _type; - Value _value; -}; \ No newline at end of file + ValueType _type; + Value _value; + }; +} \ No newline at end of file diff --git a/src/knx/interface_object/address_table_object.cpp b/src/knx/interface_object/address_table_object.cpp index 70348ad7..27dfb80c 100644 --- a/src/knx/interface_object/address_table_object.cpp +++ b/src/knx/interface_object/address_table_object.cpp @@ -7,94 +7,97 @@ #define LOGGER Logger::logger("AddressTableObject") -using namespace std; - -AddressTableObject::AddressTableObject(Memory& memory) - : TableObject(memory) +namespace Knx { - Property* properties[] = + using namespace std; + + AddressTableObject::AddressTableObject(Memory& memory) + : TableObject(memory) { - new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_ADDR_TABLE) - }; + Property* properties[] = + { + new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_ADDR_TABLE) + }; - TableObject::initializeProperties(sizeof(properties), properties); -} + TableObject::initializeProperties(sizeof(properties), properties); + } -uint16_t AddressTableObject::entryCount() -{ - // after programming without GA the module hangs - if (loadState() != LS_LOADED || _groupAddresses[0] == 0xFFFF) - return 0; + uint16_t AddressTableObject::entryCount() + { + // after programming without GA the module hangs + if (loadState() != LS_LOADED || _groupAddresses[0] == 0xFFFF) + return 0; - return ntohs(_groupAddresses[0]); -} + return ntohs(_groupAddresses[0]); + } -uint16_t AddressTableObject::getGroupAddress(uint16_t tsap) -{ - if (loadState() != LS_LOADED || tsap > entryCount() ) - return 0; + uint16_t AddressTableObject::getGroupAddress(uint16_t tsap) + { + if (loadState() != LS_LOADED || tsap > entryCount() ) + return 0; - return ntohs(_groupAddresses[tsap]); -} + return ntohs(_groupAddresses[tsap]); + } -uint16_t AddressTableObject::getTsap(uint16_t addr) -{ - uint16_t size = entryCount(); + uint16_t AddressTableObject::getTsap(uint16_t addr) + { + uint16_t size = entryCount(); #ifdef USE_BINSEARCH - uint16_t low, high, i; - low = 1; - high = size; + uint16_t low, high, i; + low = 1; + high = size; - while (low <= high) - { - i = (low + high) / 2; - uint16_t ga = ntohs(_groupAddresses[i]); + while (low <= high) + { + i = (low + high) / 2; + uint16_t ga = ntohs(_groupAddresses[i]); - if (ga == addr) - return i; + if (ga == addr) + return i; - if (addr < ga) - high = i - 1; - else - low = i + 1 ; - } + if (addr < ga) + high = i - 1; + else + low = i + 1 ; + } #else - for (uint16_t i = 1; i <= size; i++) - if (ntohs(_groupAddresses[i]) == addr) - return i; + for (uint16_t i = 1; i <= size; i++) + if (ntohs(_groupAddresses[i]) == addr) + return i; #endif - return 0; -} + return 0; + } -#pragma region SaveRestore + #pragma region SaveRestore -const uint8_t* AddressTableObject::restore(const uint8_t* buffer) -{ - buffer = TableObject::restore(buffer); + const uint8_t* AddressTableObject::restore(const uint8_t* buffer) + { + buffer = TableObject::restore(buffer); - _groupAddresses = (uint16_t*)data(); + _groupAddresses = (uint16_t*)data(); - return buffer; -} + return buffer; + } -#pragma endregion + #pragma endregion -bool AddressTableObject::contains(uint16_t addr) -{ - return (getTsap(addr) > 0); -} + bool AddressTableObject::contains(uint16_t addr) + { + return (getTsap(addr) > 0); + } -void AddressTableObject::beforeStateChange(LoadState& newState) -{ - LOGGER.info("beforeStateChange %s", enum_name(newState)); - TableObject::beforeStateChange(newState); + void AddressTableObject::beforeStateChange(LoadState& newState) + { + LOGGER.info("beforeStateChange %s", enum_name(newState)); + TableObject::beforeStateChange(newState); - if (newState != LS_LOADED) - return; + if (newState != LS_LOADED) + return; - _groupAddresses = (uint16_t*)data(); -} + _groupAddresses = (uint16_t*)data(); + } +} \ No newline at end of file diff --git a/src/knx/interface_object/address_table_object.h b/src/knx/interface_object/address_table_object.h index 0fd28908..6e33ffe2 100644 --- a/src/knx/interface_object/address_table_object.h +++ b/src/knx/interface_object/address_table_object.h @@ -1,57 +1,61 @@ #pragma once #include "table_object.h" -/** - * This class represents the group address table. It provides a mapping between transport layer - * service access points (TSAP) and group addresses. The TSAP can be imagined as an index to the array - * of group addresses. - * - * See section 4.10 of @cite knx:3/5/1 for further details. - * It implements realisation type 7 (see section 4.10.7 of @cite knx:3/5/1). - */ -class AddressTableObject : public TableObject + +namespace Knx { - public: - /** - * The constructor. - * - * @param memory This parameter is only passed to the constructor of TableObject and is not used by this class. - */ - AddressTableObject(Memory& memory); - const uint8_t* restore(const uint8_t* buffer) override; + /** + * This class represents the group address table. It provides a mapping between transport layer + * service access points (TSAP) and group addresses. The TSAP can be imagined as an index to the array + * of group addresses. + * + * See section 4.10 of @cite knx:3/5/1 for further details. + * It implements realisation type 7 (see section 4.10.7 of @cite knx:3/5/1). + */ + class AddressTableObject : public TableObject + { + public: + /** + * The constructor. + * + * @param memory This parameter is only passed to the constructor of TableObject and is not used by this class. + */ + AddressTableObject(Memory& memory); + const uint8_t* restore(const uint8_t* buffer) override; - /** - * returns the number of group addresses of the object. - */ - uint16_t entryCount(); - /** - * Get the group address mapped to a TSAP. - * - * @param tsap The TSAP of which to get the group address for. - * - * @return the groupAddress if found or zero if no group address was found. - */ - uint16_t getGroupAddress(uint16_t tsap); - /** - * Get the TSAP mapped to a group address. - * - * @param groupAddress the group address of which to get the TSAP for. - * - * @return the TSAP if found or zero if no tsap was found. - */ - uint16_t getTsap(uint16_t groupAddress); - /** - * Check if the address table contains a group address. - * - * @param groupAddress the group address to check - * - * @return true if the address table contains the group address, false otherwise - */ - bool contains(uint16_t groupAddress); + /** + * returns the number of group addresses of the object. + */ + uint16_t entryCount(); + /** + * Get the group address mapped to a TSAP. + * + * @param tsap The TSAP of which to get the group address for. + * + * @return the groupAddress if found or zero if no group address was found. + */ + uint16_t getGroupAddress(uint16_t tsap); + /** + * Get the TSAP mapped to a group address. + * + * @param groupAddress the group address of which to get the TSAP for. + * + * @return the TSAP if found or zero if no tsap was found. + */ + uint16_t getTsap(uint16_t groupAddress); + /** + * Check if the address table contains a group address. + * + * @param groupAddress the group address to check + * + * @return true if the address table contains the group address, false otherwise + */ + bool contains(uint16_t groupAddress); - protected: - void beforeStateChange(LoadState& newState) override; + protected: + void beforeStateChange(LoadState& newState) override; - private: - uint16_t* _groupAddresses = 0; -}; + private: + uint16_t* _groupAddresses = 0; + }; +} \ No newline at end of file diff --git a/src/knx/interface_object/application_program_object.cpp b/src/knx/interface_object/application_program_object.cpp index 82af9fb4..988c30ee 100644 --- a/src/knx/interface_object/application_program_object.cpp +++ b/src/knx/interface_object/application_program_object.cpp @@ -8,101 +8,104 @@ #define LOGGER Logger::logger("ApplicationProgramObject") -ApplicationProgramObject::ApplicationProgramObject(Memory& memory) +namespace Knx +{ + ApplicationProgramObject::ApplicationProgramObject(Memory& memory) #if MASK_VERSION == 0x091A - : TableObject(memory, 0x0100, 0x0100) + : TableObject(memory, 0x0100, 0x0100) #else - : TableObject(memory) + : TableObject(memory) #endif -{ - Property* properties[] = { - new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_APPLICATION_PROG), - new DataProperty(PID_PROG_VERSION, true, PDT_GENERIC_05, 1, ReadLv3 | WriteLv3), - new CallbackProperty(this, PID_PEI_TYPE, false, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv0, - [](ApplicationProgramObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { - if (start == 0) - { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); + Property* properties[] = + { + new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_APPLICATION_PROG), + new DataProperty(PID_PROG_VERSION, true, PDT_GENERIC_05, 1, ReadLv3 | WriteLv3), + new CallbackProperty(this, PID_PEI_TYPE, false, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv0, + [](ApplicationProgramObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { + if (start == 0) + { + uint16_t currentNoOfElements = 1; + pushWord(currentNoOfElements, data); + return 1; + } + + data[0] = 0; return 1; - } - - data[0] = 0; - return 1; - }) - }; - - TableObject::initializeProperties(sizeof(properties), properties); -} + }) + }; -uint8_t* ApplicationProgramObject::save(uint8_t* buffer) -{ - uint8_t programVersion[5]; - property(PID_PROG_VERSION)->read(programVersion); - buffer = pushByteArray(programVersion, 5, buffer); - - return TableObject::save(buffer); -} - -const uint8_t* ApplicationProgramObject::restore(const uint8_t* buffer) -{ - uint8_t programVersion[5]; - buffer = popByteArray(programVersion, 5, buffer); - property(PID_PROG_VERSION)->write(programVersion); + TableObject::initializeProperties(sizeof(properties), properties); + } - return TableObject::restore(buffer); -} + uint8_t* ApplicationProgramObject::save(uint8_t* buffer) + { + uint8_t programVersion[5]; + property(PID_PROG_VERSION)->read(programVersion); + buffer = pushByteArray(programVersion, 5, buffer); -uint16_t ApplicationProgramObject::saveSize() -{ - return TableObject::saveSize() + 5; // sizeof(programVersion) -} + return TableObject::save(buffer); + } -uint8_t* ApplicationProgramObject::data(uint32_t addr) -{ - return TableObject::data() + addr; -} + const uint8_t* ApplicationProgramObject::restore(const uint8_t* buffer) + { + uint8_t programVersion[5]; + buffer = popByteArray(programVersion, 5, buffer); + property(PID_PROG_VERSION)->write(programVersion); -uint8_t ApplicationProgramObject::getByte(uint32_t addr) -{ - return *(TableObject::data() + addr); -} + return TableObject::restore(buffer); + } -uint16_t ApplicationProgramObject::getWord(uint32_t addr) -{ - return ::getWord(TableObject::data() + addr); -} + uint16_t ApplicationProgramObject::saveSize() + { + return TableObject::saveSize() + 5; // sizeof(programVersion) + } -uint32_t ApplicationProgramObject::getInt(uint32_t addr) -{ - return ::getInt(TableObject::data() + addr); -} + uint8_t* ApplicationProgramObject::data(uint32_t addr) + { + return TableObject::data() + addr; + } -double ApplicationProgramObject::getFloat(uint32_t addr, ParameterFloatEncodings encoding) -{ - switch (encoding) + uint8_t ApplicationProgramObject::getByte(uint32_t addr) { - case Float_Enc_DPT9: - return float16FromPayload(TableObject::data() + addr, 0); - break; + return *(TableObject::data() + addr); + } - case Float_Enc_IEEE754Single: - return float32FromPayload(TableObject::data() + addr, 0); - break; + uint16_t ApplicationProgramObject::getWord(uint32_t addr) + { + return Knx::getWord(TableObject::data() + addr); + } - case Float_Enc_IEEE754Double: - return float64FromPayload(TableObject::data() + addr, 0); - break; + uint32_t ApplicationProgramObject::getInt(uint32_t addr) + { + return Knx::getInt(TableObject::data() + addr); + } - default: - return 0; - break; + double ApplicationProgramObject::getFloat(uint32_t addr, ParameterFloatEncodings encoding) + { + switch (encoding) + { + case Float_Enc_DPT9: + return float16FromPayload(TableObject::data() + addr, 0); + break; + + case Float_Enc_IEEE754Single: + return float32FromPayload(TableObject::data() + addr, 0); + break; + + case Float_Enc_IEEE754Double: + return float64FromPayload(TableObject::data() + addr, 0); + break; + + default: + return 0; + break; + } } -} -void ApplicationProgramObject::beforeStateChange(LoadState& newState) -{ - LOGGER.info("beforeStateChange %s", enum_name(newState)); - TableObject::beforeStateChange(newState); -} + void ApplicationProgramObject::beforeStateChange(LoadState& newState) + { + LOGGER.info("beforeStateChange %s", enum_name(newState)); + TableObject::beforeStateChange(newState); + } +} \ No newline at end of file diff --git a/src/knx/interface_object/application_program_object.h b/src/knx/interface_object/application_program_object.h index 99b03d0a..6da91178 100644 --- a/src/knx/interface_object/application_program_object.h +++ b/src/knx/interface_object/application_program_object.h @@ -2,25 +2,28 @@ #include "table_object.h" -enum ParameterFloatEncodings +namespace Knx { - Float_Enc_DPT9 = 0, // 2 Byte. See Chapter 3.7.2 section 3.10 (Datapoint Types 2-Octet Float Value) - Float_Enc_IEEE754Single = 1, // 4 Byte. C++ float - Float_Enc_IEEE754Double = 2, // 8 Byte. C++ double -}; -class ApplicationProgramObject : public TableObject -{ - public: - ApplicationProgramObject(Memory& memory); - uint8_t* save(uint8_t* buffer) override; - const uint8_t* restore(const uint8_t* buffer) override; - uint16_t saveSize() override; - uint8_t* data(uint32_t addr); - uint8_t getByte(uint32_t addr); - uint16_t getWord(uint32_t addr); - uint32_t getInt(uint32_t addr); - double getFloat(uint32_t addr, ParameterFloatEncodings encoding); + enum ParameterFloatEncodings + { + Float_Enc_DPT9 = 0, // 2 Byte. See Chapter 3.7.2 section 3.10 (Datapoint Types 2-Octet Float Value) + Float_Enc_IEEE754Single = 1, // 4 Byte. C++ float + Float_Enc_IEEE754Double = 2, // 8 Byte. C++ double + }; + class ApplicationProgramObject : public TableObject + { + public: + ApplicationProgramObject(Memory& memory); + uint8_t* save(uint8_t* buffer) override; + const uint8_t* restore(const uint8_t* buffer) override; + uint16_t saveSize() override; + uint8_t* data(uint32_t addr); + uint8_t getByte(uint32_t addr); + uint16_t getWord(uint32_t addr); + uint32_t getInt(uint32_t addr); + double getFloat(uint32_t addr, ParameterFloatEncodings encoding); - protected: - void beforeStateChange(LoadState& newState) override; -}; + protected: + void beforeStateChange(LoadState& newState) override; + }; +} \ No newline at end of file diff --git a/src/knx/interface_object/association_table_object.cpp b/src/knx/interface_object/association_table_object.cpp index 5590fe5c..cf955ced 100644 --- a/src/knx/interface_object/association_table_object.cpp +++ b/src/knx/interface_object/association_table_object.cpp @@ -7,172 +7,175 @@ #define LOGGER Logger::logger("AssociationTableObject") -using namespace std; - -AssociationTableObject::AssociationTableObject(Memory& memory) - : TableObject(memory) +namespace Knx { - Property* properties[] = + using namespace std; + + AssociationTableObject::AssociationTableObject(Memory& memory) + : TableObject(memory) { - new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_ASSOC_TABLE), - new DataProperty(PID_TABLE, false, PDT_GENERIC_04, 65535, ReadLv3 | WriteLv0) //FIXME: implement correctly - }; + Property* properties[] = + { + new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_ASSOC_TABLE), + new DataProperty(PID_TABLE, false, PDT_GENERIC_04, 65535, ReadLv3 | WriteLv0) //FIXME: implement correctly + }; - TableObject::initializeProperties(sizeof(properties), properties); -} + TableObject::initializeProperties(sizeof(properties), properties); + } -uint16_t AssociationTableObject::entryCount() -{ - return ntohs(_tableData[0]); -} + uint16_t AssociationTableObject::entryCount() + { + return ntohs(_tableData[0]); + } -uint16_t AssociationTableObject::getTSAP(uint16_t idx) -{ - if (idx >= entryCount()) - return 0; + uint16_t AssociationTableObject::getTSAP(uint16_t idx) + { + if (idx >= entryCount()) + return 0; - return ntohs(_tableData[2 * idx + 1]); -} + return ntohs(_tableData[2 * idx + 1]); + } -uint16_t AssociationTableObject::getASAP(uint16_t idx) -{ - if (idx >= entryCount()) - return 0; + uint16_t AssociationTableObject::getASAP(uint16_t idx) + { + if (idx >= entryCount()) + return 0; - return ntohs(_tableData[2 * idx + 2]); -} + return ntohs(_tableData[2 * idx + 2]); + } -// after any table change the table is checked if it allows -// binary search access. If not, sortedEntryCount stays 0, -// otherwise sortedEntryCount represents size of bin search array -void AssociationTableObject::prepareBinarySearch() -{ - sortedEntryCount = 0; -#ifdef USE_BINSEARCH - uint16_t lastASAP = 0; - uint16_t currentASAP = 0; - uint16_t lookupIdx = 0; - uint16_t lookupASAP = 0; - - // we iterate through all ASAP - // the first n ASAP are sorted (strictly increasing number), these are assigning sending TSAP - // the remaining ASAP have to be all repetitions, otherwise we set sortedEntryCount to 0, which forces linear search - if (_tableData != nullptr) + // after any table change the table is checked if it allows + // binary search access. If not, sortedEntryCount stays 0, + // otherwise sortedEntryCount represents size of bin search array + void AssociationTableObject::prepareBinarySearch() { - for (uint16_t idx = 0; idx < entryCount(); idx++) + sortedEntryCount = 0; +#ifdef USE_BINSEARCH + uint16_t lastASAP = 0; + uint16_t currentASAP = 0; + uint16_t lookupIdx = 0; + uint16_t lookupASAP = 0; + + // we iterate through all ASAP + // the first n ASAP are sorted (strictly increasing number), these are assigning sending TSAP + // the remaining ASAP have to be all repetitions, otherwise we set sortedEntryCount to 0, which forces linear search + if (_tableData != nullptr) { - currentASAP = getASAP(idx); - - if (sortedEntryCount) + for (uint16_t idx = 0; idx < entryCount(); idx++) { - // look if the remaining ASAP exist in the previously sorted list. - while (lookupIdx < sortedEntryCount) - { - lookupASAP = getASAP(lookupIdx); + currentASAP = getASAP(idx); - if (currentASAP <= lookupASAP) - break; // while - else - lookupIdx++; - } - - if (currentASAP < lookupASAP || lookupIdx >= sortedEntryCount) + if (sortedEntryCount) { - // a new ASAP found, we force linear search - sortedEntryCount = 0; - break; // for + // look if the remaining ASAP exist in the previously sorted list. + while (lookupIdx < sortedEntryCount) + { + lookupASAP = getASAP(lookupIdx); + + if (currentASAP <= lookupASAP) + break; // while + else + lookupIdx++; + } + + if (currentASAP < lookupASAP || lookupIdx >= sortedEntryCount) + { + // a new ASAP found, we force linear search + sortedEntryCount = 0; + break; // for + } } - } - else - { - // check for strictly increasing ASAP - if (currentASAP > lastASAP) - lastASAP = currentASAP; else { - sortedEntryCount = idx; // last found index indicates end of sorted list - idx--; // current item has to be handled as remaining ASAP + // check for strictly increasing ASAP + if (currentASAP > lastASAP) + lastASAP = currentASAP; + else + { + sortedEntryCount = idx; // last found index indicates end of sorted list + idx--; // current item has to be handled as remaining ASAP + } } } - } - // in case complete table is strictly increasing - if (lookupIdx == 0 && sortedEntryCount == 0) - sortedEntryCount = entryCount(); - } + // in case complete table is strictly increasing + if (lookupIdx == 0 && sortedEntryCount == 0) + sortedEntryCount = entryCount(); + } #endif -} + } -const uint8_t* AssociationTableObject::restore(const uint8_t* buffer) -{ - buffer = TableObject::restore(buffer); - _tableData = (uint16_t*)data(); - prepareBinarySearch(); - return buffer; -} - -// return type is int32 so that we can return uint16 and -1 -int32_t AssociationTableObject::translateAsap(uint16_t asap) -{ - // sortedEntryCount is determined in prepareBinarySearch() - // if ETS provides strictly increasing numbers for ASAP - // represents the size of the array to search - if (sortedEntryCount) + const uint8_t* AssociationTableObject::restore(const uint8_t* buffer) { - uint16_t low = 0; - uint16_t high = sortedEntryCount - 1; + buffer = TableObject::restore(buffer); + _tableData = (uint16_t*)data(); + prepareBinarySearch(); + return buffer; + } - while (low <= high) + // return type is int32 so that we can return uint16 and -1 + int32_t AssociationTableObject::translateAsap(uint16_t asap) + { + // sortedEntryCount is determined in prepareBinarySearch() + // if ETS provides strictly increasing numbers for ASAP + // represents the size of the array to search + if (sortedEntryCount) { - uint16_t i = (low + high) / 2; - uint16_t asap_i = getASAP(i); + uint16_t low = 0; + uint16_t high = sortedEntryCount - 1; - if (asap_i == asap) - return getTSAP(i); + while (low <= high) + { + uint16_t i = (low + high) / 2; + uint16_t asap_i = getASAP(i); - if (asap_i > asap) - high = i - 1; - else - low = i + 1 ; - } - } - else - { - // if ASAP numbers are not strictly increasing linear seach is used - for (uint16_t i = 0; i < entryCount(); i++) - if (getASAP(i) == asap) - return getTSAP(i); - } + if (asap_i == asap) + return getTSAP(i); - return -1; -} + if (asap_i > asap) + high = i - 1; + else + low = i + 1 ; + } + } + else + { + // if ASAP numbers are not strictly increasing linear seach is used + for (uint16_t i = 0; i < entryCount(); i++) + if (getASAP(i) == asap) + return getTSAP(i); + } -void AssociationTableObject::beforeStateChange(LoadState& newState) -{ - LOGGER.info("beforeStateChange %s", enum_name(newState)); - TableObject::beforeStateChange(newState); + return -1; + } - if (newState != LS_LOADED) - return; + void AssociationTableObject::beforeStateChange(LoadState& newState) + { + LOGGER.info("beforeStateChange %s", enum_name(newState)); + TableObject::beforeStateChange(newState); - _tableData = (uint16_t*)data(); - prepareBinarySearch(); -} + if (newState != LS_LOADED) + return; -int32_t AssociationTableObject::nextAsap(uint16_t tsap, uint16_t& startIdx) -{ - uint16_t entries = entryCount(); + _tableData = (uint16_t*)data(); + prepareBinarySearch(); + } - for (uint16_t i = startIdx; i < entries; i++) + int32_t AssociationTableObject::nextAsap(uint16_t tsap, uint16_t& startIdx) { - startIdx = i + 1; + uint16_t entries = entryCount(); - if (getTSAP(i) == tsap) + for (uint16_t i = startIdx; i < entries; i++) { - return getASAP(i); + startIdx = i + 1; + + if (getTSAP(i) == tsap) + { + return getASAP(i); + } } - } - return -1; -} + return -1; + } +} \ No newline at end of file diff --git a/src/knx/interface_object/association_table_object.h b/src/knx/interface_object/association_table_object.h index 7465de67..da803b9e 100644 --- a/src/knx/interface_object/association_table_object.h +++ b/src/knx/interface_object/association_table_object.h @@ -2,24 +2,27 @@ #include "table_object.h" -class AssociationTableObject : public TableObject +namespace Knx { - public: - AssociationTableObject(Memory& memory); + class AssociationTableObject : public TableObject + { + public: + AssociationTableObject(Memory& memory); - const uint8_t* restore(const uint8_t* buffer) override; + const uint8_t* restore(const uint8_t* buffer) override; - int32_t translateAsap(uint16_t asap); - int32_t nextAsap(uint16_t tsap, uint16_t& startIdx); + int32_t translateAsap(uint16_t asap); + int32_t nextAsap(uint16_t tsap, uint16_t& startIdx); - protected: - void beforeStateChange(LoadState& newState) override; + protected: + void beforeStateChange(LoadState& newState) override; - private: - uint16_t entryCount(); - uint16_t getTSAP(uint16_t idx); - uint16_t getASAP(uint16_t idx); - void prepareBinarySearch(); - uint16_t* _tableData = 0; - uint16_t sortedEntryCount; -}; + private: + uint16_t entryCount(); + uint16_t getTSAP(uint16_t idx); + uint16_t getASAP(uint16_t idx); + void prepareBinarySearch(); + uint16_t* _tableData = 0; + uint16_t sortedEntryCount; + }; +} \ No newline at end of file diff --git a/src/knx/interface_object/callback_property.h b/src/knx/interface_object/callback_property.h index 3a99f9f6..78803216 100644 --- a/src/knx/interface_object/callback_property.h +++ b/src/knx/interface_object/callback_property.h @@ -2,38 +2,41 @@ #include "property.h" -class InterfaceObject; - -template class CallbackProperty : public Property +namespace Knx { - public: - CallbackProperty(T* io, PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, - uint8_t access, uint8_t (*readCallback)(T*, uint16_t, uint8_t, uint8_t*), - uint8_t (*writeCallback)(T*, uint16_t, uint8_t, const uint8_t*)) - : Property(id, writeEnable, type, maxElements, access), - _interfaceObject(io), _readCallback(readCallback), _writeCallback(writeCallback) - {} - CallbackProperty(T* io, PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, - uint8_t access, uint8_t (*readCallback)(T*, uint16_t, uint8_t, uint8_t*)) - : Property(id, writeEnable, type, maxElements, access), _interfaceObject(io), _readCallback(readCallback) - {} + class InterfaceObject; + + template class CallbackProperty : public Property + { + public: + CallbackProperty(T* io, PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, + uint8_t access, uint8_t (*readCallback)(T*, uint16_t, uint8_t, uint8_t*), + uint8_t (*writeCallback)(T*, uint16_t, uint8_t, const uint8_t*)) + : Property(id, writeEnable, type, maxElements, access), + _interfaceObject(io), _readCallback(readCallback), _writeCallback(writeCallback) + {} + CallbackProperty(T* io, PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, + uint8_t access, uint8_t (*readCallback)(T*, uint16_t, uint8_t, uint8_t*)) + : Property(id, writeEnable, type, maxElements, access), _interfaceObject(io), _readCallback(readCallback) + {} - uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const override - { - if (count == 0 || _readCallback == nullptr || start > _maxElements || start + count > _maxElements + 1) - return 0; + uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const override + { + if (count == 0 || _readCallback == nullptr || start > _maxElements || start + count > _maxElements + 1) + return 0; - return _readCallback(_interfaceObject, start, count, data); - } - uint8_t write(uint16_t start, uint8_t count, const uint8_t* data) override - { - if (count == 0 || start > _maxElements || start + count > _maxElements + 1 || _writeCallback == nullptr) - return 0; + return _readCallback(_interfaceObject, start, count, data); + } + uint8_t write(uint16_t start, uint8_t count, const uint8_t* data) override + { + if (count == 0 || start > _maxElements || start + count > _maxElements + 1 || _writeCallback == nullptr) + return 0; - return _writeCallback(_interfaceObject, start, count, data); - } - private: - T* _interfaceObject = nullptr; - uint8_t (*_readCallback)(T*, uint16_t, uint8_t, uint8_t*) = nullptr; - uint8_t (*_writeCallback)(T*, uint16_t, uint8_t, const uint8_t*) = nullptr; -}; + return _writeCallback(_interfaceObject, start, count, data); + } + private: + T* _interfaceObject = nullptr; + uint8_t (*_readCallback)(T*, uint16_t, uint8_t, uint8_t*) = nullptr; + uint8_t (*_writeCallback)(T*, uint16_t, uint8_t, const uint8_t*) = nullptr; + }; +} \ No newline at end of file diff --git a/src/knx/interface_object/data_property.cpp b/src/knx/interface_object/data_property.cpp index cc875934..a7e25c66 100644 --- a/src/knx/interface_object/data_property.cpp +++ b/src/knx/interface_object/data_property.cpp @@ -4,166 +4,169 @@ #include -uint8_t DataProperty::read(uint16_t start, uint8_t count, uint8_t* data) const +namespace Knx { - if (start == 0) + uint8_t DataProperty::read(uint16_t start, uint8_t count, uint8_t* data) const { - pushWord(_currentElements, data); - return 1; - } - - if (count == 0 || _currentElements == 0 || start > _currentElements || count > _currentElements - start + 1) - return 0; + if (start == 0) + { + pushWord(_currentElements, data); + return 1; + } + if (count == 0 || _currentElements == 0 || start > _currentElements || count > _currentElements - start + 1) + return 0; - // we start counting with zero - start -= 1; - // data is already big enough to hold the data - memcpy(data, _data + (start * ElementSize()), count * ElementSize()); + // we start counting with zero + start -= 1; - return count; -} + // data is already big enough to hold the data + memcpy(data, _data + (start * ElementSize()), count * ElementSize()); -uint8_t DataProperty::write(uint16_t start, uint8_t count, const uint8_t* data) -{ - if (count == 0 || start > _maxElements || start + count > _maxElements + 1) - return 0; + return count; + } - if (start == 0) + uint8_t DataProperty::write(uint16_t start, uint8_t count, const uint8_t* data) { - if (count == 1 && data[0] == 0 && data[1] == 0) - { - // reset _data - _currentElements = 0; + if (count == 0 || start > _maxElements || start + count > _maxElements + 1) + return 0; - if (_data) + if (start == 0) + { + if (count == 1 && data[0] == 0 && data[1] == 0) { - delete[] _data; - _data = nullptr; - } + // reset _data + _currentElements = 0; - return 1; + if (_data) + { + delete[] _data; + _data = nullptr; + } + + return 1; + } + else + return 0; } - else - return 0; - } - // we start counting with zero - start -= 1; + // we start counting with zero + start -= 1; - if (start + count > _currentElements) - { - // reallocate memory for _data - uint8_t* oldData = _data; - size_t oldDataSize = _currentElements * ElementSize(); + if (start + count > _currentElements) + { + // reallocate memory for _data + uint8_t* oldData = _data; + size_t oldDataSize = _currentElements * ElementSize(); - size_t newDataSize = (start + count) * ElementSize(); - _data = new uint8_t[newDataSize]; - memset(_data, 0, newDataSize); + size_t newDataSize = (start + count) * ElementSize(); + _data = new uint8_t[newDataSize]; + memset(_data, 0, newDataSize); - if (oldData != nullptr) - { - memcpy(_data, oldData, oldDataSize); - delete[] oldData; + if (oldData != nullptr) + { + memcpy(_data, oldData, oldDataSize); + delete[] oldData; + } + + _currentElements = start + count; } - _currentElements = start + count; + memcpy(_data + (start * ElementSize()), data, count * ElementSize()); + + return count; } - memcpy(_data + (start * ElementSize()), data, count * ElementSize()); + DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, + uint16_t maxElements, uint8_t access) + : Property(id, writeEnable, type, maxElements, access) + {} - return count; -} + DataProperty::~DataProperty() + { + if (_data) + delete[] _data; + } -DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, - uint16_t maxElements, uint8_t access) - : Property(id, writeEnable, type, maxElements, access) -{} + DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, + uint16_t maxElements, uint8_t access, uint16_t value) + : Property(id, writeEnable, type, maxElements, access) + { + Property::write(value); + } -DataProperty::~DataProperty() -{ - if (_data) - delete[] _data; -} + DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, + uint16_t maxElements, uint8_t access, uint32_t value) + : Property(id, writeEnable, type, maxElements, access) + { + Property::write(value); + } -DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, - uint16_t maxElements, uint8_t access, uint16_t value) - : Property(id, writeEnable, type, maxElements, access) -{ - Property::write(value); -} + DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, + uint16_t maxElements, uint8_t access, uint8_t value) + : Property(id, writeEnable, type, maxElements, access) + { + Property::write(value); + } -DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, - uint16_t maxElements, uint8_t access, uint32_t value) - : Property(id, writeEnable, type, maxElements, access) -{ - Property::write(value); -} + DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, + uint16_t maxElements, uint8_t access, const uint8_t* value) + : Property(id, writeEnable, type, maxElements, access) + { + Property::write(value); + } -DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, - uint16_t maxElements, uint8_t access, uint8_t value) - : Property(id, writeEnable, type, maxElements, access) -{ - Property::write(value); -} + uint16_t DataProperty::saveSize() + { + return sizeof(_currentElements) + _maxElements * ElementSize(); + } -DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, - uint16_t maxElements, uint8_t access, const uint8_t* value) - : Property(id, writeEnable, type, maxElements, access) -{ - Property::write(value); -} -uint16_t DataProperty::saveSize() -{ - return sizeof(_currentElements) + _maxElements * ElementSize(); -} + const uint8_t* DataProperty::restore(const uint8_t* buffer) + { + uint16_t elements = 0; + buffer = popWord(elements, buffer); + if (elements != _currentElements) + { + if (_data != nullptr) + delete[] _data; -const uint8_t* DataProperty::restore(const uint8_t* buffer) -{ - uint16_t elements = 0; - buffer = popWord(elements, buffer); + _data = new uint8_t[elements * ElementSize()]; + _currentElements = elements; + } - if (elements != _currentElements) - { - if (_data != nullptr) - delete[] _data; + if (elements > 0) + buffer = popByteArray(_data, elements * ElementSize(), buffer); - _data = new uint8_t[elements * ElementSize()]; - _currentElements = elements; + return buffer; } - if (elements > 0) - buffer = popByteArray(_data, elements * ElementSize(), buffer); - return buffer; -} - - -uint8_t* DataProperty::save(uint8_t* buffer) -{ - buffer = pushWord(_currentElements, buffer); + uint8_t* DataProperty::save(uint8_t* buffer) + { + buffer = pushWord(_currentElements, buffer); - if (_currentElements > 0) - buffer = pushByteArray(_data, _currentElements * ElementSize(), buffer); + if (_currentElements > 0) + buffer = pushByteArray(_data, _currentElements * ElementSize(), buffer); - return buffer; -} + return buffer; + } -const uint8_t* DataProperty::data() -{ - return _data; -} + const uint8_t* DataProperty::data() + { + return _data; + } -const uint8_t* DataProperty::data(uint16_t elementIndex) -{ - if ((elementIndex == 0) || (elementIndex > _currentElements)) - return nullptr; + const uint8_t* DataProperty::data(uint16_t elementIndex) + { + if ((elementIndex == 0) || (elementIndex > _currentElements)) + return nullptr; - elementIndex -= 1; // Starting from 0 - uint16_t offset = elementIndex * ElementSize(); - return _data + offset; -} + elementIndex -= 1; // Starting from 0 + uint16_t offset = elementIndex * ElementSize(); + return _data + offset; + } +} \ No newline at end of file diff --git a/src/knx/interface_object/data_property.h b/src/knx/interface_object/data_property.h index f1cfca69..d300d719 100644 --- a/src/knx/interface_object/data_property.h +++ b/src/knx/interface_object/data_property.h @@ -2,24 +2,27 @@ #include "property.h" -class DataProperty : public Property +namespace Knx { - public: - DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access); - DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, uint8_t value); - DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, uint16_t value); - DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, uint32_t value); - DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, const uint8_t* value); - ~DataProperty() override; - uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const override; - uint8_t write(uint16_t start, uint8_t count, const uint8_t* data) override; - uint8_t* save(uint8_t* buffer) override; - const uint8_t* restore(const uint8_t* buffer) override; - uint16_t saveSize() override; - const uint8_t* data(); - const uint8_t* data(uint16_t elementIndex); + class DataProperty : public Property + { + public: + DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access); + DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, uint8_t value); + DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, uint16_t value); + DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, uint32_t value); + DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, const uint8_t* value); + ~DataProperty() override; + uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const override; + uint8_t write(uint16_t start, uint8_t count, const uint8_t* data) override; + uint8_t* save(uint8_t* buffer) override; + const uint8_t* restore(const uint8_t* buffer) override; + uint16_t saveSize() override; + const uint8_t* data(); + const uint8_t* data(uint16_t elementIndex); - private: - uint16_t _currentElements = 0; - uint8_t* _data = nullptr; -}; + private: + uint16_t _currentElements = 0; + uint8_t* _data = nullptr; + }; +} \ No newline at end of file diff --git a/src/knx/interface_object/device_object.cpp b/src/knx/interface_object/device_object.cpp index 60480c19..9cf0b0bf 100644 --- a/src/knx/interface_object/device_object.cpp +++ b/src/knx/interface_object/device_object.cpp @@ -7,120 +7,122 @@ #define LEN_KNX_SERIAL 6 -DeviceObject::DeviceObject() +namespace Knx { - // Default to KNXA (0xFA) - // Note: ETS does not accept a SN 00FA00000000 in data secure mode. - // ETS says that 00FA00000000 looks "suspicious" in the log file. - uint8_t serialNumber[] = {0x00, 0xFA, 0x01, 0x02, 0x03, 0x04}; - uint8_t hardwareType[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - Property* properties[] = + DeviceObject::DeviceObject() { - new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_DEVICE), - new DataProperty(PID_SERIAL_NUMBER, false, PDT_GENERIC_06, 1, ReadLv3 | WriteLv0, serialNumber), - new CallbackProperty(this, PID_MANUFACTURER_ID, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, - [](DeviceObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t + // Default to KNXA (0xFA) + // Note: ETS does not accept a SN 00FA00000000 in data secure mode. + // ETS says that 00FA00000000 looks "suspicious" in the log file. + uint8_t serialNumber[] = {0x00, 0xFA, 0x01, 0x02, 0x03, 0x04}; + uint8_t hardwareType[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + Property* properties[] = { - if (start == 0) + new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_DEVICE), + new DataProperty(PID_SERIAL_NUMBER, false, PDT_GENERIC_06, 1, ReadLv3 | WriteLv0, serialNumber), + new CallbackProperty(this, PID_MANUFACTURER_ID, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, + [](DeviceObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); + if (start == 0) + { + uint16_t currentNoOfElements = 1; + pushWord(currentNoOfElements, data); + return 1; + } + + pushByteArray(io->propertyData(PID_SERIAL_NUMBER), 2, data); return 1; - } - - pushByteArray(io->propertyData(PID_SERIAL_NUMBER), 2, data); - return 1; - }), - new DataProperty(PID_DEVICE_CONTROL, true, PDT_BITSET8, 1, ReadLv3 | WriteLv3, (uint8_t)0), - new DataProperty(PID_ORDER_INFO, false, PDT_GENERIC_10, 1, ReadLv3 | WriteLv0), - new DataProperty(PID_VERSION, false, PDT_VERSION, 1, ReadLv3 | WriteLv0, (uint16_t)3), - new DataProperty(PID_ROUTING_COUNT, true, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv3, (uint8_t)(6 << 4)), - new CallbackProperty(this, PID_PROG_MODE, true, PDT_BITSET8, 1, ReadLv3 | WriteLv3, - [](DeviceObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t - { - if (start == 0) + }), + new DataProperty(PID_DEVICE_CONTROL, true, PDT_BITSET8, 1, ReadLv3 | WriteLv3, (uint8_t)0), + new DataProperty(PID_ORDER_INFO, false, PDT_GENERIC_10, 1, ReadLv3 | WriteLv0), + new DataProperty(PID_VERSION, false, PDT_VERSION, 1, ReadLv3 | WriteLv0, (uint16_t)3), + new DataProperty(PID_ROUTING_COUNT, true, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv3, (uint8_t)(6 << 4)), + new CallbackProperty(this, PID_PROG_MODE, true, PDT_BITSET8, 1, ReadLv3 | WriteLv3, + [](DeviceObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); + if (start == 0) + { + uint16_t currentNoOfElements = 1; + pushWord(currentNoOfElements, data); + return 1; + } + + *data = io->_prgMode; return 1; - } + }, + [](DeviceObject * io, uint16_t start, uint8_t count, const uint8_t* data) -> uint8_t + { + if (start == 0) + return 1; - *data = io->_prgMode; - return 1; - }, - [](DeviceObject * io, uint16_t start, uint8_t count, const uint8_t* data) -> uint8_t - { - if (start == 0) + io->_prgMode = *data; return 1; - - io->_prgMode = *data; - return 1; - }), - new DataProperty(PID_MAX_APDU_LENGTH, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)254), - new CallbackProperty(this, PID_SUBNET_ADDR, false, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv0, - [](DeviceObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t - { - if (start == 0) + }), + new DataProperty(PID_MAX_APDU_LENGTH, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)254), + new CallbackProperty(this, PID_SUBNET_ADDR, false, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv0, + [](DeviceObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); - return 1; - } + if (start == 0) + { + uint16_t currentNoOfElements = 1; + pushWord(currentNoOfElements, data); + return 1; + } - *data = ((io->_ownAddress >> 8) & 0xff); + *data = ((io->_ownAddress >> 8) & 0xff); - return 1; - }), - new CallbackProperty(this, PID_DEVICE_ADDR, false, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv0, - [](DeviceObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t - { - if (start == 0) + return 1; + }), + new CallbackProperty(this, PID_DEVICE_ADDR, false, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv0, + [](DeviceObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); + if (start == 0) + { + uint16_t currentNoOfElements = 1; + pushWord(currentNoOfElements, data); + return 1; + } + + *data = (io->_ownAddress & 0xff); return 1; - } - - *data = (io->_ownAddress & 0xff); - return 1; - }), - new DataProperty(PID_IO_LIST, false, PDT_UNSIGNED_INT, 8, ReadLv3 | WriteLv0), - new DataProperty(PID_HARDWARE_TYPE, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv3, hardwareType), - new DataProperty(PID_DEVICE_DESCRIPTOR, false, PDT_GENERIC_02, 1, ReadLv3 | WriteLv0), + }), + new DataProperty(PID_IO_LIST, false, PDT_UNSIGNED_INT, 8, ReadLv3 | WriteLv0), + new DataProperty(PID_HARDWARE_TYPE, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv3, hardwareType), + new DataProperty(PID_DEVICE_DESCRIPTOR, false, PDT_GENERIC_02, 1, ReadLv3 | WriteLv0), #ifndef KNX_NO_RF - new DataProperty(PID_RF_DOMAIN_ADDRESS_CEMI_SERVER, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv3), + new DataProperty(PID_RF_DOMAIN_ADDRESS_CEMI_SERVER, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv3), #endif - }; - initializeProperties(sizeof(properties), properties); -} + }; + initializeProperties(sizeof(properties), properties); + } -uint8_t* DeviceObject::save(uint8_t* buffer) -{ - buffer = pushWord(_ownAddress, buffer); - return InterfaceObject::save(buffer); -} + uint8_t* DeviceObject::save(uint8_t* buffer) + { + buffer = pushWord(_ownAddress, buffer); + return InterfaceObject::save(buffer); + } -const uint8_t* DeviceObject::restore(const uint8_t* buffer) -{ - buffer = popWord(_ownAddress, buffer); - return InterfaceObject::restore(buffer); -} + const uint8_t* DeviceObject::restore(const uint8_t* buffer) + { + buffer = popWord(_ownAddress, buffer); + return InterfaceObject::restore(buffer); + } -uint16_t DeviceObject::saveSize() -{ - return 2 + InterfaceObject::saveSize(); -} + uint16_t DeviceObject::saveSize() + { + return 2 + InterfaceObject::saveSize(); + } -uint16_t DeviceObject::individualAddress() -{ - return _ownAddress; -} + uint16_t DeviceObject::individualAddress() + { + return _ownAddress; + } -void DeviceObject::individualAddress(uint16_t value) -{ - _ownAddress = value; -} + void DeviceObject::individualAddress(uint16_t value) + { + _ownAddress = value; + } #define USER_STOPPED 0x1 #define OWN_ADDR_DUPL 0x2 @@ -128,167 +130,168 @@ void DeviceObject::individualAddress(uint16_t value) #define SAFE_STATE 0x8 -void DeviceObject::individualAddressDuplication(bool value) -{ - Property* prop = property(PID_DEVICE_CONTROL); - uint8_t data; - prop->read(data); + void DeviceObject::individualAddressDuplication(bool value) + { + Property* prop = property(PID_DEVICE_CONTROL); + uint8_t data; + prop->read(data); - if (value) - data |= OWN_ADDR_DUPL; - else - data &= ~OWN_ADDR_DUPL; + if (value) + data |= OWN_ADDR_DUPL; + else + data &= ~OWN_ADDR_DUPL; - prop->write(data); -} + prop->write(data); + } -bool DeviceObject::verifyMode() -{ - Property* prop = property(PID_DEVICE_CONTROL); - uint8_t data; - prop->read(data); - return (data & VERIFY_MODE) > 0; -} + bool DeviceObject::verifyMode() + { + Property* prop = property(PID_DEVICE_CONTROL); + uint8_t data; + prop->read(data); + return (data & VERIFY_MODE) > 0; + } -void DeviceObject::verifyMode(bool value) -{ - Property* prop = property(PID_DEVICE_CONTROL); - uint8_t data; - prop->read(data); + void DeviceObject::verifyMode(bool value) + { + Property* prop = property(PID_DEVICE_CONTROL); + uint8_t data; + prop->read(data); - if (value) - data |= VERIFY_MODE; - else - data &= ~VERIFY_MODE; + if (value) + data |= VERIFY_MODE; + else + data &= ~VERIFY_MODE; - prop->write(data); -} + prop->write(data); + } -bool DeviceObject::progMode() -{ - return _prgMode == 1; -} + bool DeviceObject::progMode() + { + return _prgMode == 1; + } -void DeviceObject::progMode(bool value) -{ - if (value) - _prgMode = 1; - else - _prgMode = 0; -} + void DeviceObject::progMode(bool value) + { + if (value) + _prgMode = 1; + else + _prgMode = 0; + } -uint16_t DeviceObject::manufacturerId() -{ - uint16_t manufacturerId; - popWord(manufacturerId, propertyData(PID_SERIAL_NUMBER)); - return manufacturerId; -} + uint16_t DeviceObject::manufacturerId() + { + uint16_t manufacturerId; + popWord(manufacturerId, propertyData(PID_SERIAL_NUMBER)); + return manufacturerId; + } -void DeviceObject::manufacturerId(uint16_t value) -{ - uint8_t data[LEN_KNX_SERIAL]; - memcpy(data, propertyData(PID_SERIAL_NUMBER), LEN_KNX_SERIAL); - pushWord(value, data); - propertyValue(PID_SERIAL_NUMBER, data); -} + void DeviceObject::manufacturerId(uint16_t value) + { + uint8_t data[LEN_KNX_SERIAL]; + memcpy(data, propertyData(PID_SERIAL_NUMBER), LEN_KNX_SERIAL); + pushWord(value, data); + propertyValue(PID_SERIAL_NUMBER, data); + } -uint32_t DeviceObject::bauNumber() -{ - uint32_t bauNumber; - popInt(bauNumber, propertyData(PID_SERIAL_NUMBER) + 2); - return bauNumber; -} + uint32_t DeviceObject::bauNumber() + { + uint32_t bauNumber; + popInt(bauNumber, propertyData(PID_SERIAL_NUMBER) + 2); + return bauNumber; + } -void DeviceObject::bauNumber(uint32_t value) -{ - uint8_t data[LEN_KNX_SERIAL]; - memcpy(data, propertyData(PID_SERIAL_NUMBER), LEN_KNX_SERIAL); - pushInt(value, data + 2); - propertyValue(PID_SERIAL_NUMBER, data); -} + void DeviceObject::bauNumber(uint32_t value) + { + uint8_t data[LEN_KNX_SERIAL]; + memcpy(data, propertyData(PID_SERIAL_NUMBER), LEN_KNX_SERIAL); + pushInt(value, data + 2); + propertyValue(PID_SERIAL_NUMBER, data); + } -const uint8_t* DeviceObject::orderNumber() -{ - DataProperty* prop = (DataProperty*)property(PID_ORDER_INFO); - return prop->data(); -} + const uint8_t* DeviceObject::orderNumber() + { + DataProperty* prop = (DataProperty*)property(PID_ORDER_INFO); + return prop->data(); + } -void DeviceObject::orderNumber(const uint8_t* value) -{ - Property* prop = property(PID_ORDER_INFO); - prop->write(value); -} + void DeviceObject::orderNumber(const uint8_t* value) + { + Property* prop = property(PID_ORDER_INFO); + prop->write(value); + } -const uint8_t* DeviceObject::hardwareType() -{ - DataProperty* prop = (DataProperty*)property(PID_HARDWARE_TYPE); - return prop->data(); -} + const uint8_t* DeviceObject::hardwareType() + { + DataProperty* prop = (DataProperty*)property(PID_HARDWARE_TYPE); + return prop->data(); + } -void DeviceObject::hardwareType(const uint8_t* value) -{ - Property* prop = property(PID_HARDWARE_TYPE); - prop->write(value); -} + void DeviceObject::hardwareType(const uint8_t* value) + { + Property* prop = property(PID_HARDWARE_TYPE); + prop->write(value); + } -uint16_t DeviceObject::version() -{ - Property* prop = property(PID_VERSION); - uint16_t value; - prop->read(value); - return value; -} + uint16_t DeviceObject::version() + { + Property* prop = property(PID_VERSION); + uint16_t value; + prop->read(value); + return value; + } -void DeviceObject::version(uint16_t value) -{ - Property* prop = property(PID_VERSION); - prop->write(value); -} + void DeviceObject::version(uint16_t value) + { + Property* prop = property(PID_VERSION); + prop->write(value); + } -uint16_t DeviceObject::maskVersion() -{ - Property* prop = property(PID_DEVICE_DESCRIPTOR); - uint16_t value; - prop->read(value); - return value; -} + uint16_t DeviceObject::maskVersion() + { + Property* prop = property(PID_DEVICE_DESCRIPTOR); + uint16_t value; + prop->read(value); + return value; + } -void DeviceObject::maskVersion(uint16_t value) -{ - Property* prop = property(PID_DEVICE_DESCRIPTOR); - prop->write(value); -} + void DeviceObject::maskVersion(uint16_t value) + { + Property* prop = property(PID_DEVICE_DESCRIPTOR); + prop->write(value); + } -uint16_t DeviceObject::maxApduLength() -{ - Property* prop = property(PID_MAX_APDU_LENGTH); - uint16_t value; - prop->read(value); - return value; -} + uint16_t DeviceObject::maxApduLength() + { + Property* prop = property(PID_MAX_APDU_LENGTH); + uint16_t value; + prop->read(value); + return value; + } -void DeviceObject::maxApduLength(uint16_t value) -{ - Property* prop = property(PID_MAX_APDU_LENGTH); - prop->write(value); -} + void DeviceObject::maxApduLength(uint16_t value) + { + Property* prop = property(PID_MAX_APDU_LENGTH); + prop->write(value); + } -const uint8_t* DeviceObject::rfDomainAddress() -{ - DataProperty* prop = (DataProperty*)property(PID_RF_DOMAIN_ADDRESS_CEMI_SERVER); - return prop->data(); -} + const uint8_t* DeviceObject::rfDomainAddress() + { + DataProperty* prop = (DataProperty*)property(PID_RF_DOMAIN_ADDRESS_CEMI_SERVER); + return prop->data(); + } -void DeviceObject::rfDomainAddress(uint8_t* value) -{ - Property* prop = property(PID_RF_DOMAIN_ADDRESS_CEMI_SERVER); - prop->write(value); -} + void DeviceObject::rfDomainAddress(uint8_t* value) + { + Property* prop = property(PID_RF_DOMAIN_ADDRESS_CEMI_SERVER); + prop->write(value); + } -uint8_t DeviceObject::defaultHopCount() -{ - Property* prop = property(PID_ROUTING_COUNT); - uint8_t value; - prop->read(value); - return (value >> 4) & 0x07; -} + uint8_t DeviceObject::defaultHopCount() + { + Property* prop = property(PID_ROUTING_COUNT); + uint8_t value; + prop->read(value); + return (value >> 4) & 0x07; + } +} \ No newline at end of file diff --git a/src/knx/interface_object/device_object.h b/src/knx/interface_object/device_object.h index 8bfd2d2a..fffc7375 100644 --- a/src/knx/interface_object/device_object.h +++ b/src/knx/interface_object/device_object.h @@ -4,48 +4,51 @@ #define LEN_HARDWARE_TYPE 6 -class DeviceObject: public InterfaceObject +namespace Knx { - public: - // increase this version anytime DeviceObject-API changes - // the following value represents the serialized representation of DeviceObject. - const uint16_t apiVersion = 1; + class DeviceObject: public InterfaceObject + { + public: + // increase this version anytime DeviceObject-API changes + // the following value represents the serialized representation of DeviceObject. + const uint16_t apiVersion = 1; - DeviceObject(); - uint8_t* save(uint8_t* buffer) override; - const uint8_t* restore(const uint8_t* buffer) override; - uint16_t saveSize() override; + DeviceObject(); + uint8_t* save(uint8_t* buffer) override; + const uint8_t* restore(const uint8_t* buffer) override; + uint16_t saveSize() override; - uint16_t individualAddress(); - void individualAddress(uint16_t value); + uint16_t individualAddress(); + void individualAddress(uint16_t value); - void individualAddressDuplication(bool value); - bool verifyMode(); - void verifyMode(bool value); - bool progMode(); - void progMode(bool value); - uint16_t manufacturerId(); - void manufacturerId(uint16_t value); - uint32_t bauNumber(); - void bauNumber(uint32_t value); - const uint8_t* orderNumber(); - void orderNumber(const uint8_t* value); - const uint8_t* hardwareType(); - void hardwareType(const uint8_t* value); - uint16_t version(); - void version(uint16_t value); - uint16_t maskVersion(); - void maskVersion(uint16_t value); - uint16_t maxApduLength(); - void maxApduLength(uint16_t value); - const uint8_t* rfDomainAddress(); - void rfDomainAddress(uint8_t* value); - uint8_t defaultHopCount(); - private: - uint8_t _prgMode = 0; + void individualAddressDuplication(bool value); + bool verifyMode(); + void verifyMode(bool value); + bool progMode(); + void progMode(bool value); + uint16_t manufacturerId(); + void manufacturerId(uint16_t value); + uint32_t bauNumber(); + void bauNumber(uint32_t value); + const uint8_t* orderNumber(); + void orderNumber(const uint8_t* value); + const uint8_t* hardwareType(); + void hardwareType(const uint8_t* value); + uint16_t version(); + void version(uint16_t value); + uint16_t maskVersion(); + void maskVersion(uint16_t value); + uint16_t maxApduLength(); + void maxApduLength(uint16_t value); + const uint8_t* rfDomainAddress(); + void rfDomainAddress(uint8_t* value); + uint8_t defaultHopCount(); + private: + uint8_t _prgMode = 0; #if MASK_VERSION == 0x091A || MASK_VERSION == 0x2920 - uint16_t _ownAddress = 0xFF00; // 15.15.0; couplers have 15.15.0 as default PA + uint16_t _ownAddress = 0xFF00; // 15.15.0; couplers have 15.15.0 as default PA #else - uint16_t _ownAddress = 0xFFFF; // 15.15.255; + uint16_t _ownAddress = 0xFFFF; // 15.15.255; #endif -}; + }; +} \ No newline at end of file diff --git a/src/knx/interface_object/function_property.h b/src/knx/interface_object/function_property.h index ceb6cf27..5a4f78c9 100644 --- a/src/knx/interface_object/function_property.h +++ b/src/knx/interface_object/function_property.h @@ -2,52 +2,55 @@ #include "property.h" -class InterfaceObject; - -template class FunctionProperty : public Property +namespace Knx { - public: - FunctionProperty(T* io, PropertyID id, - void (*commandCallback)(T*, uint8_t*, uint8_t, uint8_t*, uint8_t&), - void (*stateCallback)(T*, uint8_t*, uint8_t, uint8_t*, uint8_t&)) - : Property(id, false, PDT_FUNCTION, 1, ReadLv0 | WriteLv0), _interfaceObject(io), _commandCallback(commandCallback), _stateCallback(stateCallback) - /* max_elements is set to 1, read and write level any value so we use Lv0, see 3.3.7 Application Layer p.68 */ - {} - - uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const override - { - return 0; - } - - uint8_t write(uint16_t start, uint8_t count, const uint8_t* data) override - { - return 0; - } - - void command(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) override - { - if (length == 0 || _commandCallback == nullptr ) + class InterfaceObject; + + template class FunctionProperty : public Property + { + public: + FunctionProperty(T* io, PropertyID id, + void (*commandCallback)(T*, uint8_t*, uint8_t, uint8_t*, uint8_t&), + void (*stateCallback)(T*, uint8_t*, uint8_t, uint8_t*, uint8_t&)) + : Property(id, false, PDT_FUNCTION, 1, ReadLv0 | WriteLv0), _interfaceObject(io), _commandCallback(commandCallback), _stateCallback(stateCallback) + /* max_elements is set to 1, read and write level any value so we use Lv0, see 3.3.7 Application Layer p.68 */ + {} + + uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const override { - resultLength = 0; - return; + return 0; } - _commandCallback(_interfaceObject, data, length, resultData, resultLength); - } + uint8_t write(uint16_t start, uint8_t count, const uint8_t* data) override + { + return 0; + } - void state(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) override - { - if (length == 0 || _stateCallback == nullptr ) + void command(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) override { - resultLength = 0; - return; + if (length == 0 || _commandCallback == nullptr ) + { + resultLength = 0; + return; + } + + _commandCallback(_interfaceObject, data, length, resultData, resultLength); } - _stateCallback(_interfaceObject, data, length, resultData, resultLength); - } + void state(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) override + { + if (length == 0 || _stateCallback == nullptr ) + { + resultLength = 0; + return; + } + + _stateCallback(_interfaceObject, data, length, resultData, resultLength); + } - private: - T* _interfaceObject = nullptr; - void (*_commandCallback)(T*, uint8_t*, uint8_t, uint8_t*, uint8_t&) = nullptr; - void (*_stateCallback)(T*, uint8_t*, uint8_t, uint8_t*, uint8_t&) = nullptr; -}; + private: + T* _interfaceObject = nullptr; + void (*_commandCallback)(T*, uint8_t*, uint8_t, uint8_t*, uint8_t&) = nullptr; + void (*_stateCallback)(T*, uint8_t*, uint8_t, uint8_t*, uint8_t&) = nullptr; + }; +} \ No newline at end of file diff --git a/src/knx/interface_object/group_object_table_object.cpp b/src/knx/interface_object/group_object_table_object.cpp index d1ea9934..a52bed66 100644 --- a/src/knx/interface_object/group_object_table_object.cpp +++ b/src/knx/interface_object/group_object_table_object.cpp @@ -8,128 +8,131 @@ #define LOGGER Logger::logger("GroupObjectTableObject") -GroupObjectTableObject::GroupObjectTableObject(Memory& memory) - : TableObject(memory) +namespace Knx { - Property* properties[] + GroupObjectTableObject::GroupObjectTableObject(Memory& memory) + : TableObject(memory) { - new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_GRP_OBJ_TABLE) - }; - TableObject::initializeProperties(sizeof(properties), properties); -} - -GroupObjectTableObject::~GroupObjectTableObject() -{ - freeGroupObjects(); -} - -uint16_t GroupObjectTableObject::entryCount() -{ - if (loadState() != LS_LOADED) - return 0; + Property* properties[] + { + new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_GRP_OBJ_TABLE) + }; + TableObject::initializeProperties(sizeof(properties), properties); + } - return ntohs(_tableData[0]); -} + GroupObjectTableObject::~GroupObjectTableObject() + { + freeGroupObjects(); + } -GroupObject& GroupObjectTableObject::get(uint16_t asap) -{ - return _groupObjects[asap - 1]; -} + uint16_t GroupObjectTableObject::entryCount() + { + if (loadState() != LS_LOADED) + return 0; -const uint8_t* GroupObjectTableObject::restore(const uint8_t* buffer) -{ - buffer = TableObject::restore(buffer); + return ntohs(_tableData[0]); + } - _tableData = (uint16_t*)data(); - initGroupObjects(); + GroupObject& GroupObjectTableObject::get(uint16_t asap) + { + return _groupObjects[asap - 1]; + } - return buffer; -} + const uint8_t* GroupObjectTableObject::restore(const uint8_t* buffer) + { + buffer = TableObject::restore(buffer); -GroupObject& GroupObjectTableObject::nextUpdatedObject(bool& valid) -{ - static uint16_t startIdx = 1; + _tableData = (uint16_t*)data(); + initGroupObjects(); - uint16_t objCount = entryCount(); + return buffer; + } - for (uint16_t asap = startIdx; asap <= objCount; asap++) + GroupObject& GroupObjectTableObject::nextUpdatedObject(bool& valid) { - GroupObject& go = get(asap); + static uint16_t startIdx = 1; + + uint16_t objCount = entryCount(); - if (go.commFlag() == Updated) + for (uint16_t asap = startIdx; asap <= objCount; asap++) { - go.commFlag(Ok); - startIdx = asap + 1; - valid = true; - return go; + GroupObject& go = get(asap); + + if (go.commFlag() == Updated) + { + go.commFlag(Ok); + startIdx = asap + 1; + valid = true; + return go; + } } + + startIdx = 1; + valid = false; + return get(1); } - startIdx = 1; - valid = false; - return get(1); -} + void GroupObjectTableObject::groupObjects(GroupObject* objs, uint16_t size) + { + freeGroupObjects(); + _groupObjects = objs; + _groupObjectCount = size; + initGroupObjects(); + } -void GroupObjectTableObject::groupObjects(GroupObject* objs, uint16_t size) -{ - freeGroupObjects(); - _groupObjects = objs; - _groupObjectCount = size; - initGroupObjects(); -} + void GroupObjectTableObject::beforeStateChange(LoadState& newState) + { + LOGGER.info("beforeStateChange %s", enum_name(newState)); + TableObject::beforeStateChange(newState); -void GroupObjectTableObject::beforeStateChange(LoadState& newState) -{ - LOGGER.info("beforeStateChange %s", enum_name(newState)); - TableObject::beforeStateChange(newState); + if (newState != LS_LOADED) + return; - if (newState != LS_LOADED) - return; + _tableData = (uint16_t*)data(); - _tableData = (uint16_t*)data(); + if (!initGroupObjects()) + { + newState = LS_ERROR; + TableObject::errorCode(E_SOFTWARE_FAULT); + } + } - if (!initGroupObjects()) + bool GroupObjectTableObject::initGroupObjects() { - newState = LS_ERROR; - TableObject::errorCode(E_SOFTWARE_FAULT); - } -} + if (!_tableData) + return false; -bool GroupObjectTableObject::initGroupObjects() -{ - if (!_tableData) - return false; + freeGroupObjects(); - freeGroupObjects(); + uint16_t goCount = ntohs(_tableData[0]); - uint16_t goCount = ntohs(_tableData[0]); + _groupObjects = new GroupObject[goCount]; + _groupObjectCount = goCount; - _groupObjects = new GroupObject[goCount]; - _groupObjectCount = goCount; + for (uint16_t asap = 1; asap <= goCount; asap++) + { + GroupObject& go = _groupObjects[asap - 1]; + go._asap = asap; + go._table = this; - for (uint16_t asap = 1; asap <= goCount; asap++) - { - GroupObject& go = _groupObjects[asap - 1]; - go._asap = asap; - go._table = this; + go._dataLength = go.goSize(); + size_t sizeInMemory = go.sizeInMemory(); + go._data = new uint8_t[sizeInMemory]; + memset(go._data, 0, sizeInMemory); - go._dataLength = go.goSize(); - size_t sizeInMemory = go.sizeInMemory(); - go._data = new uint8_t[sizeInMemory]; - memset(go._data, 0, sizeInMemory); + if (go.valueReadOnInit()) + go.requestObjectRead(); + } - if (go.valueReadOnInit()) - go.requestObjectRead(); + return true; } - return true; -} - -void GroupObjectTableObject::freeGroupObjects() -{ - if (_groupObjects) - delete[] _groupObjects; + void GroupObjectTableObject::freeGroupObjects() + { + if (_groupObjects) + delete[] _groupObjects; - _groupObjectCount = 0; - _groupObjects = 0; -} + _groupObjectCount = 0; + _groupObjects = 0; + } +} \ No newline at end of file diff --git a/src/knx/interface_object/group_object_table_object.h b/src/knx/interface_object/group_object_table_object.h index 04755051..a4ead133 100644 --- a/src/knx/interface_object/group_object_table_object.h +++ b/src/knx/interface_object/group_object_table_object.h @@ -3,27 +3,30 @@ #include "table_object.h" #include "../group_object/group_object.h" -class GroupObjectTableObject : public TableObject +namespace Knx { - friend class GroupObject; + class GroupObjectTableObject : public TableObject + { + friend class GroupObject; - public: - GroupObjectTableObject(Memory& memory); - virtual ~GroupObjectTableObject(); - uint16_t entryCount(); - GroupObject& get(uint16_t asap); - GroupObject& nextUpdatedObject(bool& valid); - void groupObjects(GroupObject* objs, uint16_t size); + public: + GroupObjectTableObject(Memory& memory); + virtual ~GroupObjectTableObject(); + uint16_t entryCount(); + GroupObject& get(uint16_t asap); + GroupObject& nextUpdatedObject(bool& valid); + void groupObjects(GroupObject* objs, uint16_t size); - const uint8_t* restore(const uint8_t* buffer) override; + const uint8_t* restore(const uint8_t* buffer) override; - protected: - void beforeStateChange(LoadState& newState) override; + protected: + void beforeStateChange(LoadState& newState) override; - private: - void freeGroupObjects(); - bool initGroupObjects(); - uint16_t* _tableData = 0; - GroupObject* _groupObjects = 0; - uint16_t _groupObjectCount = 0; -}; \ No newline at end of file + private: + void freeGroupObjects(); + bool initGroupObjects(); + uint16_t* _tableData = 0; + GroupObject* _groupObjects = 0; + uint16_t _groupObjectCount = 0; + }; +} \ No newline at end of file diff --git a/src/knx/interface_object/interface_object.cpp b/src/knx/interface_object/interface_object.cpp index 3a94f051..051bb8b9 100644 --- a/src/knx/interface_object/interface_object.cpp +++ b/src/knx/interface_object/interface_object.cpp @@ -4,230 +4,233 @@ #include -InterfaceObject::~InterfaceObject() +namespace Knx { - if (_properties != nullptr) - delete[] _properties; -} + InterfaceObject::~InterfaceObject() + { + if (_properties != nullptr) + delete[] _properties; + } -void InterfaceObject::readPropertyDescription(uint8_t& propertyId, uint8_t& propertyIndex, bool& writeEnable, uint8_t& type, uint16_t& numberOfElements, uint8_t& access) -{ - uint8_t count = _propertyCount; + void InterfaceObject::readPropertyDescription(uint8_t& propertyId, uint8_t& propertyIndex, bool& writeEnable, uint8_t& type, uint16_t& numberOfElements, uint8_t& access) + { + uint8_t count = _propertyCount; - numberOfElements = 0; + numberOfElements = 0; - if (_properties == nullptr || count == 0) - return; + if (_properties == nullptr || count == 0) + return; - Property* prop = nullptr; + Property* prop = nullptr; - // from KNX spec. 03.03.07 Application Layer (page 56) - 3.4.3.3 A_PropertyDescription_Read-service - // Summary: either propertyId OR propertyIndex, but not both at the same time - if (propertyId != 0) - { - for (uint8_t i = 0; i < count; i++) + // from KNX spec. 03.03.07 Application Layer (page 56) - 3.4.3.3 A_PropertyDescription_Read-service + // Summary: either propertyId OR propertyIndex, but not both at the same time + if (propertyId != 0) { - Property* p = _properties[i]; + for (uint8_t i = 0; i < count; i++) + { + Property* p = _properties[i]; - if (p->Id() != propertyId) - continue; + if (p->Id() != propertyId) + continue; - prop = p; - propertyIndex = i; - break; + prop = p; + propertyIndex = i; + break; + } } - } - else - { - // If propertyId is zero, propertyIndex shall be used. - // Response: propertyIndex of received A_PropertyDescription_Read - if (propertyIndex < count) + else { - prop = _properties[propertyIndex]; + // If propertyId is zero, propertyIndex shall be used. + // Response: propertyIndex of received A_PropertyDescription_Read + if (propertyIndex < count) + { + prop = _properties[propertyIndex]; + } + } + + if (prop != nullptr) + { + propertyId = prop->Id(); + writeEnable = prop->WriteEnable(); + type = prop->Type(); + numberOfElements = prop->MaxElements(); + access = prop->Access(); } } - if (prop != nullptr) + void InterfaceObject::masterReset(EraseCode eraseCode, uint8_t channel) { - propertyId = prop->Id(); - writeEnable = prop->WriteEnable(); - type = prop->Type(); - numberOfElements = prop->MaxElements(); - access = prop->Access(); + // every interface object shall implement this + // However, for the time being we provide an empty default implementation } -} -void InterfaceObject::masterReset(EraseCode eraseCode, uint8_t channel) -{ - // every interface object shall implement this - // However, for the time being we provide an empty default implementation -} + void InterfaceObject::readPropertyLength(PropertyID id, uint16_t& length) + { + uint8_t count = 1; + uint16_t propval = 0; + readProperty(id, 0, count, (uint8_t*)&propval); -void InterfaceObject::readPropertyLength(PropertyID id, uint16_t& length) -{ - uint8_t count = 1; - uint16_t propval = 0; - readProperty(id, 0, count, (uint8_t*)&propval); + if (count == 0) + { + length = 0; + return; + } - if (count == 0) - { - length = 0; - return; + length = ntohs(propval); } - length = ntohs(propval); -} + void InterfaceObject::readProperty(PropertyID id, uint16_t start, uint8_t& count, uint8_t* data) + { + Property* prop = property(id); -void InterfaceObject::readProperty(PropertyID id, uint16_t start, uint8_t& count, uint8_t* data) -{ - Property* prop = property(id); + if (prop == nullptr) + { + count = 0; + return; + } - if (prop == nullptr) - { - count = 0; - return; + count = prop->read(start, count, data); } - count = prop->read(start, count, data); -} + void InterfaceObject::writeProperty(PropertyID id, uint16_t start, uint8_t* data, uint8_t& count) + { + Property* prop = property(id); -void InterfaceObject::writeProperty(PropertyID id, uint16_t start, uint8_t* data, uint8_t& count) -{ - Property* prop = property(id); + if (prop == nullptr) + { + count = 0; + return; + } - if (prop == nullptr) - { - count = 0; - return; + count = prop->write(start, count, data); } - count = prop->write(start, count, data); -} + uint8_t InterfaceObject::propertySize(PropertyID id) + { + Property* prop = property(id); -uint8_t InterfaceObject::propertySize(PropertyID id) -{ - Property* prop = property(id); + if (prop == nullptr) + { + return 0; + } - if (prop == nullptr) - { - return 0; + return prop->ElementSize(); } - return prop->ElementSize(); -} + void InterfaceObject::command(PropertyID id, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) + { + Property* prop = property(id); -void InterfaceObject::command(PropertyID id, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -{ - Property* prop = property(id); + if (prop == nullptr) + { + resultLength = 0; + return;; + } - if (prop == nullptr) - { - resultLength = 0; - return;; + prop->command(data, length, resultData, resultLength); } - prop->command(data, length, resultData, resultLength); -} + void InterfaceObject::state(PropertyID id, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) + { + Property* prop = property(id); + + if (prop == nullptr) + { + resultLength = 0; + return;; + } -void InterfaceObject::state(PropertyID id, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -{ - Property* prop = property(id); + prop->state(data, length, resultData, resultLength); + } - if (prop == nullptr) + void InterfaceObject::initializeProperties(size_t propertiesSize, Property** properties) { - resultLength = 0; - return;; + _propertyCount = propertiesSize / sizeof(Property*); + _properties = new Property*[_propertyCount]; + memcpy(_properties, properties, propertiesSize); } - prop->state(data, length, resultData, resultLength); -} -void InterfaceObject::initializeProperties(size_t propertiesSize, Property** properties) -{ - _propertyCount = propertiesSize / sizeof(Property*); - _properties = new Property*[_propertyCount]; - memcpy(_properties, properties, propertiesSize); -} - - -Property* InterfaceObject::property(PropertyID id) -{ - for (int i = 0; i < _propertyCount; i++) - if (_properties[i]->Id() == id) - return _properties[i]; + Property* InterfaceObject::property(PropertyID id) + { + for (int i = 0; i < _propertyCount; i++) + if (_properties[i]->Id() == id) + return _properties[i]; - return nullptr; -} + return nullptr; + } -uint8_t* InterfaceObject::save(uint8_t* buffer) -{ - for (int i = 0; i < _propertyCount; i++) + uint8_t* InterfaceObject::save(uint8_t* buffer) { - Property* prop = _properties[i]; + for (int i = 0; i < _propertyCount; i++) + { + Property* prop = _properties[i]; - if (!prop->WriteEnable()) - continue; + if (!prop->WriteEnable()) + continue; - buffer = prop->save(buffer); - } + buffer = prop->save(buffer); + } - return buffer; -} + return buffer; + } -const uint8_t* InterfaceObject::restore(const uint8_t* buffer) -{ - for (int i = 0; i < _propertyCount; i++) + const uint8_t* InterfaceObject::restore(const uint8_t* buffer) { - Property* prop = _properties[i]; + for (int i = 0; i < _propertyCount; i++) + { + Property* prop = _properties[i]; - if (!prop->WriteEnable()) - continue; + if (!prop->WriteEnable()) + continue; + + buffer = prop->restore(buffer); + } - buffer = prop->restore(buffer); + return buffer; } - return buffer; -} + uint16_t InterfaceObject::saveSize() + { + uint16_t size = 0; -uint16_t InterfaceObject::saveSize() -{ - uint16_t size = 0; + for (int i = 0; i < _propertyCount; i++) + { + Property* prop = _properties[i]; - for (int i = 0; i < _propertyCount; i++) - { - Property* prop = _properties[i]; + if (!prop->WriteEnable()) + continue; - if (!prop->WriteEnable()) - continue; + size += prop->saveSize(); + } - size += prop->saveSize(); + return size; } - return size; -} - -const Property* InterfaceObject::property(PropertyID id) const -{ - for (int i = 0; i < _propertyCount; i++) - if (_properties[i]->Id() == id) - return _properties[i]; + const Property* InterfaceObject::property(PropertyID id) const + { + for (int i = 0; i < _propertyCount; i++) + if (_properties[i]->Id() == id) + return _properties[i]; - return nullptr; -} + return nullptr; + } -const uint8_t* InterfaceObject::propertyData(PropertyID id) -{ - DataProperty* prop = (DataProperty*)property(id); - return prop->data(); -} + const uint8_t* InterfaceObject::propertyData(PropertyID id) + { + DataProperty* prop = (DataProperty*)property(id); + return prop->data(); + } -const uint8_t* InterfaceObject::propertyData(PropertyID id, uint16_t elementIndex) -{ - DataProperty* prop = (DataProperty*)property(id); - return prop->data(elementIndex); -} + const uint8_t* InterfaceObject::propertyData(PropertyID id, uint16_t elementIndex) + { + DataProperty* prop = (DataProperty*)property(id); + return prop->data(elementIndex); + } +} \ No newline at end of file diff --git a/src/knx/interface_object/interface_object.h b/src/knx/interface_object/interface_object.h index 1de2a859..efbebb7c 100644 --- a/src/knx/interface_object/interface_object.h +++ b/src/knx/interface_object/interface_object.h @@ -9,205 +9,208 @@ #include -/** Enum for the type of an interface object. See Section 2.2 of knx:3/7/3 */ -enum ObjectType +namespace Knx { - /** Device object. */ - OT_DEVICE = 0, - - /** Address table object. */ - OT_ADDR_TABLE = 1, - - /** Association table object. */ - OT_ASSOC_TABLE = 2, - - /** Application program object. */ - OT_APPLICATION_PROG = 3, - - /** Interface program object. */ - OT_INTERFACE_PROG = 4, - - /** KNX - Object Associationtable. */ - OT_OJB_ASSOC_TABLE = 5, - - /** Router Object */ - OT_ROUTER = 6, - - /** LTE Address Routing Table Object */ - OT_LTE_ADDR_ROUTING_TABLE = 7, - - /** cEMI Server Object */ - OT_CEMI_SERVER = 8, - - /** Group Object Table Object */ - OT_GRP_OBJ_TABLE = 9, - - /** Polling Master */ - OT_POLLING_MASTER = 10, - - /** KNXnet/IP Parameter Object */ - OT_IP_PARAMETER = 11, - - /** Reserved. Shall not be used. */ - OT_RESERVED = 12, - - /** File Server Object */ - OT_FILE_SERVER = 13, - - /** Security Interface Object */ - OT_SECURITY = 17, - - /** RF Medium Object */ - OT_RF_MEDIUM = 19, - - /** Dummy so this enum is 16bit */ - OT_DUMMY = 0xFFFF -}; - -/** - * This class represents and interface object. See section 4 of @cite knx:3/4/1. - */ -class InterfaceObject : public SaveRestore -{ - public: - /** - * Destructor - */ - virtual ~InterfaceObject(); - /** - * Read length of a property of the interface object. See section 4.8.4.2 of @cite knx:3/4/1. - * - * @param id id of the property to read - * - * @param[out] length length of the requested property - */ - virtual void readPropertyLength(PropertyID id, uint16_t& length); - /** - * Read a property of the interface object. See section 4.8.4.2 of @cite knx:3/4/1. - * - * @param id id of the property to read - * - * @param start (for properties with multiple values) at which element should we start - * - * @param[in, out] count how many values should be read. If there is a problem (e.g. property does not exist) - * this value is set to 0. - * - * @param[out] data The requested data of the property. - */ - virtual void readProperty(PropertyID id, uint16_t start, uint8_t& count, uint8_t* data); - /** - * Write property of the interface object. If the interface object does not have the property this - * method does nothing. See section 4.8.4.4 of @cite knx:3/4/1. - * - * @param id id of the property to write - * - * @param start (for properties with multiple values) at which element should we start - * - * @param[in, out] count how many values should be written. If there is a problem (e.g. property does not exist) - * this value is set to 0. - * - * @param[in] data The data that should be written. - */ - virtual void writeProperty(PropertyID id, uint16_t start, uint8_t* data, uint8_t& count); - /** - * Gets the size of of property in bytes. - * - * @param id of the property to get the size of - * - * @returns the size in byte or 0 if the interface object does not have the property - */ - virtual uint8_t propertySize(PropertyID id); - /** - * Call command of a function property of the interface object. Property type must be PDT_FUNCTION - * - * @param id id of the property to call - * - * @param[in] length The size of the data buffer - * - * @param[in] data The argument data for the function - * - * @param[out] resultLength The size of the result data buffer - * - * @param[out] resultData The result data for the function - */ - virtual void command(PropertyID id, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength); - /** - * Get state of a function property of the interface object. Property type must be PDT_FUNCTION - * - * @param id id of the property to call - * - * @param[in] length The size of the data buffer - * - * @param[in] data The argument data for the function - * - * @param[out] resultLength The size of the result data buffer - * - * @param[out] resultData The result data for the function - */ - virtual void state(PropertyID id, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength); - /** - * Read the Description of a property of the interface object. The output parameters are only valid if nuberOfElements is not zero. - * - * @param[in,out] propertyId The id of the property of which to read the description of. If this parameter is not zero - * propertyIndex paramter is ignored as input and the corrrect index of the property is written to it. If this - * parameter is zero the ::PropertyID of the property specified by propertyIndex is written to it. - * - * @param[in,out] propertyIndex The index of the property of the interface object of which to read the description of. - * only used for input if propertyId is not set. Otherwise the index of the property specified by propertyId is written to it. - * - * @param[out] writeEnable Can the property be written to. - * - * @param[out] type the ::PropertyDataType of the property - * - * @param[out] numberOfElements the number of elements of the property. Zero if the interface object does not have the requested property. - * - * @param[out] access the ::AccessLevel necessary to read/write the property. - */ - void readPropertyDescription(uint8_t& propertyId, uint8_t& propertyIndex, bool& writeEnable, uint8_t& type, uint16_t& numberOfElements, uint8_t& access); - - // every interface object shall implement this - // However, for the time being we provide an empty default implementation - virtual void masterReset(EraseCode eraseCode, uint8_t channel); - - /** - * Gets property with PropertyID id if it exists and nullptr otherwise. - */ - Property* property(PropertyID id); - - template - T propertyValue(PropertyID id) - { - const Property* prop = property(id); - - T value = 0; - prop->read(value); - return value; - } - - template - void propertyValue(PropertyID id, T value) - { - Property* prop = property(id); - prop->write(value); - } - - const uint8_t* propertyData(PropertyID id); - const uint8_t* propertyData(PropertyID id, uint16_t elementIndex); - /** - * Gets const property with PropertyID id if it exists and nullptr otherwise. - */ - const Property* property(PropertyID id) const; - - uint8_t* save(uint8_t* buffer) override; - const uint8_t* restore(const uint8_t* buffer) override; - uint16_t saveSize() override; - - protected: - /** - * Intializes the Property-array the the supplied values. - */ - virtual void initializeProperties(size_t propertiesSize, Property** properties); - - Property** _properties = nullptr; - uint8_t _propertyCount = 0; -}; + /** Enum for the type of an interface object. See Section 2.2 of knx:3/7/3 */ + enum ObjectType + { + /** Device object. */ + OT_DEVICE = 0, + + /** Address table object. */ + OT_ADDR_TABLE = 1, + + /** Association table object. */ + OT_ASSOC_TABLE = 2, + + /** Application program object. */ + OT_APPLICATION_PROG = 3, + + /** Interface program object. */ + OT_INTERFACE_PROG = 4, + + /** KNX - Object Associationtable. */ + OT_OJB_ASSOC_TABLE = 5, + + /** Router Object */ + OT_ROUTER = 6, + + /** LTE Address Routing Table Object */ + OT_LTE_ADDR_ROUTING_TABLE = 7, + + /** cEMI Server Object */ + OT_CEMI_SERVER = 8, + + /** Group Object Table Object */ + OT_GRP_OBJ_TABLE = 9, + + /** Polling Master */ + OT_POLLING_MASTER = 10, + + /** KNXnet/IP Parameter Object */ + OT_IP_PARAMETER = 11, + + /** Reserved. Shall not be used. */ + OT_RESERVED = 12, + + /** File Server Object */ + OT_FILE_SERVER = 13, + + /** Security Interface Object */ + OT_SECURITY = 17, + + /** RF Medium Object */ + OT_RF_MEDIUM = 19, + + /** Dummy so this enum is 16bit */ + OT_DUMMY = 0xFFFF + }; + + /** + * This class represents and interface object. See section 4 of @cite knx:3/4/1. + */ + class InterfaceObject : public SaveRestore + { + public: + /** + * Destructor + */ + virtual ~InterfaceObject(); + /** + * Read length of a property of the interface object. See section 4.8.4.2 of @cite knx:3/4/1. + * + * @param id id of the property to read + * + * @param[out] length length of the requested property + */ + virtual void readPropertyLength(PropertyID id, uint16_t& length); + /** + * Read a property of the interface object. See section 4.8.4.2 of @cite knx:3/4/1. + * + * @param id id of the property to read + * + * @param start (for properties with multiple values) at which element should we start + * + * @param[in, out] count how many values should be read. If there is a problem (e.g. property does not exist) + * this value is set to 0. + * + * @param[out] data The requested data of the property. + */ + virtual void readProperty(PropertyID id, uint16_t start, uint8_t& count, uint8_t* data); + /** + * Write property of the interface object. If the interface object does not have the property this + * method does nothing. See section 4.8.4.4 of @cite knx:3/4/1. + * + * @param id id of the property to write + * + * @param start (for properties with multiple values) at which element should we start + * + * @param[in, out] count how many values should be written. If there is a problem (e.g. property does not exist) + * this value is set to 0. + * + * @param[in] data The data that should be written. + */ + virtual void writeProperty(PropertyID id, uint16_t start, uint8_t* data, uint8_t& count); + /** + * Gets the size of of property in bytes. + * + * @param id of the property to get the size of + * + * @returns the size in byte or 0 if the interface object does not have the property + */ + virtual uint8_t propertySize(PropertyID id); + /** + * Call command of a function property of the interface object. Property type must be PDT_FUNCTION + * + * @param id id of the property to call + * + * @param[in] length The size of the data buffer + * + * @param[in] data The argument data for the function + * + * @param[out] resultLength The size of the result data buffer + * + * @param[out] resultData The result data for the function + */ + virtual void command(PropertyID id, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength); + /** + * Get state of a function property of the interface object. Property type must be PDT_FUNCTION + * + * @param id id of the property to call + * + * @param[in] length The size of the data buffer + * + * @param[in] data The argument data for the function + * + * @param[out] resultLength The size of the result data buffer + * + * @param[out] resultData The result data for the function + */ + virtual void state(PropertyID id, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength); + /** + * Read the Description of a property of the interface object. The output parameters are only valid if nuberOfElements is not zero. + * + * @param[in,out] propertyId The id of the property of which to read the description of. If this parameter is not zero + * propertyIndex paramter is ignored as input and the corrrect index of the property is written to it. If this + * parameter is zero the ::PropertyID of the property specified by propertyIndex is written to it. + * + * @param[in,out] propertyIndex The index of the property of the interface object of which to read the description of. + * only used for input if propertyId is not set. Otherwise the index of the property specified by propertyId is written to it. + * + * @param[out] writeEnable Can the property be written to. + * + * @param[out] type the ::PropertyDataType of the property + * + * @param[out] numberOfElements the number of elements of the property. Zero if the interface object does not have the requested property. + * + * @param[out] access the ::AccessLevel necessary to read/write the property. + */ + void readPropertyDescription(uint8_t& propertyId, uint8_t& propertyIndex, bool& writeEnable, uint8_t& type, uint16_t& numberOfElements, uint8_t& access); + + // every interface object shall implement this + // However, for the time being we provide an empty default implementation + virtual void masterReset(EraseCode eraseCode, uint8_t channel); + + /** + * Gets property with PropertyID id if it exists and nullptr otherwise. + */ + Property* property(PropertyID id); + + template + T propertyValue(PropertyID id) + { + const Property* prop = property(id); + + T value = 0; + prop->read(value); + return value; + } + + template + void propertyValue(PropertyID id, T value) + { + Property* prop = property(id); + prop->write(value); + } + + const uint8_t* propertyData(PropertyID id); + const uint8_t* propertyData(PropertyID id, uint16_t elementIndex); + /** + * Gets const property with PropertyID id if it exists and nullptr otherwise. + */ + const Property* property(PropertyID id) const; + + uint8_t* save(uint8_t* buffer) override; + const uint8_t* restore(const uint8_t* buffer) override; + uint16_t saveSize() override; + + protected: + /** + * Intializes the Property-array the the supplied values. + */ + virtual void initializeProperties(size_t propertiesSize, Property** properties); + + Property** _properties = nullptr; + uint8_t _propertyCount = 0; + }; +} \ No newline at end of file diff --git a/src/knx/interface_object/property.cpp b/src/knx/interface_object/property.cpp index 7e618fa6..773f220b 100644 --- a/src/knx/interface_object/property.cpp +++ b/src/knx/interface_object/property.cpp @@ -4,863 +4,871 @@ #include -PropertyID Property::Id() const +namespace Knx { - return _id; -} + PropertyID Property::Id() const + { + return _id; + } -bool Property::WriteEnable() const -{ - return _writeEnable; -} + bool Property::WriteEnable() const + { + return _writeEnable; + } -PropertyDataType Property::Type() const -{ - return _type; -} + PropertyDataType Property::Type() const + { + return _type; + } -uint16_t Property::MaxElements() const -{ - return _maxElements; -} + uint16_t Property::MaxElements() const + { + return _maxElements; + } -uint8_t Property::Access() const -{ - return _access; -} + uint8_t Property::Access() const + { + return _access; + } -uint8_t Property::ElementSize() const -{ - switch (_type) + uint8_t Property::ElementSize() const { - case PDT_CHAR: - case PDT_CONTROL: // is actually 10 if written, but this is always handled with a callback - case PDT_GENERIC_01: - case PDT_UNSIGNED_CHAR: - case PDT_BITSET8: - case PDT_BINARY_INFORMATION: // only 1 bit really - case PDT_ENUM8: - case PDT_SCALING: - return 1; - - case PDT_GENERIC_02: - case PDT_INT: - case PDT_KNX_FLOAT: - case PDT_UNSIGNED_INT: - case PDT_VERSION: - case PDT_BITSET16: - return 2; - - case PDT_DATE: - case PDT_ESCAPE: - case PDT_FUNCTION: - case PDT_GENERIC_03: - case PDT_NE_FL: - case PDT_NE_VL: - case PDT_POLL_GROUP_SETTING: - case PDT_TIME: - case PDT_UTF8: - return 3; - - case PDT_FLOAT: - case PDT_GENERIC_04: - case PDT_LONG: - case PDT_UNSIGNED_LONG: - return 4; - - case PDT_GENERIC_05: - case PDT_SHORT_CHAR_BLOCK: - return 5; - - case PDT_GENERIC_06: - case PDT_ALARM_INFO: - return 6; - - case PDT_GENERIC_07: - return 7; - - case PDT_DATE_TIME: - case PDT_DOUBLE: - case PDT_GENERIC_08: - return 8; - - case PDT_GENERIC_09: - return 9; - - case PDT_CHAR_BLOCK: - case PDT_GENERIC_10: - return 10; - - case PDT_GENERIC_11: - return 11; - - case PDT_GENERIC_12: - return 12; - - case PDT_GENERIC_13: - return 13; - - case PDT_GENERIC_14: - return 14; - - case PDT_GENERIC_15: - return 15; - - case PDT_GENERIC_16: - return 16; - - case PDT_GENERIC_17: - return 17; - - case PDT_GENERIC_18: - return 18; - - case PDT_GENERIC_19: - return 19; - - case PDT_GENERIC_20: - return 20; - - default: - return 0; + switch (_type) + { + case PDT_CHAR: + case PDT_CONTROL: // is actually 10 if written, but this is always handled with a callback + case PDT_GENERIC_01: + case PDT_UNSIGNED_CHAR: + case PDT_BITSET8: + case PDT_BINARY_INFORMATION: // only 1 bit really + case PDT_ENUM8: + case PDT_SCALING: + return 1; + + case PDT_GENERIC_02: + case PDT_INT: + case PDT_KNX_FLOAT: + case PDT_UNSIGNED_INT: + case PDT_VERSION: + case PDT_BITSET16: + return 2; + + case PDT_DATE: + case PDT_ESCAPE: + case PDT_FUNCTION: + case PDT_GENERIC_03: + case PDT_NE_FL: + case PDT_NE_VL: + case PDT_POLL_GROUP_SETTING: + case PDT_TIME: + case PDT_UTF8: + return 3; + + case PDT_FLOAT: + case PDT_GENERIC_04: + case PDT_LONG: + case PDT_UNSIGNED_LONG: + return 4; + + case PDT_GENERIC_05: + case PDT_SHORT_CHAR_BLOCK: + return 5; + + case PDT_GENERIC_06: + case PDT_ALARM_INFO: + return 6; + + case PDT_GENERIC_07: + return 7; + + case PDT_DATE_TIME: + case PDT_DOUBLE: + case PDT_GENERIC_08: + return 8; + + case PDT_GENERIC_09: + return 9; + + case PDT_CHAR_BLOCK: + case PDT_GENERIC_10: + return 10; + + case PDT_GENERIC_11: + return 11; + + case PDT_GENERIC_12: + return 12; + + case PDT_GENERIC_13: + return 13; + + case PDT_GENERIC_14: + return 14; + + case PDT_GENERIC_15: + return 15; + + case PDT_GENERIC_16: + return 16; + + case PDT_GENERIC_17: + return 17; + + case PDT_GENERIC_18: + return 18; + + case PDT_GENERIC_19: + return 19; + + case PDT_GENERIC_20: + return 20; + + default: + return 0; + } } -} -Property::Property(PropertyID id, bool writeEnable, PropertyDataType type, - uint16_t maxElements, uint8_t access) - : _id(id), _writeEnable(writeEnable), _type(type), _maxElements(maxElements), _access(access) -{} + Property::Property(PropertyID id, bool writeEnable, PropertyDataType type, + uint16_t maxElements, uint8_t access) + : _id(id), _writeEnable(writeEnable), _type(type), _maxElements(maxElements), _access(access) + {} -Property::~Property() -{} + Property::~Property() + {} -uint8_t Property::read(uint8_t& value) const -{ - if (ElementSize() != 1) - return 0; + uint8_t Property::read(uint8_t& value) const + { + if (ElementSize() != 1) + return 0; - return read(1, 1, &value); -} + return read(1, 1, &value); + } -uint8_t Property::read(uint16_t& value) const -{ - if (ElementSize() != 2) - return 0; + uint8_t Property::read(uint16_t& value) const + { + if (ElementSize() != 2) + return 0; - uint8_t data[2]; - uint8_t count = read(1, 1, data); + uint8_t data[2]; + uint8_t count = read(1, 1, data); - if (count > 0) - { - popWord(value, data); + if (count > 0) + { + popWord(value, data); + } + + return count; } - return count; -} + uint8_t Property::read(uint32_t& value) const + { + if (ElementSize() != 4) + return 0; -uint8_t Property::read(uint32_t& value) const -{ - if (ElementSize() != 4) - return 0; + uint8_t data[4]; + uint8_t count = read(1, 1, data); - uint8_t data[4]; - uint8_t count = read(1, 1, data); + if (count > 0) + { + popInt(value, data); + } - if (count > 0) - { - popInt(value, data); + return count; } - return count; -} - -uint8_t Property::read(uint8_t* value) const -{ - return read(1, 1, value); -} + uint8_t Property::read(uint8_t* value) const + { + return read(1, 1, value); + } -uint8_t Property::write(uint8_t value) -{ - if (ElementSize() != 1) - return 0; + uint8_t Property::write(uint8_t value) + { + if (ElementSize() != 1) + return 0; - return write(1, 1, &value); -} + return write(1, 1, &value); + } -uint8_t Property::write(uint16_t value) -{ - if (ElementSize() != 2) - return 0; + uint8_t Property::write(uint16_t value) + { + if (ElementSize() != 2) + return 0; - uint8_t data[2]; - pushWord(value, data); - return write(1, 1, data); -} + uint8_t data[2]; + pushWord(value, data); + return write(1, 1, data); + } -uint8_t Property::write(uint32_t value) -{ - if (ElementSize() != 4) - return 0; + uint8_t Property::write(uint32_t value) + { + if (ElementSize() != 4) + return 0; - uint8_t data[4]; - pushInt(value, data); - return write(1, 1, data); -} + uint8_t data[4]; + pushInt(value, data); + return write(1, 1, data); + } -uint8_t Property::write(const uint8_t* value) -{ - return write(1, 1, value); -} + uint8_t Property::write(const uint8_t* value) + { + return write(1, 1, value); + } -uint8_t Property::write(uint16_t position, uint16_t value) -{ - if (ElementSize() != 2) - return 0; + uint8_t Property::write(uint16_t position, uint16_t value) + { + if (ElementSize() != 2) + return 0; - uint8_t data[2]; - pushWord(value, data); - return write(position, 1, data); -} + uint8_t data[2]; + pushWord(value, data); + return write(position, 1, data); + } -void Property::command(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -{ - (void)data; - (void)length; - (void)resultData; - resultLength = 0; -} + void Property::command(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) + { + (void)data; + (void)length; + (void)resultData; + resultLength = 0; + } -void Property::state(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -{ - (void)data; - (void)length; - (void)resultData; - resultLength = 0; -} + void Property::state(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) + { + (void)data; + (void)length; + (void)resultData; + resultLength = 0; + } #ifndef KNX_NO_PRINT -const char* enum_name(const PropertyDataType enum_val) -{ - switch (enum_val) + const char* enum_name(const PropertyDataType enum_val) { - case PDT_CONTROL: - return "PDT_CONTROL"; + switch (enum_val) + { + case PDT_CONTROL: + return "PDT_CONTROL"; - case PDT_CHAR: - return "PDT_CHAR"; + case PDT_CHAR: + return "PDT_CHAR"; - case PDT_UNSIGNED_CHAR: - return "PDT_UNSIGNED_CHAR"; + case PDT_UNSIGNED_CHAR: + return "PDT_UNSIGNED_CHAR"; - case PDT_INT: - return "PDT_INT"; + case PDT_INT: + return "PDT_INT"; - case PDT_UNSIGNED_INT: - return "PDT_UNSIGNED_INT"; + case PDT_UNSIGNED_INT: + return "PDT_UNSIGNED_INT"; - case PDT_KNX_FLOAT: - return "PDT_KNX_FLOAT"; + case PDT_KNX_FLOAT: + return "PDT_KNX_FLOAT"; - case PDT_DATE: - return "PDT_DATE"; + case PDT_DATE: + return "PDT_DATE"; - case PDT_TIME: - return "PDT_TIME"; + case PDT_TIME: + return "PDT_TIME"; - case PDT_LONG: - return "PDT_LONG"; + case PDT_LONG: + return "PDT_LONG"; - case PDT_UNSIGNED_LONG: - return "PDT_UNSIGNED_LONG"; + case PDT_UNSIGNED_LONG: + return "PDT_UNSIGNED_LONG"; - case PDT_FLOAT: - return "PDT_FLOAT"; + case PDT_FLOAT: + return "PDT_FLOAT"; - case PDT_DOUBLE: - return "PDT_DOUBLE"; + case PDT_DOUBLE: + return "PDT_DOUBLE"; - case PDT_CHAR_BLOCK: - return "PDT_CHAR_BLOCK"; + case PDT_CHAR_BLOCK: + return "PDT_CHAR_BLOCK"; - case PDT_POLL_GROUP_SETTING: - return "PDT_POLL_GROUP_SETTING"; + case PDT_POLL_GROUP_SETTING: + return "PDT_POLL_GROUP_SETTING"; - case PDT_SHORT_CHAR_BLOCK: - return "PDT_SHORT_CHAR_BLOCK"; + case PDT_SHORT_CHAR_BLOCK: + return "PDT_SHORT_CHAR_BLOCK"; - case PDT_DATE_TIME: - return "PDT_DATE_TIME"; + case PDT_DATE_TIME: + return "PDT_DATE_TIME"; - case PDT_VARIABLE_LENGTH: - return "PDT_VARIABLE_LENGTH"; + case PDT_VARIABLE_LENGTH: + return "PDT_VARIABLE_LENGTH"; - case PDT_GENERIC_01: - return "PDT_GENERIC_01"; + case PDT_GENERIC_01: + return "PDT_GENERIC_01"; - case PDT_GENERIC_02: - return "PDT_GENERIC_02"; + case PDT_GENERIC_02: + return "PDT_GENERIC_02"; - case PDT_GENERIC_03: - return "PDT_GENERIC_03"; + case PDT_GENERIC_03: + return "PDT_GENERIC_03"; - case PDT_GENERIC_04: - return "PDT_GENERIC_04"; + case PDT_GENERIC_04: + return "PDT_GENERIC_04"; - case PDT_GENERIC_05: - return "PDT_GENERIC_05"; + case PDT_GENERIC_05: + return "PDT_GENERIC_05"; - case PDT_GENERIC_06: - return "PDT_GENERIC_06"; + case PDT_GENERIC_06: + return "PDT_GENERIC_06"; - case PDT_GENERIC_07: - return "PDT_GENERIC_07"; + case PDT_GENERIC_07: + return "PDT_GENERIC_07"; - case PDT_GENERIC_08: - return "PDT_GENERIC_08"; + case PDT_GENERIC_08: + return "PDT_GENERIC_08"; - case PDT_GENERIC_09: - return "PDT_GENERIC_09"; + case PDT_GENERIC_09: + return "PDT_GENERIC_09"; - case PDT_GENERIC_10: - return "PDT_GENERIC_10"; + case PDT_GENERIC_10: + return "PDT_GENERIC_10"; - case PDT_GENERIC_11: - return "PDT_GENERIC_11"; + case PDT_GENERIC_11: + return "PDT_GENERIC_11"; - case PDT_GENERIC_12: - return "PDT_GENERIC_12"; + case PDT_GENERIC_12: + return "PDT_GENERIC_12"; - case PDT_GENERIC_13: - return "PDT_GENERIC_13"; + case PDT_GENERIC_13: + return "PDT_GENERIC_13"; - case PDT_GENERIC_14: - return "PDT_GENERIC_14"; + case PDT_GENERIC_14: + return "PDT_GENERIC_14"; - case PDT_GENERIC_15: - return "PDT_GENERIC_15"; + case PDT_GENERIC_15: + return "PDT_GENERIC_15"; - case PDT_GENERIC_16: - return "PDT_GENERIC_16"; + case PDT_GENERIC_16: + return "PDT_GENERIC_16"; - case PDT_GENERIC_17: - return "PDT_GENERIC_17"; + case PDT_GENERIC_17: + return "PDT_GENERIC_17"; - case PDT_GENERIC_18: - return "PDT_GENERIC_18"; + case PDT_GENERIC_18: + return "PDT_GENERIC_18"; - case PDT_GENERIC_19: - return "PDT_GENERIC_19"; + case PDT_GENERIC_19: + return "PDT_GENERIC_19"; - case PDT_GENERIC_20: - return "PDT_GENERIC_20"; + case PDT_GENERIC_20: + return "PDT_GENERIC_20"; - case PDT_UTF8: - return "PDT_UTF8"; + case PDT_UTF8: + return "PDT_UTF8"; - case PDT_VERSION: - return "PDT_VERSION"; + case PDT_VERSION: + return "PDT_VERSION"; - case PDT_ALARM_INFO: - return "PDT_ALARM_INFO"; + case PDT_ALARM_INFO: + return "PDT_ALARM_INFO"; - case PDT_BINARY_INFORMATION: - return "PDT_BINARY_INFORMATION"; + case PDT_BINARY_INFORMATION: + return "PDT_BINARY_INFORMATION"; - case PDT_BITSET8: - return "PDT_BITSET8"; + case PDT_BITSET8: + return "PDT_BITSET8"; - case PDT_BITSET16: - return "PDT_BITSET16"; + case PDT_BITSET16: + return "PDT_BITSET16"; - case PDT_ENUM8: - return "PDT_ENUM8"; + case PDT_ENUM8: + return "PDT_ENUM8"; - case PDT_SCALING: - return "PDT_SCALING"; + case PDT_SCALING: + return "PDT_SCALING"; - case PDT_NE_VL: - return "PDT_NE_VL"; + case PDT_NE_VL: + return "PDT_NE_VL"; - case PDT_NE_FL: - return "PDT_NE_FL"; + case PDT_NE_FL: + return "PDT_NE_FL"; - case PDT_FUNCTION: - return "PDT_FUNCTION"; + case PDT_FUNCTION: + return "PDT_FUNCTION"; - case PDT_ESCAPE: - return "PDT_ESCAPE"; - } + case PDT_ESCAPE: + return "PDT_ESCAPE"; + } - return ""; -} + return ""; + } -const char* enum_name(const PropertyID enum_val) -{ - switch (enum_val) + const char* enum_name(const PropertyID enum_val) { - case PID_OBJECT_TYPE: - return "PID_OBJECT_TYPE"; + switch (enum_val) + { + case PID_OBJECT_TYPE: + return "PID_OBJECT_TYPE"; - case PID_LOAD_STATE_CONTROL: - return "PID_LOAD_STATE_CONTROL"; + case PID_LOAD_STATE_CONTROL: + return "PID_LOAD_STATE_CONTROL"; - case PID_RUN_STATE_CONTROL: - return "PID_RUN_STATE_CONTROL"; + case PID_RUN_STATE_CONTROL: + return "PID_RUN_STATE_CONTROL"; - case PID_TABLE_REFERENCE: - return "PID_TABLE_REFERENCE"; + case PID_TABLE_REFERENCE: + return "PID_TABLE_REFERENCE"; - case PID_SERVICE_CONTROL: - return "PID_SERVICE_CONTROL"; + case PID_SERVICE_CONTROL: + return "PID_SERVICE_CONTROL"; - case PID_FIRMWARE_REVISION: - return "PID_FIRMWARE_REVISION"; + case PID_FIRMWARE_REVISION: + return "PID_FIRMWARE_REVISION"; - case PID_SERIAL_NUMBER: - return "PID_SERIAL_NUMBER"; + case PID_SERIAL_NUMBER: + return "PID_SERIAL_NUMBER"; - case PID_MANUFACTURER_ID: - return "PID_MANUFACTURER_ID"; + case PID_MANUFACTURER_ID: + return "PID_MANUFACTURER_ID"; - case PID_PROG_VERSION: - return "PID_PROG_VERSION"; + case PID_PROG_VERSION: + return "PID_PROG_VERSION"; - case PID_DEVICE_CONTROL: - return "PID_DEVICE_CONTROL"; + case PID_DEVICE_CONTROL: + return "PID_DEVICE_CONTROL"; - case PID_ORDER_INFO: - return "PID_ORDER_INFO"; + case PID_ORDER_INFO: + return "PID_ORDER_INFO"; - case PID_PEI_TYPE: - return "PID_PEI_TYPE"; + case PID_PEI_TYPE: + return "PID_PEI_TYPE"; - case PID_PORT_CONFIGURATION: - return "PID_PORT_CONFIGURATION"; + case PID_PORT_CONFIGURATION: + return "PID_PORT_CONFIGURATION"; - case PID_TABLE: - return "PID_TABLE"; + case PID_TABLE: + return "PID_TABLE"; - case PID_VERSION: - return "PID_VERSION"; + case PID_VERSION: + return "PID_VERSION"; - case PID_MCB_TABLE: - return "PID_MCB_TABLE"; + case PID_MCB_TABLE: + return "PID_MCB_TABLE"; - case PID_ERROR_CODE: - return "PID_ERROR_CODE"; + case PID_ERROR_CODE: + return "PID_ERROR_CODE"; - case PID_OBJECT_INDEX: - return "PID_OBJECT_INDEX"; + case PID_OBJECT_INDEX: + return "PID_OBJECT_INDEX"; - case PID_DOWNLOAD_COUNTER: - return "PID_DOWNLOAD_COUNTER"; + case PID_DOWNLOAD_COUNTER: + return "PID_DOWNLOAD_COUNTER"; - case PID_ROUTING_COUNT: - return "PID_ROUTING_COUNT/RF_MULTI_TYPE/PROJECT_INSTALLATION_ID"; + case PID_ROUTING_COUNT: + return "PID_ROUTING_COUNT/RF_MULTI_TYPE/PROJECT_INSTALLATION_ID"; - case PID_PROG_MODE: - return "PID_PROG_MODE/CURRENT_IP_ASSIGNMENT_METHOD"; + case PID_PROG_MODE: + return "PID_PROG_MODE/CURRENT_IP_ASSIGNMENT_METHOD"; - case PID_MAX_APDU_LENGTH: - return "PID_MAX_APDU_LENGTH/RF_DOMAIN_ADDRESS/IP_CAPABILITIES"; + case PID_MAX_APDU_LENGTH: + return "PID_MAX_APDU_LENGTH/RF_DOMAIN_ADDRESS/IP_CAPABILITIES"; - case PID_SUBNET_ADDR: - return "PID_SUBNET_ADDR/RF_RETRANSMITTER"; + case PID_SUBNET_ADDR: + return "PID_SUBNET_ADDR/RF_RETRANSMITTER"; - case PID_DEVICE_ADDR: - return "PID_DEVICE_ADDR/RF_FILTERING_MODE_SUPPORT"; + case PID_DEVICE_ADDR: + return "PID_DEVICE_ADDR/RF_FILTERING_MODE_SUPPORT"; - case PID_IO_LIST: - return "PID_IO_LIST/PRIORITY_FIFO_ENABLED"; + case PID_IO_LIST: + return "PID_IO_LIST/PRIORITY_FIFO_ENABLED"; - case PID_HARDWARE_TYPE: - return "PID_HARDWARE_TYPE"; + case PID_HARDWARE_TYPE: + return "PID_HARDWARE_TYPE"; - case PID_RF_DOMAIN_ADDRESS_CEMI_SERVER: - return "PID_RF_DOMAIN_ADDRESS_CEMI_SERVER"; + case PID_RF_DOMAIN_ADDRESS_CEMI_SERVER: + return "PID_RF_DOMAIN_ADDRESS_CEMI_SERVER"; - case PID_DEVICE_DESCRIPTOR: - return "PID_DEVICE_DESCRIPTOR"; + case PID_DEVICE_DESCRIPTOR: + return "PID_DEVICE_DESCRIPTOR"; - case PID_RF_FILTERING_MODE_SELECT: - return "PID_RF_FILTERING_MODE_SELECT"; + case PID_RF_FILTERING_MODE_SELECT: + return "PID_RF_FILTERING_MODE_SELECT"; - case PID_RF_BIDIR_TIMEOUT: - return "PID_RF_BIDIR_TIMEOUT"; + case PID_RF_BIDIR_TIMEOUT: + return "PID_RF_BIDIR_TIMEOUT"; - case PID_RF_DIAG_SA_FILTER_TABLE: - return "PID_RF_DIAG_SA_FILTER_TABLE"; + case PID_RF_DIAG_SA_FILTER_TABLE: + return "PID_RF_DIAG_SA_FILTER_TABLE"; - case PID_RF_DIAG_BUDGET_TABLE: - return "PID_RF_DIAG_BUDGET_TABLE"; + case PID_RF_DIAG_BUDGET_TABLE: + return "PID_RF_DIAG_BUDGET_TABLE"; - case PID_RF_DIAG_PROBE: - return "PID_RF_DIAG_PROBE"; + case PID_RF_DIAG_PROBE: + return "PID_RF_DIAG_PROBE"; - case PID_KNX_INDIVIDUAL_ADDRESS: - return "PID_KNX_INDIVIDUAL_ADDRESS"; + case PID_KNX_INDIVIDUAL_ADDRESS: + return "PID_KNX_INDIVIDUAL_ADDRESS"; - case PID_ADDITIONAL_INDIVIDUAL_ADDRESSES: - return "PID_ADDITIONAL_INDIVIDUAL_ADDRESSES"; + case PID_ADDITIONAL_INDIVIDUAL_ADDRESSES: + return "PID_ADDITIONAL_INDIVIDUAL_ADDRESSES"; - case PID_IP_ASSIGNMENT_METHOD: - return "PID_IP_ASSIGNMENT_METHOD"; -/* - case PID_CURRENT_IP_ADDRESS: - return "PID_CURRENT_IP_ADDRESS"; + case PID_IP_ASSIGNMENT_METHOD: + return "PID_IP_ASSIGNMENT_METHOD"; - case PID_CURRENT_SUBNET_MASK: - return "PID_CURRENT_SUBNET_MASK"; + /* + case PID_CURRENT_IP_ADDRESS: + return "PID_CURRENT_IP_ADDRESS"; - case PID_CURRENT_DEFAULT_GATEWAY: - return "PID_CURRENT_DEFAULT_GATEWAY"; + case PID_CURRENT_SUBNET_MASK: + return "PID_CURRENT_SUBNET_MASK"; - case PID_IP_ADDRESS: - return "PID_IP_ADDRESS"; + case PID_CURRENT_DEFAULT_GATEWAY: + return "PID_CURRENT_DEFAULT_GATEWAY"; - case PID_SUBNET_MASK: - return "PID_SUBNET_MASK"; + case PID_IP_ADDRESS: + return "PID_IP_ADDRESS"; - case PID_DEFAULT_GATEWAY: - return "PID_DEFAULT_GATEWAY"; + case PID_SUBNET_MASK: + return "PID_SUBNET_MASK"; - case PID_DHCP_BOOTP_SERVER: - return "PID_DHCP_BOOTP_SERVER"; -*/ - case PID_MAC_ADDRESS: - return "PID_MAC_ADDRESS"; + case PID_DEFAULT_GATEWAY: + return "PID_DEFAULT_GATEWAY"; - case PID_SYSTEM_SETUP_MULTICAST_ADDRESS: - return "PID_SYSTEM_SETUP_MULTICAST_ADDRESS"; + case PID_DHCP_BOOTP_SERVER: + return "PID_DHCP_BOOTP_SERVER"; + */ + case PID_MAC_ADDRESS: + return "PID_MAC_ADDRESS"; - case PID_ROUTING_MULTICAST_ADDRESS: - return "PID_ROUTING_MULTICAST_ADDRESS"; + case PID_SYSTEM_SETUP_MULTICAST_ADDRESS: + return "PID_SYSTEM_SETUP_MULTICAST_ADDRESS"; - case PID_TTL: - return "PID_TTL"; + case PID_ROUTING_MULTICAST_ADDRESS: + return "PID_ROUTING_MULTICAST_ADDRESS"; - case PID_KNXNETIP_DEVICE_CAPABILITIES: - return "PID_KNXNETIP_DEVICE_CAPABILITIES"; + case PID_TTL: + return "PID_TTL"; - case PID_KNXNETIP_DEVICE_STATE: - return "PID_KNXNETIP_DEVICE_STATE"; + case PID_KNXNETIP_DEVICE_CAPABILITIES: + return "PID_KNXNETIP_DEVICE_CAPABILITIES"; - case PID_KNXNETIP_ROUTING_CAPABILITIES: - return "PID_KNXNETIP_ROUTING_CAPABILITIES"; -/* - case PID_PRIORITY_FIFO_ENABLED: - return "PID_PRIORITY_FIFO_ENABLED"; -*/ - case PID_QUEUE_OVERFLOW_TO_IP: - return "PID_QUEUE_OVERFLOW_TO_IP"; + case PID_KNXNETIP_DEVICE_STATE: + return "PID_KNXNETIP_DEVICE_STATE"; - case PID_QUEUE_OVERFLOW_TO_KNX: - return "PID_QUEUE_OVERFLOW_TO_KNX"; + case PID_KNXNETIP_ROUTING_CAPABILITIES: + return "PID_KNXNETIP_ROUTING_CAPABILITIES"; - case PID_MSG_TRANSMIT_TO_IP: - return "PID_MSG_TRANSMIT_TO_IP"; + /* + case PID_PRIORITY_FIFO_ENABLED: + return "PID_PRIORITY_FIFO_ENABLED"; + */ + case PID_QUEUE_OVERFLOW_TO_IP: + return "PID_QUEUE_OVERFLOW_TO_IP"; - case PID_MSG_TRANSMIT_TO_KNX: - return "PID_MSG_TRANSMIT_TO_KNX"; + case PID_QUEUE_OVERFLOW_TO_KNX: + return "PID_QUEUE_OVERFLOW_TO_KNX"; - case PID_FRIENDLY_NAME: - return "PID_FRIENDLY_NAME"; -/* - case PID_ROUTING_BUSY_WAIT_TIME: - return "PID_ROUTING_BUSY_WAIT_TIME"; -*/ - case PID_CUSTOM_RESERVED_TUNNELS_CTRL: - return "PID_CUSTOM_RESERVED_TUNNELS_CTRL"; + case PID_MSG_TRANSMIT_TO_IP: + return "PID_MSG_TRANSMIT_TO_IP"; - case PID_CUSTOM_RESERVED_TUNNELS_IP: - return "PID_CUSTOM_RESERVED_TUNNELS_IP"; -/* - case PID_MEDIUM_TYPE: - return "PID_MEDIUM_TYPE"; + case PID_MSG_TRANSMIT_TO_KNX: + return "PID_MSG_TRANSMIT_TO_KNX"; - case PID_COMM_MODE: - return "PID_COMM_MODE"; + case PID_FRIENDLY_NAME: + return "PID_FRIENDLY_NAME"; - case PID_MEDIUM_AVAILABILITY: - return "PID_MEDIUM_AVAILABILITY"; + /* + case PID_ROUTING_BUSY_WAIT_TIME: + return "PID_ROUTING_BUSY_WAIT_TIME"; + */ + case PID_CUSTOM_RESERVED_TUNNELS_CTRL: + return "PID_CUSTOM_RESERVED_TUNNELS_CTRL"; - case PID_ADD_INFO_TYPES: - return "PID_ADD_INFO_TYPES"; + case PID_CUSTOM_RESERVED_TUNNELS_IP: + return "PID_CUSTOM_RESERVED_TUNNELS_IP"; - case PID_TIME_BASE: - return "PID_TIME_BASE"; + /* + case PID_MEDIUM_TYPE: + return "PID_MEDIUM_TYPE"; - case PID_TRANSP_ENABLE: - return "PID_TRANSP_ENABLE"; + case PID_COMM_MODE: + return "PID_COMM_MODE"; - case PID_CLIENT_SNA: - return "PID_CLIENT_SNA"; + case PID_MEDIUM_AVAILABILITY: + return "PID_MEDIUM_AVAILABILITY"; - case PID_CLIENT_DEVICE_ADDRESS: - return "PID_CLIENT_DEVICE_ADDRESS"; + case PID_ADD_INFO_TYPES: + return "PID_ADD_INFO_TYPES"; - case PID_BIBAT_NEXTBLOCK: - return "PID_BIBAT_NEXTBLOCK"; + case PID_TIME_BASE: + return "PID_TIME_BASE"; - case PID_RF_MODE_SELECT: - return "PID_RF_MODE_SELECT"; + case PID_TRANSP_ENABLE: + return "PID_TRANSP_ENABLE"; - case PID_RF_MODE_SUPPORT: - return "PID_RF_MODE_SUPPORT"; + case PID_CLIENT_SNA: + return "PID_CLIENT_SNA"; - case PID_RF_FILTERING_MODE_SELECT_CEMI_SERVER: - return "PID_RF_FILTERING_MODE_SELECT_CEMI_SERVER"; + case PID_CLIENT_DEVICE_ADDRESS: + return "PID_CLIENT_DEVICE_ADDRESS"; - case PID_RF_FILTERING_MODE_SUPPORT_CEMI_SERVER: - return "PID_RF_FILTERING_MODE_SUPPORT_CEMI_SERVER"; + case PID_BIBAT_NEXTBLOCK: + return "PID_BIBAT_NEXTBLOCK"; - case PID_COMM_MODES_SUPPORTED: - return "PID_COMM_MODES_SUPPORTED"; + case PID_RF_MODE_SELECT: + return "PID_RF_MODE_SELECT"; - case PID_FILTERING_MODE_SUPPORT: - return "PID_FILTERING_MODE_SUPPORT"; + case PID_RF_MODE_SUPPORT: + return "PID_RF_MODE_SUPPORT"; - case PID_FILTERING_MODE_SELECT: - return "PID_FILTERING_MODE_SELECT"; + case PID_RF_FILTERING_MODE_SELECT_CEMI_SERVER: + return "PID_RF_FILTERING_MODE_SELECT_CEMI_SERVER"; - case PID_MAX_INTERFACE_APDU_LENGTH: - return "PID_MAX_INTERFACE_APDU_LENGTH"; + case PID_RF_FILTERING_MODE_SUPPORT_CEMI_SERVER: + return "PID_RF_FILTERING_MODE_SUPPORT_CEMI_SERVER"; - case PID_MAX_LOCAL_APDU_LENGTH: - return "PID_MAX_LOCAL_APDU_LENGTH"; + case PID_COMM_MODES_SUPPORTED: + return "PID_COMM_MODES_SUPPORTED"; - case PID_SECURITY_MODE: - return "PID_SECURITY_MODE"; + case PID_FILTERING_MODE_SUPPORT: + return "PID_FILTERING_MODE_SUPPORT"; - case PID_P2P_KEY_TABLE: - return "PID_P2P_KEY_TABLE"; + case PID_FILTERING_MODE_SELECT: + return "PID_FILTERING_MODE_SELECT"; - case PID_GRP_KEY_TABLE: - return "PID_GRP_KEY_TABLE"; + case PID_MAX_INTERFACE_APDU_LENGTH: + return "PID_MAX_INTERFACE_APDU_LENGTH"; - case PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE: - return "PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE"; + case PID_MAX_LOCAL_APDU_LENGTH: + return "PID_MAX_LOCAL_APDU_LENGTH"; - case PID_SECURITY_FAILURES_LOG: - return "PID_SECURITY_FAILURES_LOG"; + case PID_SECURITY_MODE: + return "PID_SECURITY_MODE"; - case PID_TOOL_KEY: - return "PID_TOOL_KEY"; + case PID_P2P_KEY_TABLE: + return "PID_P2P_KEY_TABLE"; - case PID_SECURITY_REPORT: - return "PID_SECURITY_REPORT"; + case PID_GRP_KEY_TABLE: + return "PID_GRP_KEY_TABLE"; - case PID_SECURITY_REPORT_CONTROL: - return "PID_SECURITY_REPORT_CONTROL"; + case PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE: + return "PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE"; - case PID_SEQUENCE_NUMBER_SENDING: - return "PID_SEQUENCE_NUMBER_SENDING"; + case PID_SECURITY_FAILURES_LOG: + return "PID_SECURITY_FAILURES_LOG"; - case PID_ZONE_KEY_TABLE: - return "PID_ZONE_KEY_TABLE"; + case PID_TOOL_KEY: + return "PID_TOOL_KEY"; - case PID_GO_SECURITY_FLAGS: - return "PID_GO_SECURITY_FLAGS"; + case PID_SECURITY_REPORT: + return "PID_SECURITY_REPORT"; - case PID_ROLE_TABLE: - return "PID_ROLE_TABLE"; -*/ - case PID_TOOL_SEQUENCE_NUMBER_SENDING: - return "PID_TOOL_SEQUENCE_NUMBER_SENDING"; -/* - case PID_MEDIUM_STATUS: - return "PID_MEDIUM_STATUS"; + case PID_SECURITY_REPORT_CONTROL: + return "PID_SECURITY_REPORT_CONTROL"; - case PID_MAIN_LCCONFIG: - return "PID_MAIN_LCCONFIG"; + case PID_SEQUENCE_NUMBER_SENDING: + return "PID_SEQUENCE_NUMBER_SENDING"; - case PID_SUB_LCCONFIG: - return "PID_SUB_LCCONFIG"; + case PID_ZONE_KEY_TABLE: + return "PID_ZONE_KEY_TABLE"; - case PID_MAIN_LCGRPCONFIG: - return "PID_MAIN_LCGRPCONFIG"; + case PID_GO_SECURITY_FLAGS: + return "PID_GO_SECURITY_FLAGS"; - case PID_SUB_LCGRPCONFIG: - return "PID_SUB_LCGRPCONFIG"; + case PID_ROLE_TABLE: + return "PID_ROLE_TABLE"; + */ + case PID_TOOL_SEQUENCE_NUMBER_SENDING: + return "PID_TOOL_SEQUENCE_NUMBER_SENDING"; - case PID_ROUTETABLE_CONTROL: - return "PID_ROUTETABLE_CONTROL"; + /* + case PID_MEDIUM_STATUS: + return "PID_MEDIUM_STATUS"; - case PID_COUPLER_SERVICES_CONTROL: - return "PID_COUPLER_SERVICES_CONTROL"; + case PID_MAIN_LCCONFIG: + return "PID_MAIN_LCCONFIG"; - case PID_MAX_APDU_LENGTH_ROUTER: - return "PID_MAX_APDU_LENGTH_ROUTER"; + case PID_SUB_LCCONFIG: + return "PID_SUB_LCCONFIG"; - case PID_L2_COUPLER_TYPE: - return "PID_L2_COUPLER_TYPE"; + case PID_MAIN_LCGRPCONFIG: + return "PID_MAIN_LCGRPCONFIG"; - case PID_HOP_COUNT: - return "PID_HOP_COUNT"; + case PID_SUB_LCGRPCONFIG: + return "PID_SUB_LCGRPCONFIG"; - case PID_MEDIUM: - return "PID_MEDIUM"; + case PID_ROUTETABLE_CONTROL: + return "PID_ROUTETABLE_CONTROL"; - case PID_FILTER_TABLE_USE: - return "PID_FILTER_TABLE_USE"; + case PID_COUPLER_SERVICES_CONTROL: + return "PID_COUPLER_SERVICES_CONTROL"; -*/ - case PID_RF_ENABLE_SBC: - return "PID_RF_ENABLE_SBC"; + case PID_MAX_APDU_LENGTH_ROUTER: + return "PID_MAX_APDU_LENGTH_ROUTER"; - case PID_IP_ENABLE_SBC: - return "PID_IP_ENABLE_SBC"; - } + case PID_L2_COUPLER_TYPE: + return "PID_L2_COUPLER_TYPE"; - return ""; -} + case PID_HOP_COUNT: + return "PID_HOP_COUNT"; -const char* enum_name(const LoadState enum_val) -{ - switch (enum_val) + case PID_MEDIUM: + return "PID_MEDIUM"; + + case PID_FILTER_TABLE_USE: + return "PID_FILTER_TABLE_USE"; + + */ + case PID_RF_ENABLE_SBC: + return "PID_RF_ENABLE_SBC"; + + case PID_IP_ENABLE_SBC: + return "PID_IP_ENABLE_SBC"; + } + + return ""; + } + + const char* enum_name(const LoadState enum_val) { - case LS_UNLOADED: - return "LS_UNLOADED"; + switch (enum_val) + { + case LS_UNLOADED: + return "LS_UNLOADED"; - case LS_LOADED: - return "LS_LOADED"; + case LS_LOADED: + return "LS_LOADED"; - case LS_LOADING: - return "LS_LOADING"; + case LS_LOADING: + return "LS_LOADING"; - case LS_ERROR: - return "LS_ERROR"; + case LS_ERROR: + return "LS_ERROR"; - case LS_UNLOADING: - return "LS_UNLOADING"; + case LS_UNLOADING: + return "LS_UNLOADING"; - case LS_LOADCOMPLETING: - return "LS_LOADCOMPLETING"; - } + case LS_LOADCOMPLETING: + return "LS_LOADCOMPLETING"; + } - return ""; -} + return ""; + } -const char* enum_name(const LoadEvents enum_val) -{ - switch (enum_val) + const char* enum_name(const LoadEvents enum_val) { - case LE_NOOP: - return "LE_NOOP"; + switch (enum_val) + { + case LE_NOOP: + return "LE_NOOP"; - case LE_START_LOADING: - return "LE_START_LOADING"; + case LE_START_LOADING: + return "LE_START_LOADING"; - case LE_LOAD_COMPLETED: - return "LE_LOAD_COMPLETED"; + case LE_LOAD_COMPLETED: + return "LE_LOAD_COMPLETED"; - case LE_ADDITIONAL_LOAD_CONTROLS: - return "LE_ADDITIONAL_LOAD_CONTROLS"; + case LE_ADDITIONAL_LOAD_CONTROLS: + return "LE_ADDITIONAL_LOAD_CONTROLS"; - case LE_UNLOAD: - return "LE_UNLOAD"; - } + case LE_UNLOAD: + return "LE_UNLOAD"; + } - return ""; -} + return ""; + } -const char* enum_name(const ErrorCode enum_val) -{ - switch (enum_val) + const char* enum_name(const ErrorCode enum_val) { - case E_NO_FAULT: - return "E_NO_FAULT"; + switch (enum_val) + { + case E_NO_FAULT: + return "E_NO_FAULT"; - case E_GENERAL_DEVICE_FAULT: - return "E_GENERAL_DEVICE_FAULT"; + case E_GENERAL_DEVICE_FAULT: + return "E_GENERAL_DEVICE_FAULT"; - case E_COMMUNICATION_FAULT: - return "E_COMMUNICATION_FAULT"; + case E_COMMUNICATION_FAULT: + return "E_COMMUNICATION_FAULT"; - case E_CONFIGURATION_FAULT: - return "E_CONFIGURATION_FAULT"; + case E_CONFIGURATION_FAULT: + return "E_CONFIGURATION_FAULT"; - case E_HARDWARE_FAULT: - return "E_HARDWARE_FAULT"; + case E_HARDWARE_FAULT: + return "E_HARDWARE_FAULT"; - case E_SOFTWARE_FAULT: - return "E_SOFTWARE_FAULT"; + case E_SOFTWARE_FAULT: + return "E_SOFTWARE_FAULT"; - case E_INSUFFICIENT_NON_VOLATILE_MEMORY: - return "E_INSUFFICIENT_NON_VOLATILE_MEMORY"; + case E_INSUFFICIENT_NON_VOLATILE_MEMORY: + return "E_INSUFFICIENT_NON_VOLATILE_MEMORY"; - case E_INSUFFICIENT_VOLATILE_MEMORY: - return "E_INSUFFICIENT_VOLATILE_MEMORY"; + case E_INSUFFICIENT_VOLATILE_MEMORY: + return "E_INSUFFICIENT_VOLATILE_MEMORY"; - case E_GOT_MEM_ALLOC_ZERO: - return "E_GOT_MEM_ALLOC_ZERO"; + case E_GOT_MEM_ALLOC_ZERO: + return "E_GOT_MEM_ALLOC_ZERO"; - case E_CRC_ERROR: - return "E_CRC_ERROR"; + case E_CRC_ERROR: + return "E_CRC_ERROR"; - case E_WATCHDOG_RESET: - return "E_WATCHDOG_RESET"; + case E_WATCHDOG_RESET: + return "E_WATCHDOG_RESET"; - case E_INVALID_OPCODE: - return "E_INVALID_OPCODE"; + case E_INVALID_OPCODE: + return "E_INVALID_OPCODE"; - case E_GENERAL_PROTECTION_FAULT: - return "E_GENERAL_PROTECTION_FAULT"; + case E_GENERAL_PROTECTION_FAULT: + return "E_GENERAL_PROTECTION_FAULT"; - case E_MAX_TABLE_LENGTH_EXEEDED: - return "E_MAX_TABLE_LENGTH_EXEEDED"; + case E_MAX_TABLE_LENGTH_EXEEDED: + return "E_MAX_TABLE_LENGTH_EXEEDED"; - case E_GOT_UNDEF_LOAD_CMD: - return "E_GOT_UNDEF_LOAD_CMD"; + case E_GOT_UNDEF_LOAD_CMD: + return "E_GOT_UNDEF_LOAD_CMD"; - case E_GAT_NOT_SORTED: - return "E_GAT_NOT_SORTED"; + case E_GAT_NOT_SORTED: + return "E_GAT_NOT_SORTED"; - case E_INVALID_CONNECTION_NUMBER: - return "E_INVALID_CONNECTION_NUMBER"; + case E_INVALID_CONNECTION_NUMBER: + return "E_INVALID_CONNECTION_NUMBER"; - case E_INVALID_GO_NUMBER: - return "E_INVALID_GO_NUMBER"; + case E_INVALID_GO_NUMBER: + return "E_INVALID_GO_NUMBER"; - case E_GO_TYPE_TOO_BIG: - return "E_GO_TYPE_TOO_BIG"; - } + case E_GO_TYPE_TOO_BIG: + return "E_GO_TYPE_TOO_BIG"; + } - return ""; -} + return ""; + } -const char* enum_name(const AccessLevel enum_val) -{ - switch (enum_val) + const char* enum_name(const AccessLevel enum_val) { - case ReadLv0: - return "ReadLv0/WriteLv0"; + switch (enum_val) + { + case ReadLv0: + return "ReadLv0/WriteLv0"; - case ReadLv1: - return "ReadLv1"; + case ReadLv1: + return "ReadLv1"; - case ReadLv2: - return "ReadLv2"; + case ReadLv2: + return "ReadLv2"; - case ReadLv3: - return "ReadLv3"; + case ReadLv3: + return "ReadLv3"; - case WriteLv1: - return "WriteLv1"; + case WriteLv1: + return "WriteLv1"; - case WriteLv2: - return "WriteLv2"; + case WriteLv2: + return "WriteLv2"; - case WriteLv3: - return "WriteLv3"; - } + case WriteLv3: + return "WriteLv3"; + } - return ""; -} -#endif \ No newline at end of file + return ""; + } +#endif +} \ No newline at end of file diff --git a/src/knx/interface_object/property.h b/src/knx/interface_object/property.h index c17f0bc8..ff6723ed 100644 --- a/src/knx/interface_object/property.h +++ b/src/knx/interface_object/property.h @@ -13,287 +13,290 @@ #include -/** The data type of a property. */ -enum PropertyDataType +namespace Knx { - PDT_CONTROL = 0x00, //!< length: 1 read, 10 write - PDT_CHAR = 0x01, //!< length: 1 - PDT_UNSIGNED_CHAR = 0x02, //!< length: 1 - PDT_INT = 0x03, //!< length: 2 - PDT_UNSIGNED_INT = 0x04, //!< length: 2 - PDT_KNX_FLOAT = 0x05, //!< length: 2 - PDT_DATE = 0x06, //!< length: 3 - PDT_TIME = 0x07, //!< length: 3 - PDT_LONG = 0x08, //!< length: 4 - PDT_UNSIGNED_LONG = 0x09, //!< length: 4 - PDT_FLOAT = 0x0a, //!< length: 4 - PDT_DOUBLE = 0x0b, //!< length: 8 - PDT_CHAR_BLOCK = 0x0c, //!< length: 10 - PDT_POLL_GROUP_SETTING = 0x0d, //!< length: 3 - PDT_SHORT_CHAR_BLOCK = 0x0e, //!< length: 5 - PDT_DATE_TIME = 0x0f, //!< length: 8 - PDT_VARIABLE_LENGTH = 0x10, - PDT_GENERIC_01 = 0x11, //!< length: 1 - PDT_GENERIC_02 = 0x12, //!< length: 2 - PDT_GENERIC_03 = 0x13, //!< length: 3 - PDT_GENERIC_04 = 0x14, //!< length: 4 - PDT_GENERIC_05 = 0x15, //!< length: 5 - PDT_GENERIC_06 = 0x16, //!< length: 6 - PDT_GENERIC_07 = 0x17, //!< length: 7 - PDT_GENERIC_08 = 0x18, //!< length: 8 - PDT_GENERIC_09 = 0x19, //!< length: 9 - PDT_GENERIC_10 = 0x1a, //!< length: 10 - PDT_GENERIC_11 = 0x1b, //!< length: 11 - PDT_GENERIC_12 = 0x1c, //!< length: 12 - PDT_GENERIC_13 = 0x1d, //!< length: 13 - PDT_GENERIC_14 = 0x1e, //!< length: 14 - PDT_GENERIC_15 = 0x1f, //!< length: 15 - PDT_GENERIC_16 = 0x20, //!< length: 16 - PDT_GENERIC_17 = 0x21, //!< length: 17 - PDT_GENERIC_18 = 0x22, //!< length: 18 - PDT_GENERIC_19 = 0x23, //!< length: 19 - PDT_GENERIC_20 = 0x24, //!< length: 20 - PDT_UTF8 = 0x2f, //!< length: 3 - PDT_VERSION = 0x30, //!< length: 3 - PDT_ALARM_INFO = 0x31, //!< length: 3 - PDT_BINARY_INFORMATION = 0x32, //!< length: 3 - PDT_BITSET8 = 0x33, //!< length: 3 - PDT_BITSET16 = 0x34, //!< length: 3 - PDT_ENUM8 = 0x35, //!< length: 3 - PDT_SCALING = 0x36, //!< length: 3 - PDT_NE_VL = 0x3c, //!< length: 3 - PDT_NE_FL = 0x3d, //!< length: 3 - PDT_FUNCTION = 0x3e, //!< length: 3 - PDT_ESCAPE = 0x3f, //!< length: 3 -}; -const char* enum_name(const PropertyDataType enum_val); + /** The data type of a property. */ + enum PropertyDataType + { + PDT_CONTROL = 0x00, //!< length: 1 read, 10 write + PDT_CHAR = 0x01, //!< length: 1 + PDT_UNSIGNED_CHAR = 0x02, //!< length: 1 + PDT_INT = 0x03, //!< length: 2 + PDT_UNSIGNED_INT = 0x04, //!< length: 2 + PDT_KNX_FLOAT = 0x05, //!< length: 2 + PDT_DATE = 0x06, //!< length: 3 + PDT_TIME = 0x07, //!< length: 3 + PDT_LONG = 0x08, //!< length: 4 + PDT_UNSIGNED_LONG = 0x09, //!< length: 4 + PDT_FLOAT = 0x0a, //!< length: 4 + PDT_DOUBLE = 0x0b, //!< length: 8 + PDT_CHAR_BLOCK = 0x0c, //!< length: 10 + PDT_POLL_GROUP_SETTING = 0x0d, //!< length: 3 + PDT_SHORT_CHAR_BLOCK = 0x0e, //!< length: 5 + PDT_DATE_TIME = 0x0f, //!< length: 8 + PDT_VARIABLE_LENGTH = 0x10, + PDT_GENERIC_01 = 0x11, //!< length: 1 + PDT_GENERIC_02 = 0x12, //!< length: 2 + PDT_GENERIC_03 = 0x13, //!< length: 3 + PDT_GENERIC_04 = 0x14, //!< length: 4 + PDT_GENERIC_05 = 0x15, //!< length: 5 + PDT_GENERIC_06 = 0x16, //!< length: 6 + PDT_GENERIC_07 = 0x17, //!< length: 7 + PDT_GENERIC_08 = 0x18, //!< length: 8 + PDT_GENERIC_09 = 0x19, //!< length: 9 + PDT_GENERIC_10 = 0x1a, //!< length: 10 + PDT_GENERIC_11 = 0x1b, //!< length: 11 + PDT_GENERIC_12 = 0x1c, //!< length: 12 + PDT_GENERIC_13 = 0x1d, //!< length: 13 + PDT_GENERIC_14 = 0x1e, //!< length: 14 + PDT_GENERIC_15 = 0x1f, //!< length: 15 + PDT_GENERIC_16 = 0x20, //!< length: 16 + PDT_GENERIC_17 = 0x21, //!< length: 17 + PDT_GENERIC_18 = 0x22, //!< length: 18 + PDT_GENERIC_19 = 0x23, //!< length: 19 + PDT_GENERIC_20 = 0x24, //!< length: 20 + PDT_UTF8 = 0x2f, //!< length: 3 + PDT_VERSION = 0x30, //!< length: 3 + PDT_ALARM_INFO = 0x31, //!< length: 3 + PDT_BINARY_INFORMATION = 0x32, //!< length: 3 + PDT_BITSET8 = 0x33, //!< length: 3 + PDT_BITSET16 = 0x34, //!< length: 3 + PDT_ENUM8 = 0x35, //!< length: 3 + PDT_SCALING = 0x36, //!< length: 3 + PDT_NE_VL = 0x3c, //!< length: 3 + PDT_NE_FL = 0x3d, //!< length: 3 + PDT_FUNCTION = 0x3e, //!< length: 3 + PDT_ESCAPE = 0x3f, //!< length: 3 + }; + const char* enum_name(const PropertyDataType enum_val); -enum PropertyID -{ - /** Interface Object Type independent Properties */ - PID_OBJECT_TYPE = 1, - PID_LOAD_STATE_CONTROL = 5, - PID_RUN_STATE_CONTROL = 6, - PID_TABLE_REFERENCE = 7, - PID_SERVICE_CONTROL = 8, - PID_FIRMWARE_REVISION = 9, - PID_SERIAL_NUMBER = 11, - PID_MANUFACTURER_ID = 12, - PID_PROG_VERSION = 13, - PID_DEVICE_CONTROL = 14, - PID_ORDER_INFO = 15, - PID_PEI_TYPE = 16, - PID_PORT_CONFIGURATION = 17, - PID_TABLE = 23, - PID_VERSION = 25, - PID_MCB_TABLE = 27, - PID_ERROR_CODE = 28, - PID_OBJECT_INDEX = 29, - PID_DOWNLOAD_COUNTER = 30, + enum PropertyID + { + /** Interface Object Type independent Properties */ + PID_OBJECT_TYPE = 1, + PID_LOAD_STATE_CONTROL = 5, + PID_RUN_STATE_CONTROL = 6, + PID_TABLE_REFERENCE = 7, + PID_SERVICE_CONTROL = 8, + PID_FIRMWARE_REVISION = 9, + PID_SERIAL_NUMBER = 11, + PID_MANUFACTURER_ID = 12, + PID_PROG_VERSION = 13, + PID_DEVICE_CONTROL = 14, + PID_ORDER_INFO = 15, + PID_PEI_TYPE = 16, + PID_PORT_CONFIGURATION = 17, + PID_TABLE = 23, + PID_VERSION = 25, + PID_MCB_TABLE = 27, + PID_ERROR_CODE = 28, + PID_OBJECT_INDEX = 29, + PID_DOWNLOAD_COUNTER = 30, - /** Properties in the Device Object */ - PID_ROUTING_COUNT = 51, - PID_PROG_MODE = 54, - PID_MAX_APDU_LENGTH = 56, - PID_SUBNET_ADDR = 57, - PID_DEVICE_ADDR = 58, - PID_IO_LIST = 71, - PID_HARDWARE_TYPE = 78, - PID_RF_DOMAIN_ADDRESS_CEMI_SERVER = 82, - PID_DEVICE_DESCRIPTOR = 83, + /** Properties in the Device Object */ + PID_ROUTING_COUNT = 51, + PID_PROG_MODE = 54, + PID_MAX_APDU_LENGTH = 56, + PID_SUBNET_ADDR = 57, + PID_DEVICE_ADDR = 58, + PID_IO_LIST = 71, + PID_HARDWARE_TYPE = 78, + PID_RF_DOMAIN_ADDRESS_CEMI_SERVER = 82, + PID_DEVICE_DESCRIPTOR = 83, - /** Properties in the RF Medium Object */ - PID_RF_MULTI_TYPE = 51, - PID_RF_DOMAIN_ADDRESS = 56, - PID_RF_RETRANSMITTER = 57, - PID_RF_FILTERING_MODE_SUPPORT = 58, - PID_RF_FILTERING_MODE_SELECT = 59, - PID_RF_BIDIR_TIMEOUT = 60, - PID_RF_DIAG_SA_FILTER_TABLE = 61, - PID_RF_DIAG_BUDGET_TABLE = 62, - PID_RF_DIAG_PROBE = 63, + /** Properties in the RF Medium Object */ + PID_RF_MULTI_TYPE = 51, + PID_RF_DOMAIN_ADDRESS = 56, + PID_RF_RETRANSMITTER = 57, + PID_RF_FILTERING_MODE_SUPPORT = 58, + PID_RF_FILTERING_MODE_SELECT = 59, + PID_RF_BIDIR_TIMEOUT = 60, + PID_RF_DIAG_SA_FILTER_TABLE = 61, + PID_RF_DIAG_BUDGET_TABLE = 62, + PID_RF_DIAG_PROBE = 63, - /** KNXnet/IP Parameter Object */ - PID_PROJECT_INSTALLATION_ID = 51, - PID_KNX_INDIVIDUAL_ADDRESS = 52, - PID_ADDITIONAL_INDIVIDUAL_ADDRESSES = 53, - PID_CURRENT_IP_ASSIGNMENT_METHOD = 54, - PID_IP_ASSIGNMENT_METHOD = 55, - PID_IP_CAPABILITIES = 56, - PID_CURRENT_IP_ADDRESS = 57, - PID_CURRENT_SUBNET_MASK = 58, - PID_CURRENT_DEFAULT_GATEWAY = 59, - PID_IP_ADDRESS = 60, - PID_SUBNET_MASK = 61, - PID_DEFAULT_GATEWAY = 62, - PID_DHCP_BOOTP_SERVER = 63, - PID_MAC_ADDRESS = 64, - PID_SYSTEM_SETUP_MULTICAST_ADDRESS = 65, - PID_ROUTING_MULTICAST_ADDRESS = 66, - PID_TTL = 67, - PID_KNXNETIP_DEVICE_CAPABILITIES = 68, - PID_KNXNETIP_DEVICE_STATE = 69, - PID_KNXNETIP_ROUTING_CAPABILITIES = 70, - PID_PRIORITY_FIFO_ENABLED = 71, - PID_QUEUE_OVERFLOW_TO_IP = 72, - PID_QUEUE_OVERFLOW_TO_KNX = 73, - PID_MSG_TRANSMIT_TO_IP = 74, - PID_MSG_TRANSMIT_TO_KNX = 75, - PID_FRIENDLY_NAME = 76, - PID_ROUTING_BUSY_WAIT_TIME = 78, - PID_CUSTOM_RESERVED_TUNNELS_CTRL = 201, // custom propertiy to control the stacks behaviour for reserverd tunnels, not in Spec (PID >= 200) - PID_CUSTOM_RESERVED_TUNNELS_IP = 202, // custom propertiy to control the stacks behaviour for reserverd tunnels, not in Spec (PID >= 200) + /** KNXnet/IP Parameter Object */ + PID_PROJECT_INSTALLATION_ID = 51, + PID_KNX_INDIVIDUAL_ADDRESS = 52, + PID_ADDITIONAL_INDIVIDUAL_ADDRESSES = 53, + PID_CURRENT_IP_ASSIGNMENT_METHOD = 54, + PID_IP_ASSIGNMENT_METHOD = 55, + PID_IP_CAPABILITIES = 56, + PID_CURRENT_IP_ADDRESS = 57, + PID_CURRENT_SUBNET_MASK = 58, + PID_CURRENT_DEFAULT_GATEWAY = 59, + PID_IP_ADDRESS = 60, + PID_SUBNET_MASK = 61, + PID_DEFAULT_GATEWAY = 62, + PID_DHCP_BOOTP_SERVER = 63, + PID_MAC_ADDRESS = 64, + PID_SYSTEM_SETUP_MULTICAST_ADDRESS = 65, + PID_ROUTING_MULTICAST_ADDRESS = 66, + PID_TTL = 67, + PID_KNXNETIP_DEVICE_CAPABILITIES = 68, + PID_KNXNETIP_DEVICE_STATE = 69, + PID_KNXNETIP_ROUTING_CAPABILITIES = 70, + PID_PRIORITY_FIFO_ENABLED = 71, + PID_QUEUE_OVERFLOW_TO_IP = 72, + PID_QUEUE_OVERFLOW_TO_KNX = 73, + PID_MSG_TRANSMIT_TO_IP = 74, + PID_MSG_TRANSMIT_TO_KNX = 75, + PID_FRIENDLY_NAME = 76, + PID_ROUTING_BUSY_WAIT_TIME = 78, + PID_CUSTOM_RESERVED_TUNNELS_CTRL = 201, // custom propertiy to control the stacks behaviour for reserverd tunnels, not in Spec (PID >= 200) + PID_CUSTOM_RESERVED_TUNNELS_IP = 202, // custom propertiy to control the stacks behaviour for reserverd tunnels, not in Spec (PID >= 200) - /** cEMI Server Object */ - PID_MEDIUM_TYPE = 51, - PID_COMM_MODE = 52, - PID_MEDIUM_AVAILABILITY = 53, - PID_ADD_INFO_TYPES = 54, - PID_TIME_BASE = 55, - PID_TRANSP_ENABLE = 56, - PID_CLIENT_SNA = 57, - PID_CLIENT_DEVICE_ADDRESS = 58, - PID_BIBAT_NEXTBLOCK = 59, - PID_RF_MODE_SELECT = 60, - PID_RF_MODE_SUPPORT = 61, - PID_RF_FILTERING_MODE_SELECT_CEMI_SERVER = 62, - PID_RF_FILTERING_MODE_SUPPORT_CEMI_SERVER = 63, - PID_COMM_MODES_SUPPORTED = 64, - PID_FILTERING_MODE_SUPPORT = 65, - PID_FILTERING_MODE_SELECT = 66, - PID_MAX_INTERFACE_APDU_LENGTH = 68, - PID_MAX_LOCAL_APDU_LENGTH = 69, + /** cEMI Server Object */ + PID_MEDIUM_TYPE = 51, + PID_COMM_MODE = 52, + PID_MEDIUM_AVAILABILITY = 53, + PID_ADD_INFO_TYPES = 54, + PID_TIME_BASE = 55, + PID_TRANSP_ENABLE = 56, + PID_CLIENT_SNA = 57, + PID_CLIENT_DEVICE_ADDRESS = 58, + PID_BIBAT_NEXTBLOCK = 59, + PID_RF_MODE_SELECT = 60, + PID_RF_MODE_SUPPORT = 61, + PID_RF_FILTERING_MODE_SELECT_CEMI_SERVER = 62, + PID_RF_FILTERING_MODE_SUPPORT_CEMI_SERVER = 63, + PID_COMM_MODES_SUPPORTED = 64, + PID_FILTERING_MODE_SUPPORT = 65, + PID_FILTERING_MODE_SELECT = 66, + PID_MAX_INTERFACE_APDU_LENGTH = 68, + PID_MAX_LOCAL_APDU_LENGTH = 69, - /** Security Interface Object */ - PID_SECURITY_MODE = 51, // Enable and disable the Security Mode - PID_P2P_KEY_TABLE = 52, // Security keys used for securing point-to-point and broadcast communication - PID_GRP_KEY_TABLE = 53, // Security keys used for securing standard mode group communication - PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE = 54, // IAs and last valid sequence numbers of communication partners with secure links - PID_SECURITY_FAILURES_LOG = 55, // Provides security failure information - PID_TOOL_KEY = 56, // Stores the security information for the central MaC in S-Mode and Ctrl-Mode - PID_SECURITY_REPORT = 57, // KNX Data Security-related status and diagnostic information - PID_SECURITY_REPORT_CONTROL = 58, // Control the spontaneous communication of the security report through DMP_InterfaceObject-InfoReport_RCl - PID_SEQUENCE_NUMBER_SENDING = 59, // Sequence Number used for the next outgoing secure communication - PID_ZONE_KEY_TABLE = 60, // Security keys used for securing zone addressing communication - PID_GO_SECURITY_FLAGS = 61, // Defines the required security requirements for each group object - PID_ROLE_TABLE = 62, // Role table - PID_TOOL_SEQUENCE_NUMBER_SENDING = 250, // Sequence Number used for the next outgoing secure communication (Tool Access only, non-standardized!) + /** Security Interface Object */ + PID_SECURITY_MODE = 51, // Enable and disable the Security Mode + PID_P2P_KEY_TABLE = 52, // Security keys used for securing point-to-point and broadcast communication + PID_GRP_KEY_TABLE = 53, // Security keys used for securing standard mode group communication + PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE = 54, // IAs and last valid sequence numbers of communication partners with secure links + PID_SECURITY_FAILURES_LOG = 55, // Provides security failure information + PID_TOOL_KEY = 56, // Stores the security information for the central MaC in S-Mode and Ctrl-Mode + PID_SECURITY_REPORT = 57, // KNX Data Security-related status and diagnostic information + PID_SECURITY_REPORT_CONTROL = 58, // Control the spontaneous communication of the security report through DMP_InterfaceObject-InfoReport_RCl + PID_SEQUENCE_NUMBER_SENDING = 59, // Sequence Number used for the next outgoing secure communication + PID_ZONE_KEY_TABLE = 60, // Security keys used for securing zone addressing communication + PID_GO_SECURITY_FLAGS = 61, // Defines the required security requirements for each group object + PID_ROLE_TABLE = 62, // Role table + PID_TOOL_SEQUENCE_NUMBER_SENDING = 250, // Sequence Number used for the next outgoing secure communication (Tool Access only, non-standardized!) - /** Router Object */ - PID_MEDIUM_STATUS = 51, - PID_MAIN_LCCONFIG = 52, - PID_SUB_LCCONFIG = 53, - PID_MAIN_LCGRPCONFIG = 54, - PID_SUB_LCGRPCONFIG = 55, - PID_ROUTETABLE_CONTROL = 56, - PID_COUPLER_SERVICES_CONTROL = 57, - PID_MAX_APDU_LENGTH_ROUTER = 58, - PID_L2_COUPLER_TYPE = 59, // Only interesting for mask 0x0912 (TP1/TP1 coupler) - PID_HOP_COUNT = 61, // Only interesting in primary if other medium(secondary) is open medium without hopcount - PID_MEDIUM = 63, - PID_FILTER_TABLE_USE = 67, - PID_RF_ENABLE_SBC = 112, // Exists only if medium for this router object is RF (PDT_FUNCTION) - PID_IP_ENABLE_SBC = 120, // Exists only if medium for this router object is IP (PDT_FUNCTION) -}; -const char* enum_name(const PropertyID enum_val); + /** Router Object */ + PID_MEDIUM_STATUS = 51, + PID_MAIN_LCCONFIG = 52, + PID_SUB_LCCONFIG = 53, + PID_MAIN_LCGRPCONFIG = 54, + PID_SUB_LCGRPCONFIG = 55, + PID_ROUTETABLE_CONTROL = 56, + PID_COUPLER_SERVICES_CONTROL = 57, + PID_MAX_APDU_LENGTH_ROUTER = 58, + PID_L2_COUPLER_TYPE = 59, // Only interesting for mask 0x0912 (TP1/TP1 coupler) + PID_HOP_COUNT = 61, // Only interesting in primary if other medium(secondary) is open medium without hopcount + PID_MEDIUM = 63, + PID_FILTER_TABLE_USE = 67, + PID_RF_ENABLE_SBC = 112, // Exists only if medium for this router object is RF (PDT_FUNCTION) + PID_IP_ENABLE_SBC = 120, // Exists only if medium for this router object is IP (PDT_FUNCTION) + }; + const char* enum_name(const PropertyID enum_val); -enum LoadState -{ - LS_UNLOADED = 0, - LS_LOADED = 1, - LS_LOADING = 2, - LS_ERROR = 3, - LS_UNLOADING = 4, - LS_LOADCOMPLETING = 5 -}; -const char* enum_name(const LoadState enum_val); + enum LoadState + { + LS_UNLOADED = 0, + LS_LOADED = 1, + LS_LOADING = 2, + LS_ERROR = 3, + LS_UNLOADING = 4, + LS_LOADCOMPLETING = 5 + }; + const char* enum_name(const LoadState enum_val); -enum LoadEvents -{ - LE_NOOP = 0, - LE_START_LOADING = 1, - LE_LOAD_COMPLETED = 2, - LE_ADDITIONAL_LOAD_CONTROLS = 3, - LE_UNLOAD = 4 -}; -const char* enum_name(const LoadEvents enum_val); + enum LoadEvents + { + LE_NOOP = 0, + LE_START_LOADING = 1, + LE_LOAD_COMPLETED = 2, + LE_ADDITIONAL_LOAD_CONTROLS = 3, + LE_UNLOAD = 4 + }; + const char* enum_name(const LoadEvents enum_val); -// 20.011 DPT_ErrorClass_System -enum ErrorCode -{ - E_NO_FAULT = 0, - E_GENERAL_DEVICE_FAULT = 1, - E_COMMUNICATION_FAULT = 2, - E_CONFIGURATION_FAULT = 3, - E_HARDWARE_FAULT = 4, - E_SOFTWARE_FAULT = 5, - E_INSUFFICIENT_NON_VOLATILE_MEMORY = 6, - E_INSUFFICIENT_VOLATILE_MEMORY = 7, - E_GOT_MEM_ALLOC_ZERO = 8, - E_CRC_ERROR = 9, - E_WATCHDOG_RESET = 10, - E_INVALID_OPCODE = 11, - E_GENERAL_PROTECTION_FAULT = 12, - E_MAX_TABLE_LENGTH_EXEEDED = 13, - E_GOT_UNDEF_LOAD_CMD = 14, - E_GAT_NOT_SORTED = 15, - E_INVALID_CONNECTION_NUMBER = 16, - E_INVALID_GO_NUMBER = 17, - E_GO_TYPE_TOO_BIG = 18 -}; -const char* enum_name(const ErrorCode enum_val); + // 20.011 DPT_ErrorClass_System + enum ErrorCode + { + E_NO_FAULT = 0, + E_GENERAL_DEVICE_FAULT = 1, + E_COMMUNICATION_FAULT = 2, + E_CONFIGURATION_FAULT = 3, + E_HARDWARE_FAULT = 4, + E_SOFTWARE_FAULT = 5, + E_INSUFFICIENT_NON_VOLATILE_MEMORY = 6, + E_INSUFFICIENT_VOLATILE_MEMORY = 7, + E_GOT_MEM_ALLOC_ZERO = 8, + E_CRC_ERROR = 9, + E_WATCHDOG_RESET = 10, + E_INVALID_OPCODE = 11, + E_GENERAL_PROTECTION_FAULT = 12, + E_MAX_TABLE_LENGTH_EXEEDED = 13, + E_GOT_UNDEF_LOAD_CMD = 14, + E_GAT_NOT_SORTED = 15, + E_INVALID_CONNECTION_NUMBER = 16, + E_INVALID_GO_NUMBER = 17, + E_GO_TYPE_TOO_BIG = 18 + }; + const char* enum_name(const ErrorCode enum_val); -/** The access level necessary to read a property of an interface object. */ -enum AccessLevel -{ - ReadLv0 = 0x00, - ReadLv1 = 0x10, - ReadLv2 = 0x20, - ReadLv3 = 0x30, - WriteLv0 = 0x00, - WriteLv1 = 0x01, - WriteLv2 = 0x02, - WriteLv3 = 0x03, -}; -const char* enum_name(const AccessLevel enum_val); + /** The access level necessary to read a property of an interface object. */ + enum AccessLevel + { + ReadLv0 = 0x00, + ReadLv1 = 0x10, + ReadLv2 = 0x20, + ReadLv3 = 0x30, + WriteLv0 = 0x00, + WriteLv1 = 0x01, + WriteLv2 = 0x02, + WriteLv3 = 0x03, + }; + const char* enum_name(const AccessLevel enum_val); -struct PropertyDescription -{ - PropertyID Id; - bool WriteEnable; - PropertyDataType Type; - uint16_t MaxElements; - uint8_t Access; -}; + struct PropertyDescription + { + PropertyID Id; + bool WriteEnable; + PropertyDataType Type; + uint16_t MaxElements; + uint8_t Access; + }; -class Property : public SaveRestore -{ - public: - Property(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access); - virtual ~Property(); - PropertyID Id() const; - bool WriteEnable() const; - PropertyDataType Type() const; - uint16_t MaxElements() const; - uint8_t Access() const; - uint8_t ElementSize() const; - virtual uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const = 0; - virtual uint8_t write(uint16_t start, uint8_t count, const uint8_t* data) = 0; - virtual void command(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength); - virtual void state(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength); - uint8_t read(uint8_t& value) const; - uint8_t read(uint16_t& value) const; - uint8_t read(uint32_t& value) const; - uint8_t read(uint8_t* value) const; - uint8_t write(uint8_t value); - uint8_t write(uint16_t value); - uint8_t write(uint16_t position, uint16_t value); - uint8_t write(uint32_t value); - uint8_t write(const uint8_t* value); - protected: - PropertyID _id; - bool _writeEnable; - PropertyDataType _type; - uint16_t _maxElements; - uint8_t _access; -}; + class Property : public SaveRestore + { + public: + Property(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access); + virtual ~Property(); + PropertyID Id() const; + bool WriteEnable() const; + PropertyDataType Type() const; + uint16_t MaxElements() const; + uint8_t Access() const; + uint8_t ElementSize() const; + virtual uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const = 0; + virtual uint8_t write(uint16_t start, uint8_t count, const uint8_t* data) = 0; + virtual void command(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength); + virtual void state(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength); + uint8_t read(uint8_t& value) const; + uint8_t read(uint16_t& value) const; + uint8_t read(uint32_t& value) const; + uint8_t read(uint8_t* value) const; + uint8_t write(uint8_t value); + uint8_t write(uint16_t value); + uint8_t write(uint16_t position, uint16_t value); + uint8_t write(uint32_t value); + uint8_t write(const uint8_t* value); + protected: + PropertyID _id; + bool _writeEnable; + PropertyDataType _type; + uint16_t _maxElements; + uint8_t _access; + }; +} \ No newline at end of file diff --git a/src/knx/interface_object/table_object.cpp b/src/knx/interface_object/table_object.cpp index fc7b607e..7a6ef69a 100644 --- a/src/knx/interface_object/table_object.cpp +++ b/src/knx/interface_object/table_object.cpp @@ -4,409 +4,412 @@ #include -BeforeTablesUnloadCallback TableObject::_beforeTablesUnload = 0; -uint8_t TableObject::_tableUnloadCount = 0; - -void TableObject::beforeTablesUnloadCallback(BeforeTablesUnloadCallback func) -{ - _beforeTablesUnload = func; -} - -BeforeTablesUnloadCallback TableObject::beforeTablesUnloadCallback() -{ - return _beforeTablesUnload; -} - -TableObject::TableObject(Memory& memory, uint32_t staticTableAdr, uint32_t staticTableSize) - : _memory(memory) -{ - _staticTableAdr = staticTableAdr; - _staticTableSize = staticTableSize; -} - -TableObject::~TableObject() -{} - -void TableObject::beforeStateChange(LoadState& newState) +namespace Knx { - if (newState == LS_LOADED && _tableUnloadCount > 0) - _tableUnloadCount--; - - if (_tableUnloadCount > 0) - return; + BeforeTablesUnloadCallback TableObject::_beforeTablesUnload = 0; + uint8_t TableObject::_tableUnloadCount = 0; - if (newState == LS_UNLOADED) + void TableObject::beforeTablesUnloadCallback(BeforeTablesUnloadCallback func) { - _tableUnloadCount++; - - if (_beforeTablesUnload != 0) - _beforeTablesUnload(); + _beforeTablesUnload = func; } -} - -LoadState TableObject::loadState() -{ - return _state; -} -void TableObject::loadState(LoadState newState) -{ - if (newState == _state) - return; + BeforeTablesUnloadCallback TableObject::beforeTablesUnloadCallback() + { + return _beforeTablesUnload; + } - beforeStateChange(newState); - _state = newState; -} + TableObject::TableObject(Memory& memory, uint32_t staticTableAdr, uint32_t staticTableSize) + : _memory(memory) + { + _staticTableAdr = staticTableAdr; + _staticTableSize = staticTableSize; + } + TableObject::~TableObject() + {} -uint8_t* TableObject::save(uint8_t* buffer) -{ - //println("TableObject::save"); - allocTableStatic(); + void TableObject::beforeStateChange(LoadState& newState) + { + if (newState == LS_LOADED && _tableUnloadCount > 0) + _tableUnloadCount--; - buffer = pushByte(_state, buffer); + if (_tableUnloadCount > 0) + return; - buffer = pushInt(_size, buffer); + if (newState == LS_UNLOADED) + { + _tableUnloadCount++; - if (_data) - buffer = pushInt(_memory.toRelative(_data), buffer); - else - buffer = pushInt(0, buffer); + if (_beforeTablesUnload != 0) + _beforeTablesUnload(); + } + } - return InterfaceObject::save(buffer); -} + LoadState TableObject::loadState() + { + return _state; + } + void TableObject::loadState(LoadState newState) + { + if (newState == _state) + return; -const uint8_t* TableObject::restore(const uint8_t* buffer) -{ - //println("TableObject::restore"); + beforeStateChange(newState); + _state = newState; + } - uint8_t state = 0; - buffer = popByte(state, buffer); - _state = (LoadState)state; - buffer = popInt(_size, buffer); + uint8_t* TableObject::save(uint8_t* buffer) + { + //println("TableObject::save"); + allocTableStatic(); - uint32_t relativeAddress = 0; - buffer = popInt(relativeAddress, buffer); - //println(relativeAddress); + buffer = pushByte(_state, buffer); - if (relativeAddress != 0) - _data = _memory.toAbsolute(relativeAddress); - else - _data = 0; + buffer = pushInt(_size, buffer); - //println((uint32_t)_data); - return InterfaceObject::restore(buffer); -} + if (_data) + buffer = pushInt(_memory.toRelative(_data), buffer); + else + buffer = pushInt(0, buffer); -uint32_t TableObject::tableReference() -{ - return (uint32_t)_memory.toRelative(_data); -} + return InterfaceObject::save(buffer); + } -bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte) -{ - if (_staticTableAdr) - return false; - if (_data) + const uint8_t* TableObject::restore(const uint8_t* buffer) { - _memory.freeMemory(_data); - _data = 0; - } + //println("TableObject::restore"); - if (size == 0) - return true; + uint8_t state = 0; + buffer = popByte(state, buffer); + _state = (LoadState)state; - _data = _memory.allocMemory(size); + buffer = popInt(_size, buffer); - if (!_data) - return false; + uint32_t relativeAddress = 0; + buffer = popInt(relativeAddress, buffer); + //println(relativeAddress); - if (doFill) - { - uint32_t addr = _memory.toRelative(_data); + if (relativeAddress != 0) + _data = _memory.toAbsolute(relativeAddress); + else + _data = 0; - for (uint32_t i = 0; i < size; i++) - _memory.writeMemory(addr + i, 1, &fillByte); + //println((uint32_t)_data); + return InterfaceObject::restore(buffer); } - _size = size; - - return true; -} - - -void TableObject::allocTableStatic() -{ - if (_staticTableAdr && !_data) + uint32_t TableObject::tableReference() { - _data = _memory.toAbsolute(_staticTableAdr); - _size = _staticTableSize; - _memory.addNewUsedBlock(_data, _size); + return (uint32_t)_memory.toRelative(_data); } -} -void TableObject::loadEvent(const uint8_t* data) -{ - //printHex("TableObject::loadEvent 0x", data, 10); - switch (_state) + bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte) { - case LS_UNLOADED: - loadEventUnloaded(data); - break; + if (_staticTableAdr) + return false; - case LS_LOADING: - loadEventLoading(data); - break; + if (_data) + { + _memory.freeMemory(_data); + _data = 0; + } - case LS_LOADED: - loadEventLoaded(data); - break; + if (size == 0) + return true; - case LS_ERROR: - loadEventError(data); - break; + _data = _memory.allocMemory(size); - default: - /* do nothing */ - break; - } -} + if (!_data) + return false; -void TableObject::loadEventUnloaded(const uint8_t* data) -{ - uint8_t event = data[0]; + if (doFill) + { + uint32_t addr = _memory.toRelative(_data); - switch (event) - { - case LE_NOOP: - case LE_LOAD_COMPLETED: - case LE_ADDITIONAL_LOAD_CONTROLS: - case LE_UNLOAD: - break; + for (uint32_t i = 0; i < size; i++) + _memory.writeMemory(addr + i, 1, &fillByte); + } - case LE_START_LOADING: - loadState(LS_LOADING); - break; + _size = size; - default: - loadState(LS_ERROR); - errorCode(E_GOT_UNDEF_LOAD_CMD); + return true; } -} -void TableObject::loadEventLoading(const uint8_t* data) -{ - uint8_t event = data[0]; - switch (event) + void TableObject::allocTableStatic() { - case LE_NOOP: - case LE_START_LOADING: - break; - - case LE_LOAD_COMPLETED: - _memory.saveMemory(); - loadState(LS_LOADED); - break; - - case LE_UNLOAD: - loadState(LS_UNLOADED); - break; + if (_staticTableAdr && !_data) + { + _data = _memory.toAbsolute(_staticTableAdr); + _size = _staticTableSize; + _memory.addNewUsedBlock(_data, _size); + } + } - case LE_ADDITIONAL_LOAD_CONTROLS: - additionalLoadControls(data); - break; + void TableObject::loadEvent(const uint8_t* data) + { + //printHex("TableObject::loadEvent 0x", data, 10); + switch (_state) + { + case LS_UNLOADED: + loadEventUnloaded(data); + break; + + case LS_LOADING: + loadEventLoading(data); + break; + + case LS_LOADED: + loadEventLoaded(data); + break; + + case LS_ERROR: + loadEventError(data); + break; + + default: + /* do nothing */ + break; + } + } - default: - loadState(LS_ERROR); - errorCode(E_GOT_UNDEF_LOAD_CMD); + void TableObject::loadEventUnloaded(const uint8_t* data) + { + uint8_t event = data[0]; + + switch (event) + { + case LE_NOOP: + case LE_LOAD_COMPLETED: + case LE_ADDITIONAL_LOAD_CONTROLS: + case LE_UNLOAD: + break; + + case LE_START_LOADING: + loadState(LS_LOADING); + break; + + default: + loadState(LS_ERROR); + errorCode(E_GOT_UNDEF_LOAD_CMD); + } } -} -void TableObject::loadEventLoaded(const uint8_t* data) -{ - uint8_t event = data[0]; + void TableObject::loadEventLoading(const uint8_t* data) + { + uint8_t event = data[0]; + + switch (event) + { + case LE_NOOP: + case LE_START_LOADING: + break; + + case LE_LOAD_COMPLETED: + _memory.saveMemory(); + loadState(LS_LOADED); + break; + + case LE_UNLOAD: + loadState(LS_UNLOADED); + break; + + case LE_ADDITIONAL_LOAD_CONTROLS: + additionalLoadControls(data); + break; + + default: + loadState(LS_ERROR); + errorCode(E_GOT_UNDEF_LOAD_CMD); + } + } - switch (event) + void TableObject::loadEventLoaded(const uint8_t* data) { - case LE_NOOP: - case LE_LOAD_COMPLETED: - break; + uint8_t event = data[0]; + + switch (event) + { + case LE_NOOP: + case LE_LOAD_COMPLETED: + break; - case LE_START_LOADING: - loadState(LS_LOADING); - break; + case LE_START_LOADING: + loadState(LS_LOADING); + break; - case LE_UNLOAD: - loadState(LS_UNLOADED); + case LE_UNLOAD: + loadState(LS_UNLOADED); - //free nv memory - if (_data) - { - if (!_staticTableAdr) + //free nv memory + if (_data) { - _memory.freeMemory(_data); - _data = 0; + if (!_staticTableAdr) + { + _memory.freeMemory(_data); + _data = 0; + } } - } - break; + break; - case LE_ADDITIONAL_LOAD_CONTROLS: - loadState(LS_ERROR); - errorCode(E_INVALID_OPCODE); - break; + case LE_ADDITIONAL_LOAD_CONTROLS: + loadState(LS_ERROR); + errorCode(E_INVALID_OPCODE); + break; - default: - loadState(LS_ERROR); - errorCode(E_GOT_UNDEF_LOAD_CMD); + default: + loadState(LS_ERROR); + errorCode(E_GOT_UNDEF_LOAD_CMD); + } } -} -void TableObject::loadEventError(const uint8_t* data) -{ - uint8_t event = data[0]; + void TableObject::loadEventError(const uint8_t* data) + { + uint8_t event = data[0]; + + switch (event) + { + case LE_NOOP: + case LE_LOAD_COMPLETED: + case LE_ADDITIONAL_LOAD_CONTROLS: + case LE_START_LOADING: + break; + + case LE_UNLOAD: + loadState(LS_UNLOADED); + break; + + default: + loadState(LS_ERROR); + errorCode(E_GOT_UNDEF_LOAD_CMD); + } + } - switch (event) + void TableObject::additionalLoadControls(const uint8_t* data) { - case LE_NOOP: - case LE_LOAD_COMPLETED: - case LE_ADDITIONAL_LOAD_CONTROLS: - case LE_START_LOADING: - break; + if (data[1] != 0x0B) // Data Relative Allocation + { + loadState(LS_ERROR); + errorCode(E_INVALID_OPCODE); + return; + } - case LE_UNLOAD: - loadState(LS_UNLOADED); - break; + size_t size = ((data[2] << 24) | (data[3] << 16) | (data[4] << 8) | data[5]); + bool doFill = data[6] == 0x1; + uint8_t fillByte = data[7]; - default: + if (!allocTable(size, doFill, fillByte)) + { loadState(LS_ERROR); - errorCode(E_GOT_UNDEF_LOAD_CMD); + errorCode(E_MAX_TABLE_LENGTH_EXEEDED); + } } -} -void TableObject::additionalLoadControls(const uint8_t* data) -{ - if (data[1] != 0x0B) // Data Relative Allocation + uint8_t* TableObject::data() { - loadState(LS_ERROR); - errorCode(E_INVALID_OPCODE); - return; + return _data; } - size_t size = ((data[2] << 24) | (data[3] << 16) | (data[4] << 8) | data[5]); - bool doFill = data[6] == 0x1; - uint8_t fillByte = data[7]; + void TableObject::errorCode(ErrorCode errorCode) + { + uint8_t data = errorCode; + Property* prop = property(PID_ERROR_CODE); + prop->write(data); + } - if (!allocTable(size, doFill, fillByte)) + uint16_t TableObject::saveSize() { - loadState(LS_ERROR); - errorCode(E_MAX_TABLE_LENGTH_EXEEDED); + return 5 + InterfaceObject::saveSize() + sizeof(_size); } -} -uint8_t* TableObject::data() -{ - return _data; -} + void TableObject::initializeProperties(size_t propertiesSize, Property** properties) + { + Property* ownProperties[] = + { + new CallbackProperty(this, PID_LOAD_STATE_CONTROL, true, PDT_CONTROL, 1, ReadLv3 | WriteLv3, + [](TableObject * obj, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { + if (start == 0) + { + uint16_t currentNoOfElements = 1; + pushWord(currentNoOfElements, data); + return 1; + } -void TableObject::errorCode(ErrorCode errorCode) -{ - uint8_t data = errorCode; - Property* prop = property(PID_ERROR_CODE); - prop->write(data); -} + data[0] = obj->_state; + return 1; + }, + [](TableObject * obj, uint16_t start, uint8_t count, const uint8_t* data) -> uint8_t { + obj->loadEvent(data); + return 1; + }) + }; -uint16_t TableObject::saveSize() -{ - return 5 + InterfaceObject::saveSize() + sizeof(_size); -} + uint8_t ownPropertiesCount = sizeof(ownProperties) / sizeof(Property*); -void TableObject::initializeProperties(size_t propertiesSize, Property** properties) -{ - Property* ownProperties[] = + uint8_t propertyCount = propertiesSize / sizeof(Property*); + uint8_t allPropertiesCount = propertyCount + ownPropertiesCount; + + Property* allProperties[allPropertiesCount]; + memcpy(allProperties, properties, propertiesSize); + memcpy(allProperties + propertyCount, ownProperties, sizeof(ownProperties)); + + if (_staticTableAdr) + InterfaceObject::initializeProperties(sizeof(allProperties), allProperties); + else + initializeDynTableProperties(sizeof(allProperties), allProperties); + } + + void TableObject::initializeDynTableProperties(size_t propertiesSize, Property** properties) { - new CallbackProperty(this, PID_LOAD_STATE_CONTROL, true, PDT_CONTROL, 1, ReadLv3 | WriteLv3, - [](TableObject * obj, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { - if (start == 0) - { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); + Property* ownProperties[] = + { + new CallbackProperty(this, PID_TABLE_REFERENCE, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0, + [](TableObject * obj, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { + if (start == 0) + { + uint16_t currentNoOfElements = 1; + pushWord(currentNoOfElements, data); + return 1; + } + + if (obj->_state == LS_UNLOADED) + pushInt(0, data); + else + pushInt(obj->tableReference(), data); return 1; - } + }), + new CallbackProperty(this, PID_MCB_TABLE, false, PDT_GENERIC_08, 1, ReadLv3 | WriteLv0, + [](TableObject * obj, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { + if (obj->_state != LS_LOADED) + return 0; // need to check return code for invalid - data[0] = obj->_state; - return 1; - }, - [](TableObject * obj, uint16_t start, uint8_t count, const uint8_t* data) -> uint8_t { - obj->loadEvent(data); - return 1; - }) - }; + uint32_t segmentSize = obj->_size; + uint16_t crc16 = crc16Ccitt(obj->data(), segmentSize); - uint8_t ownPropertiesCount = sizeof(ownProperties) / sizeof(Property*); + pushInt(segmentSize, data); // Segment size + pushByte(0x00, data + 4); // CRC control byte -> 0: always valid + pushByte(0xFF, data + 5); // Read access 4 bits + Write access 4 bits + pushWord(crc16, data + 6); // CRC-16 CCITT of data - uint8_t propertyCount = propertiesSize / sizeof(Property*); - uint8_t allPropertiesCount = propertyCount + ownPropertiesCount; + return 1; + }), + new DataProperty(PID_ERROR_CODE, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint8_t)E_NO_FAULT) + }; - Property* allProperties[allPropertiesCount]; - memcpy(allProperties, properties, propertiesSize); - memcpy(allProperties + propertyCount, ownProperties, sizeof(ownProperties)); + uint8_t ownPropertiesCount = sizeof(ownProperties) / sizeof(Property*); - if (_staticTableAdr) - InterfaceObject::initializeProperties(sizeof(allProperties), allProperties); - else - initializeDynTableProperties(sizeof(allProperties), allProperties); -} + uint8_t propertyCount = propertiesSize / sizeof(Property*); + uint8_t allPropertiesCount = propertyCount + ownPropertiesCount; -void TableObject::initializeDynTableProperties(size_t propertiesSize, Property** properties) -{ - Property* ownProperties[] = - { - new CallbackProperty(this, PID_TABLE_REFERENCE, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0, - [](TableObject * obj, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { - if (start == 0) - { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); - return 1; - } - - if (obj->_state == LS_UNLOADED) - pushInt(0, data); - else - pushInt(obj->tableReference(), data); - return 1; - }), - new CallbackProperty(this, PID_MCB_TABLE, false, PDT_GENERIC_08, 1, ReadLv3 | WriteLv0, - [](TableObject * obj, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { - if (obj->_state != LS_LOADED) - return 0; // need to check return code for invalid - - uint32_t segmentSize = obj->_size; - uint16_t crc16 = crc16Ccitt(obj->data(), segmentSize); - - pushInt(segmentSize, data); // Segment size - pushByte(0x00, data + 4); // CRC control byte -> 0: always valid - pushByte(0xFF, data + 5); // Read access 4 bits + Write access 4 bits - pushWord(crc16, data + 6); // CRC-16 CCITT of data - - return 1; - }), - new DataProperty(PID_ERROR_CODE, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint8_t)E_NO_FAULT) - }; - - uint8_t ownPropertiesCount = sizeof(ownProperties) / sizeof(Property*); - - uint8_t propertyCount = propertiesSize / sizeof(Property*); - uint8_t allPropertiesCount = propertyCount + ownPropertiesCount; - - Property* allProperties[allPropertiesCount]; - memcpy(allProperties, properties, propertiesSize); - memcpy(allProperties + propertyCount, ownProperties, sizeof(ownProperties)); - - InterfaceObject::initializeProperties(sizeof(allProperties), allProperties); + Property* allProperties[allPropertiesCount]; + memcpy(allProperties, properties, propertiesSize); + memcpy(allProperties + propertyCount, ownProperties, sizeof(ownProperties)); + + InterfaceObject::initializeProperties(sizeof(allProperties), allProperties); + } } \ No newline at end of file diff --git a/src/knx/interface_object/table_object.h b/src/knx/interface_object/table_object.h index 914bb2e8..e7547e56 100644 --- a/src/knx/interface_object/table_object.h +++ b/src/knx/interface_object/table_object.h @@ -2,93 +2,96 @@ #include "interface_object.h" -class Memory; +namespace Knx +{ + class Memory; -typedef void (*BeforeTablesUnloadCallback)(); + typedef void (*BeforeTablesUnloadCallback)(); -/** - * This class provides common functionality for interface objects that are configured by ETS with MemorWrite. - */ -class TableObject: public InterfaceObject -{ - friend class Memory; + /** + * This class provides common functionality for interface objects that are configured by ETS with MemorWrite. + */ + class TableObject: public InterfaceObject + { + friend class Memory; - public: - /** - * The constuctor. - * @param memory The instance of the memory management class to use. - */ - TableObject(Memory& memory, uint32_t staticTableAdr = 0, uint32_t staticTableSize = 0); + public: + /** + * The constuctor. + * @param memory The instance of the memory management class to use. + */ + TableObject(Memory& memory, uint32_t staticTableAdr = 0, uint32_t staticTableSize = 0); - /** - * The destructor. - */ - virtual ~TableObject(); - /** - * This method returns the ::LoadState of the interface object. - */ - LoadState loadState(); - uint8_t* save(uint8_t* buffer) override; - const uint8_t* restore(const uint8_t* buffer) override; - uint16_t saveSize() override; + /** + * The destructor. + */ + virtual ~TableObject(); + /** + * This method returns the ::LoadState of the interface object. + */ + LoadState loadState(); + uint8_t* save(uint8_t* buffer) override; + const uint8_t* restore(const uint8_t* buffer) override; + uint16_t saveSize() override; - static void beforeTablesUnloadCallback(BeforeTablesUnloadCallback func); - static BeforeTablesUnloadCallback beforeTablesUnloadCallback(); + static void beforeTablesUnloadCallback(BeforeTablesUnloadCallback func); + static BeforeTablesUnloadCallback beforeTablesUnloadCallback(); - protected: - /** - * This method is called before the interface object enters a new ::LoadState. - * If there is a error changing the state newState should be set to ::LS_ERROR and errorCode() - * to a reason for the failure. - */ - virtual void beforeStateChange(LoadState& newState); + protected: + /** + * This method is called before the interface object enters a new ::LoadState. + * If there is a error changing the state newState should be set to ::LS_ERROR and errorCode() + * to a reason for the failure. + */ + virtual void beforeStateChange(LoadState& newState); - /** - * returns the internal data of the interface object. This pointer belongs to the TableObject class and - * must not be written at nor freed. - */ - uint8_t* data(); - /** - * Set the reason for a state change failure. - */ - void errorCode(ErrorCode errorCode); + /** + * returns the internal data of the interface object. This pointer belongs to the TableObject class and + * must not be written at nor freed. + */ + uint8_t* data(); + /** + * Set the reason for a state change failure. + */ + void errorCode(ErrorCode errorCode); - void initializeProperties(size_t propertiesSize, Property** properties) override; + void initializeProperties(size_t propertiesSize, Property** properties) override; - static BeforeTablesUnloadCallback _beforeTablesUnload; + static BeforeTablesUnloadCallback _beforeTablesUnload; - Memory& _memory; + Memory& _memory; - private: - uint32_t tableReference(); - bool allocTable(uint32_t size, bool doFill, uint8_t fillByte); - void allocTableStatic(); - void initializeDynTableProperties(size_t propertiesSize, Property** properties); - void loadEvent(const uint8_t* data); - void loadEventUnloaded(const uint8_t* data); - void loadEventLoading(const uint8_t* data); - void loadEventLoaded(const uint8_t* data); - void loadEventError(const uint8_t* data); - void additionalLoadControls(const uint8_t* data); + private: + uint32_t tableReference(); + bool allocTable(uint32_t size, bool doFill, uint8_t fillByte); + void allocTableStatic(); + void initializeDynTableProperties(size_t propertiesSize, Property** properties); + void loadEvent(const uint8_t* data); + void loadEventUnloaded(const uint8_t* data); + void loadEventLoading(const uint8_t* data); + void loadEventLoaded(const uint8_t* data); + void loadEventError(const uint8_t* data); + void additionalLoadControls(const uint8_t* data); - /** - * set the ::LoadState of the interface object. - * - * Calls beforeStateChange(). - * - * @param newState the new ::LoadState - */ - void loadState(LoadState newState); - LoadState _state = LS_UNLOADED; - uint8_t* _data = 0; - static uint8_t _tableUnloadCount; - uint32_t _staticTableAdr; - uint32_t _staticTableSize; + /** + * set the ::LoadState of the interface object. + * + * Calls beforeStateChange(). + * + * @param newState the new ::LoadState + */ + void loadState(LoadState newState); + LoadState _state = LS_UNLOADED; + uint8_t* _data = 0; + static uint8_t _tableUnloadCount; + uint32_t _staticTableAdr; + uint32_t _staticTableSize; - /** - * used to store size of data() in allocTable(), needed for calculation of crc in PID_MCB_TABLE. - * This value is also saved and restored. - * The size of the memory block cannot be used because it is changed during alignment to page size. - */ - uint32_t _size = 0; -}; + /** + * used to store size of data() in allocTable(), needed for calculation of crc in PID_MCB_TABLE. + * This value is also saved and restored. + * The size of the memory block cannot be used because it is changed during alignment to page size. + */ + uint32_t _size = 0; + }; +} \ No newline at end of file diff --git a/src/knx/ip/bau57B0.cpp b/src/knx/ip/bau57B0.cpp index 70619690..e0905dde 100644 --- a/src/knx/ip/bau57B0.cpp +++ b/src/knx/ip/bau57B0.cpp @@ -5,163 +5,166 @@ #include #include -using namespace std; +namespace Knx +{ + using namespace std; -Bau57B0::Bau57B0(Platform& platform) - : BauSystemBDevice(platform), DataLinkLayerCallbacks(), - _ipParameters(_deviceObj, platform), - _dlLayer(_deviceObj, _ipParameters, _netLayer.getInterface(), _platform, (DataLinkLayerCallbacks*) this) + Bau57B0::Bau57B0(Platform& platform) + : BauSystemBDevice(platform), DataLinkLayerCallbacks(), + _ipParameters(_deviceObj, platform), + _dlLayer(_deviceObj, _ipParameters, _netLayer.getInterface(), _platform, (DataLinkLayerCallbacks*) this) #ifdef USE_CEMI_SERVER - , _cemiServer(*this) + , _cemiServer(*this) #endif -{ - _netLayer.getInterface().dataLinkLayer(_dlLayer); + { + _netLayer.getInterface().dataLinkLayer(_dlLayer); #ifdef USE_CEMI_SERVER - _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_IP); - _cemiServer.dataLinkLayer(_dlLayer); - _dlLayer.cemiServer(_cemiServer); - _memory.addSaveRestore(&_cemiServerObject); + _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_IP); + _cemiServer.dataLinkLayer(_dlLayer); + _dlLayer.cemiServer(_cemiServer); + _memory.addSaveRestore(&_cemiServerObject); #endif - _memory.addSaveRestore(&_ipParameters); - - // Set Mask Version in Device Object depending on the BAU - _deviceObj.maskVersion(0x57B0); - - // Set which interface objects are available in the device object - // This differs from BAU to BAU with different medium types. - // See PID_IO_LIST - Property* prop = _deviceObj.property(PID_IO_LIST); - prop->write(1, (uint16_t) OT_DEVICE); - prop->write(2, (uint16_t) OT_ADDR_TABLE); - prop->write(3, (uint16_t) OT_ASSOC_TABLE); - prop->write(4, (uint16_t) OT_GRP_OBJ_TABLE); - prop->write(5, (uint16_t) OT_APPLICATION_PROG); - prop->write(6, (uint16_t) OT_IP_PARAMETER); + _memory.addSaveRestore(&_ipParameters); + + // Set Mask Version in Device Object depending on the BAU + _deviceObj.maskVersion(0x57B0); + + // Set which interface objects are available in the device object + // This differs from BAU to BAU with different medium types. + // See PID_IO_LIST + Property* prop = _deviceObj.property(PID_IO_LIST); + prop->write(1, (uint16_t) OT_DEVICE); + prop->write(2, (uint16_t) OT_ADDR_TABLE); + prop->write(3, (uint16_t) OT_ASSOC_TABLE); + prop->write(4, (uint16_t) OT_GRP_OBJ_TABLE); + prop->write(5, (uint16_t) OT_APPLICATION_PROG); + prop->write(6, (uint16_t) OT_IP_PARAMETER); #if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER) - prop->write(7, (uint16_t) OT_SECURITY); - prop->write(8, (uint16_t) OT_CEMI_SERVER); + prop->write(7, (uint16_t) OT_SECURITY); + prop->write(8, (uint16_t) OT_CEMI_SERVER); #elif defined(USE_DATASECURE) - prop->write(7, (uint16_t) OT_SECURITY); + prop->write(7, (uint16_t) OT_SECURITY); #elif defined(USE_CEMI_SERVER) - prop->write(7, (uint16_t) OT_CEMI_SERVER); + prop->write(7, (uint16_t) OT_CEMI_SERVER); #endif -} + } -InterfaceObject* Bau57B0::getInterfaceObject(uint8_t idx) -{ - switch (idx) + InterfaceObject* Bau57B0::getInterfaceObject(uint8_t idx) { - case 0: - return &_deviceObj; + switch (idx) + { + case 0: + return &_deviceObj; - case 1: - return &_addrTable; + case 1: + return &_addrTable; - case 2: - return &_assocTable; + case 2: + return &_assocTable; - case 3: - return &_groupObjTable; + case 3: + return &_groupObjTable; - case 4: - return &_appProgram; + case 4: + return &_appProgram; - case 5: // would be app_program 2 - return nullptr; + case 5: // would be app_program 2 + return nullptr; - case 6: - return &_ipParameters; + case 6: + return &_ipParameters; #if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER) - case 7: - return &_secIfObj; + case 7: + return &_secIfObj; - case 8: - return &_cemiServerObject; + case 8: + return &_cemiServerObject; #elif defined(USE_CEMI_SERVER) - case 7: - return &_cemiServerObject; + case 7: + return &_cemiServerObject; #elif defined(USE_DATASECURE) - case 7: - return &_secIfObj; + case 7: + return &_secIfObj; #endif - default: - return nullptr; + default: + return nullptr; + } } -} - -InterfaceObject* Bau57B0::getInterfaceObject(ObjectType objectType, uint16_t objectInstance) -{ - // We do not use it right now. - // Required for coupler mode as there are multiple router objects for example - (void) objectInstance; - switch (objectType) + InterfaceObject* Bau57B0::getInterfaceObject(ObjectType objectType, uint16_t objectInstance) { - case OT_DEVICE: - return &_deviceObj; + // We do not use it right now. + // Required for coupler mode as there are multiple router objects for example + (void) objectInstance; + + switch (objectType) + { + case OT_DEVICE: + return &_deviceObj; - case OT_ADDR_TABLE: - return &_addrTable; + case OT_ADDR_TABLE: + return &_addrTable; - case OT_ASSOC_TABLE: - return &_assocTable; + case OT_ASSOC_TABLE: + return &_assocTable; - case OT_GRP_OBJ_TABLE: - return &_groupObjTable; + case OT_GRP_OBJ_TABLE: + return &_groupObjTable; - case OT_APPLICATION_PROG: - return &_appProgram; + case OT_APPLICATION_PROG: + return &_appProgram; - case OT_IP_PARAMETER: - return &_ipParameters; + case OT_IP_PARAMETER: + return &_ipParameters; #ifdef USE_DATASECURE - case OT_SECURITY: - return &_secIfObj; + case OT_SECURITY: + return &_secIfObj; #endif #ifdef USE_CEMI_SERVER - case OT_CEMI_SERVER: - return &_cemiServerObject; + case OT_CEMI_SERVER: + return &_cemiServerObject; #endif - default: - return nullptr; + default: + return nullptr; + } } -} -void Bau57B0::doMasterReset(EraseCode eraseCode, uint8_t channel) -{ - // Common SystemB objects - BauSystemB::doMasterReset(eraseCode, channel); + void Bau57B0::doMasterReset(EraseCode eraseCode, uint8_t channel) + { + // Common SystemB objects + BauSystemB::doMasterReset(eraseCode, channel); - _ipParameters.masterReset(eraseCode, channel); -} + _ipParameters.masterReset(eraseCode, channel); + } -bool Bau57B0::enabled() -{ - return _dlLayer.enabled(); -} + bool Bau57B0::enabled() + { + return _dlLayer.enabled(); + } -void Bau57B0::enabled(bool value) -{ - _dlLayer.enabled(value); -} + void Bau57B0::enabled(bool value) + { + _dlLayer.enabled(value); + } -void Bau57B0::loop() -{ - _dlLayer.loop(); - BauSystemBDevice::loop(); + void Bau57B0::loop() + { + _dlLayer.loop(); + BauSystemBDevice::loop(); #ifdef USE_CEMI_SERVER - _cemiServer.loop(); + _cemiServer.loop(); #endif -} + } -IpDataLinkLayer* Bau57B0::getDataLinkLayer() -{ - return (IpDataLinkLayer*)&_dlLayer; + IpDataLinkLayer* Bau57B0::getDataLinkLayer() + { + return (IpDataLinkLayer*)&_dlLayer; + } } \ No newline at end of file diff --git a/src/knx/ip/bau57B0.h b/src/knx/ip/bau57B0.h index d67bf075..ddc2be12 100644 --- a/src/knx/ip/bau57B0.h +++ b/src/knx/ip/bau57B0.h @@ -7,25 +7,28 @@ #include "../bau/bau_systemB_device.h" #include "../cemi_server/cemi_server_object.h" -class Bau57B0 : public BauSystemBDevice, public DataLinkLayerCallbacks +namespace Knx { - public: - Bau57B0(Platform& platform); - void loop() override; - bool enabled() override; - void enabled(bool value) override; + class Bau57B0 : public BauSystemBDevice, public DataLinkLayerCallbacks + { + public: + Bau57B0(Platform& platform); + void loop() override; + bool enabled() override; + void enabled(bool value) override; - IpDataLinkLayer* getDataLinkLayer(); - protected: - InterfaceObject* getInterfaceObject(uint8_t idx); - InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance); + IpDataLinkLayer* getDataLinkLayer(); + protected: + InterfaceObject* getInterfaceObject(uint8_t idx); + InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance); - void doMasterReset(EraseCode eraseCode, uint8_t channel) override; - private: - IpParameterObject _ipParameters; - IpDataLinkLayer _dlLayer; + void doMasterReset(EraseCode eraseCode, uint8_t channel) override; + private: + IpParameterObject _ipParameters; + IpDataLinkLayer _dlLayer; #ifdef USE_CEMI_SERVER - CemiServer _cemiServer; - CemiServerObject _cemiServerObject; + CemiServer _cemiServer; + CemiServerObject _cemiServerObject; #endif -}; + }; +} \ No newline at end of file diff --git a/src/knx/ip/ip_data_link_layer.cpp b/src/knx/ip/ip_data_link_layer.cpp index d491f0dd..75d9c4ff 100644 --- a/src/knx/ip/ip_data_link_layer.cpp +++ b/src/knx/ip/ip_data_link_layer.cpp @@ -31,412 +31,414 @@ #define MIN_LEN_CEMI 10 -IpDataLinkLayer::IpDataLinkLayer(DeviceObject& devObj, IpParameterObject& ipParam, - NetworkLayerEntity& netLayerEntity, Platform& platform, DataLinkLayerCallbacks* dllcb) : DataLinkLayer(devObj, netLayerEntity, platform), _ipParameters(ipParam), _dllcb(dllcb) +namespace Knx { -} + IpDataLinkLayer::IpDataLinkLayer(DeviceObject& devObj, IpParameterObject& ipParam, + NetworkLayerEntity& netLayerEntity, Platform& platform, DataLinkLayerCallbacks* dllcb) : DataLinkLayer(devObj, netLayerEntity, platform), _ipParameters(ipParam), _dllcb(dllcb) + { + } -bool IpDataLinkLayer::sendFrame(CemiFrame& frame) -{ - KnxIpRoutingIndication packet(frame); + bool IpDataLinkLayer::sendFrame(CemiFrame& frame) + { + KnxIpRoutingIndication packet(frame); - // only send 50 packet per second: see KNX 3.2.6 p.6 - if (isSendLimitReached()) - return false; + // only send 50 packet per second: see KNX 3.2.6 p.6 + if (isSendLimitReached()) + return false; - bool success = sendMulicast(packet); + bool success = sendMulicast(packet); #ifdef KNX_ACTIVITYCALLBACK - if (_dllcb) - _dllcb->activity((_netIndex << KNX_ACTIVITYCALLBACK_NET) | (KNX_ACTIVITYCALLBACK_DIR_SEND << KNX_ACTIVITYCALLBACK_DIR)); + if (_dllcb) + _dllcb->activity((_netIndex << KNX_ACTIVITYCALLBACK_NET) | (KNX_ACTIVITYCALLBACK_DIR_SEND << KNX_ACTIVITYCALLBACK_DIR)); #endif - dataConReceived(frame, success); - return success; -} + dataConReceived(frame, success); + return success; + } #ifdef KNX_TUNNELING -void IpDataLinkLayer::dataRequestToTunnel(CemiFrame& frame) -{ - if (frame.addressType() == AddressType::GroupAddress) + void IpDataLinkLayer::dataRequestToTunnel(CemiFrame& frame) { - for (int i = 0; i < KNX_TUNNELING; i++) - if (tunnels[i].ChannelId != 0 && tunnels[i].IndividualAddress == frame.sourceAddress()) - sendFrameToTunnel(&tunnels[i], frame); - - //TODO check if source is from tunnel - return; - } + if (frame.addressType() == AddressType::GroupAddress) + { + for (int i = 0; i < KNX_TUNNELING; i++) + if (tunnels[i].ChannelId != 0 && tunnels[i].IndividualAddress == frame.sourceAddress()) + sendFrameToTunnel(&tunnels[i], frame); - KnxIpTunnelConnection* tun = nullptr; + //TODO check if source is from tunnel + return; + } - for (int i = 0; i < KNX_TUNNELING; i++) - { - if (tunnels[i].IndividualAddress == frame.sourceAddress()) - continue; + KnxIpTunnelConnection* tun = nullptr; - if (tunnels[i].IndividualAddress == frame.destinationAddress()) + for (int i = 0; i < KNX_TUNNELING; i++) { - tun = &tunnels[i]; - break; + if (tunnels[i].IndividualAddress == frame.sourceAddress()) + continue; + + if (tunnels[i].IndividualAddress == frame.destinationAddress()) + { + tun = &tunnels[i]; + break; + } } - } - if (tun == nullptr) - { - for (int i = 0; i < KNX_TUNNELING; i++) + if (tun == nullptr) { - if (tunnels[i].IsConfig) + for (int i = 0; i < KNX_TUNNELING; i++) { + if (tunnels[i].IsConfig) + { #ifdef KNX_LOG_TUNNELING - println("Found config Channel"); + println("Found config Channel"); #endif - tun = &tunnels[i]; - break; + tun = &tunnels[i]; + break; + } } } - } - if (tun == nullptr) - { + if (tun == nullptr) + { #ifdef KNX_LOG_TUNNELING - print("Found no Tunnel for IA: "); - println(frame.destinationAddress(), 16); + print("Found no Tunnel for IA: "); + println(frame.destinationAddress(), 16); #endif - return; - } - - sendFrameToTunnel(tun, frame); -} - -void IpDataLinkLayer::dataConfirmationToTunnel(CemiFrame& frame) -{ - if (frame.addressType() == AddressType::GroupAddress) - { - for (int i = 0; i < KNX_TUNNELING; i++) - if (tunnels[i].ChannelId != 0 && tunnels[i].IndividualAddress == frame.sourceAddress()) - sendFrameToTunnel(&tunnels[i], frame); + return; + } - //TODO check if source is from tunnel - return; + sendFrameToTunnel(tun, frame); } - KnxIpTunnelConnection* tun = nullptr; - - for (int i = 0; i < KNX_TUNNELING; i++) + void IpDataLinkLayer::dataConfirmationToTunnel(CemiFrame& frame) { - if (tunnels[i].IndividualAddress == frame.destinationAddress()) - continue; - - if (tunnels[i].IndividualAddress == frame.sourceAddress()) + if (frame.addressType() == AddressType::GroupAddress) { - tun = &tunnels[i]; - break; + for (int i = 0; i < KNX_TUNNELING; i++) + if (tunnels[i].ChannelId != 0 && tunnels[i].IndividualAddress == frame.sourceAddress()) + sendFrameToTunnel(&tunnels[i], frame); + + //TODO check if source is from tunnel + return; } - } - if (tun == nullptr) - { + KnxIpTunnelConnection* tun = nullptr; + for (int i = 0; i < KNX_TUNNELING; i++) { - if (tunnels[i].IsConfig) + if (tunnels[i].IndividualAddress == frame.destinationAddress()) + continue; + + if (tunnels[i].IndividualAddress == frame.sourceAddress()) { -#ifdef KNX_LOG_TUNNELING - println("Found config Channel"); -#endif tun = &tunnels[i]; break; } } - } - if (tun == nullptr) - { + if (tun == nullptr) + { + for (int i = 0; i < KNX_TUNNELING; i++) + { + if (tunnels[i].IsConfig) + { #ifdef KNX_LOG_TUNNELING - print("Found no Tunnel for IA: "); - println(frame.destinationAddress(), 16); + println("Found config Channel"); #endif - return; - } - - sendFrameToTunnel(tun, frame); -} + tun = &tunnels[i]; + break; + } + } + } -void IpDataLinkLayer::dataIndicationToTunnel(CemiFrame& frame) -{ - if (frame.addressType() == AddressType::GroupAddress) - { - for (int i = 0; i < KNX_TUNNELING; i++) - if (tunnels[i].ChannelId != 0 && tunnels[i].IndividualAddress != frame.sourceAddress()) - sendFrameToTunnel(&tunnels[i], frame); + if (tun == nullptr) + { +#ifdef KNX_LOG_TUNNELING + print("Found no Tunnel for IA: "); + println(frame.destinationAddress(), 16); +#endif + return; + } - return; + sendFrameToTunnel(tun, frame); } - KnxIpTunnelConnection* tun = nullptr; - - for (int i = 0; i < KNX_TUNNELING; i++) + void IpDataLinkLayer::dataIndicationToTunnel(CemiFrame& frame) { - if (tunnels[i].ChannelId == 0 || tunnels[i].IndividualAddress == frame.sourceAddress()) - continue; - - if (tunnels[i].IndividualAddress == frame.destinationAddress()) + if (frame.addressType() == AddressType::GroupAddress) { - tun = &tunnels[i]; - break; + for (int i = 0; i < KNX_TUNNELING; i++) + if (tunnels[i].ChannelId != 0 && tunnels[i].IndividualAddress != frame.sourceAddress()) + sendFrameToTunnel(&tunnels[i], frame); + + return; } - } - if (tun == nullptr) - { + KnxIpTunnelConnection* tun = nullptr; + for (int i = 0; i < KNX_TUNNELING; i++) { - if (tunnels[i].IsConfig) + if (tunnels[i].ChannelId == 0 || tunnels[i].IndividualAddress == frame.sourceAddress()) + continue; + + if (tunnels[i].IndividualAddress == frame.destinationAddress()) { -#ifdef KNX_LOG_TUNNELING - println("Found config Channel"); -#endif tun = &tunnels[i]; break; } } - } - if (tun == nullptr) - { + if (tun == nullptr) + { + for (int i = 0; i < KNX_TUNNELING; i++) + { + if (tunnels[i].IsConfig) + { #ifdef KNX_LOG_TUNNELING - print("Found no Tunnel for IA: "); - println(frame.destinationAddress(), 16); + println("Found config Channel"); #endif - return; - } - - sendFrameToTunnel(tun, frame); -} + tun = &tunnels[i]; + break; + } + } + } -void IpDataLinkLayer::sendFrameToTunnel(KnxIpTunnelConnection* tunnel, CemiFrame& frame) -{ + if (tun == nullptr) + { #ifdef KNX_LOG_TUNNELING - print("Send to Channel: "); - println(tunnel->ChannelId, 16); + print("Found no Tunnel for IA: "); + println(frame.destinationAddress(), 16); #endif - KnxIpTunnelingRequest req(frame); - req.connectionHeader().sequenceCounter(tunnel->SequenceCounter_S++); - req.connectionHeader().length(LEN_CH); - req.connectionHeader().channelId(tunnel->ChannelId); - - if (frame.messageCode() != L_data_req && frame.messageCode() != L_data_con && frame.messageCode() != L_data_ind) - req.serviceTypeIdentifier(DeviceConfigurationRequest); + return; + } + sendFrameToTunnel(tun, frame); + } - sendUnicast(tunnel->IpAddress, tunnel->PortData, req); -} + void IpDataLinkLayer::sendFrameToTunnel(KnxIpTunnelConnection* tunnel, CemiFrame& frame) + { +#ifdef KNX_LOG_TUNNELING + print("Send to Channel: "); + println(tunnel->ChannelId, 16); +#endif + KnxIpTunnelingRequest req(frame); + req.connectionHeader().sequenceCounter(tunnel->SequenceCounter_S++); + req.connectionHeader().length(LEN_CH); + req.connectionHeader().channelId(tunnel->ChannelId); -bool IpDataLinkLayer::isTunnelAddress(uint16_t addr) -{ - if (addr == 0) - return false; // 0.0.0 is not a valid tunnel address and is used as default value + if (frame.messageCode() != L_data_req && frame.messageCode() != L_data_con && frame.messageCode() != L_data_ind) + req.serviceTypeIdentifier(DeviceConfigurationRequest); - for (int i = 0; i < KNX_TUNNELING; i++) - if (tunnels[i].IndividualAddress == addr) - return true; - return false; -} + sendUnicast(tunnel->IpAddress, tunnel->PortData, req); + } -bool IpDataLinkLayer::isSentToTunnel(uint16_t address, bool isGrpAddr) -{ - if (isGrpAddr) + bool IpDataLinkLayer::isTunnelAddress(uint16_t addr) { + if (addr == 0) + return false; // 0.0.0 is not a valid tunnel address and is used as default value + for (int i = 0; i < KNX_TUNNELING; i++) - if (tunnels[i].ChannelId != 0) + if (tunnels[i].IndividualAddress == addr) return true; return false; } - else + + bool IpDataLinkLayer::isSentToTunnel(uint16_t address, bool isGrpAddr) { - for (int i = 0; i < KNX_TUNNELING; i++) - if (tunnels[i].ChannelId != 0 && tunnels[i].IndividualAddress == address) - return true; + if (isGrpAddr) + { + for (int i = 0; i < KNX_TUNNELING; i++) + if (tunnels[i].ChannelId != 0) + return true; - return false; + return false; + } + else + { + for (int i = 0; i < KNX_TUNNELING; i++) + if (tunnels[i].ChannelId != 0 && tunnels[i].IndividualAddress == address) + return true; + + return false; + } } -} #endif -void IpDataLinkLayer::loop() -{ - if (!_enabled) - return; + void IpDataLinkLayer::loop() + { + if (!_enabled) + return; #ifdef KNX_TUNNELING - for (int i = 0; i < KNX_TUNNELING; i++) - { - if (tunnels[i].ChannelId != 0) + for (int i = 0; i < KNX_TUNNELING; i++) { - if (millis() - tunnels[i].lastHeartbeat > 120000) + if (tunnels[i].ChannelId != 0) { + if (millis() - tunnels[i].lastHeartbeat > 120000) + { #ifdef KNX_LOG_TUNNELING - print("Closed Tunnel 0x"); - print(tunnels[i].ChannelId, 16); - println(" due to no heartbeat in 2 minutes"); + print("Closed Tunnel 0x"); + print(tunnels[i].ChannelId, 16); + println(" due to no heartbeat in 2 minutes"); #endif - KnxIpDisconnectRequest discReq; - discReq.channelId(tunnels[i].ChannelId); - discReq.hpaiCtrl().length(LEN_IPHPAI); - discReq.hpaiCtrl().code(IPV4_UDP); - discReq.hpaiCtrl().ipAddress(tunnels[i].IpAddress); - discReq.hpaiCtrl().ipPortNumber(tunnels[i].PortCtrl); - sendUnicast(tunnels[i].IpAddress, tunnels[i].PortCtrl, discReq); - tunnels[i].Reset(); - } + KnxIpDisconnectRequest discReq; + discReq.channelId(tunnels[i].ChannelId); + discReq.hpaiCtrl().length(LEN_IPHPAI); + discReq.hpaiCtrl().code(IPV4_UDP); + discReq.hpaiCtrl().ipAddress(tunnels[i].IpAddress); + discReq.hpaiCtrl().ipPortNumber(tunnels[i].PortCtrl); + sendUnicast(tunnels[i].IpAddress, tunnels[i].PortCtrl, discReq); + tunnels[i].Reset(); + } - break; + break; + } } - } #endif - uint8_t buffer[512]; - uint16_t remotePort = 0; - uint32_t remoteAddr = 0; - int len = _platform.readBytesMultiCast(buffer, 512, remoteAddr, remotePort); + uint8_t buffer[512]; + uint16_t remotePort = 0; + uint32_t remoteAddr = 0; + int len = _platform.readBytesMultiCast(buffer, 512, remoteAddr, remotePort); - if (len <= 0) - return; + if (len <= 0) + return; - if (len < KNXIP_HEADER_LEN) - return; + if (len < KNXIP_HEADER_LEN) + return; - if (buffer[0] != KNXIP_HEADER_LEN - || buffer[1] != KNXIP_PROTOCOL_VERSION) - return; + if (buffer[0] != KNXIP_HEADER_LEN + || buffer[1] != KNXIP_PROTOCOL_VERSION) + return; #ifdef KNX_ACTIVITYCALLBACK - if (_dllcb) - _dllcb->activity((_netIndex << KNX_ACTIVITYCALLBACK_NET) | (KNX_ACTIVITYCALLBACK_DIR_RECV << KNX_ACTIVITYCALLBACK_DIR)); + if (_dllcb) + _dllcb->activity((_netIndex << KNX_ACTIVITYCALLBACK_NET) | (KNX_ACTIVITYCALLBACK_DIR_RECV << KNX_ACTIVITYCALLBACK_DIR)); #endif - uint16_t code; - popWord(code, buffer + 2); + uint16_t code; + popWord(code, buffer + 2); - LOGGER.info("loop: %s", enum_name((KnxIpServiceType)code)); + LOGGER.info("loop: %s", enum_name((KnxIpServiceType)code)); - switch ((KnxIpServiceType)code) - { - case RoutingIndication: + switch ((KnxIpServiceType)code) { - KnxIpRoutingIndication routingIndication(buffer, len); - frameReceived(routingIndication.frame()); - break; - } + case RoutingIndication: + { + KnxIpRoutingIndication routingIndication(buffer, len); + frameReceived(routingIndication.frame()); + break; + } - case SearchRequest: - { - KnxIpSearchRequest searchRequest(buffer, len); - KnxIpSearchResponse searchResponse(_ipParameters, _deviceObject); + case SearchRequest: + { + KnxIpSearchRequest searchRequest(buffer, len); + KnxIpSearchResponse searchResponse(_ipParameters, _deviceObject); - auto hpai = searchRequest.hpai(); + auto hpai = searchRequest.hpai(); #ifdef KNX_ACTIVITYCALLBACK - if (_dllcb) - _dllcb->activity((_netIndex << KNX_ACTIVITYCALLBACK_NET) | (KNX_ACTIVITYCALLBACK_DIR_SEND << KNX_ACTIVITYCALLBACK_DIR) | (KNX_ACTIVITYCALLBACK_IPUNICAST)); + if (_dllcb) + _dllcb->activity((_netIndex << KNX_ACTIVITYCALLBACK_NET) | (KNX_ACTIVITYCALLBACK_DIR_SEND << KNX_ACTIVITYCALLBACK_DIR) | (KNX_ACTIVITYCALLBACK_IPUNICAST)); #endif - sendUnicast(hpai.ipAddress(), hpai.ipPortNumber(), searchResponse); - break; - } + sendUnicast(hpai.ipAddress(), hpai.ipPortNumber(), searchResponse); + break; + } #ifdef KNX_TUNNELING - case SearchRequestExt: - { - loopHandleSearchRequestExtended(buffer, len); - break; - } + case SearchRequestExt: + { + loopHandleSearchRequestExtended(buffer, len); + break; + } - case ConnectRequest: - { - loopHandleConnectRequest(buffer, len, remoteAddr, remotePort); - break; - } + case ConnectRequest: + { + loopHandleConnectRequest(buffer, len, remoteAddr, remotePort); + break; + } - case ConnectionStateRequest: - { - loopHandleConnectionStateRequest(buffer, len); - break; - } + case ConnectionStateRequest: + { + loopHandleConnectionStateRequest(buffer, len); + break; + } - case DisconnectRequest: - { - loopHandleDisconnectRequest(buffer, len); - break; - } + case DisconnectRequest: + { + loopHandleDisconnectRequest(buffer, len); + break; + } - case DescriptionRequest: - { - loopHandleDescriptionRequest(buffer, len); - break; - } + case DescriptionRequest: + { + loopHandleDescriptionRequest(buffer, len); + break; + } - case DeviceConfigurationRequest: - { - loopHandleDeviceConfigurationRequest(buffer, len); - break; - } + case DeviceConfigurationRequest: + { + loopHandleDeviceConfigurationRequest(buffer, len); + break; + } - case TunnelingRequest: - { - loopHandleTunnelingRequest(buffer, len); - return; - } + case TunnelingRequest: + { + loopHandleTunnelingRequest(buffer, len); + return; + } - case DeviceConfigurationAck: - { - //TOOD nothing to do now - //println("got Ack"); - break; - } + case DeviceConfigurationAck: + { + //TOOD nothing to do now + //println("got Ack"); + break; + } - case TunnelingAck: - { - //TOOD nothing to do now - //println("got Ack"); - break; - } + case TunnelingAck: + { + //TOOD nothing to do now + //println("got Ack"); + break; + } #endif - default: - LOGGER.warning("Unhandled service identifier: %x:", code); - break; + default: + LOGGER.warning("Unhandled service identifier: %x:", code); + break; + } } -} -void IpDataLinkLayer::loopHandleSearchRequestExtended(uint8_t* buffer, uint16_t length) -{ - KnxIpSearchRequestExtended searchRequest(buffer, length); - - if (searchRequest.srpByProgMode) + void IpDataLinkLayer::loopHandleSearchRequestExtended(uint8_t* buffer, uint16_t length) { - println("srpByProgMode"); + KnxIpSearchRequestExtended searchRequest(buffer, length); - if (!_deviceObject.progMode()) - return; - } - - if (searchRequest.srpByMacAddr) - { - println("srpByMacAddr"); - const uint8_t* x = _ipParameters.propertyData(PID_MAC_ADDRESS); + if (searchRequest.srpByProgMode) + { + println("srpByProgMode"); - for (int i = 0; i < 6; i++) - if (searchRequest.srpMacAddr[i] != x[i]) + if (!_deviceObject.progMode()) return; - } + } + + if (searchRequest.srpByMacAddr) + { + println("srpByMacAddr"); + const uint8_t* x = _ipParameters.propertyData(PID_MAC_ADDRESS); + + for (int i = 0; i < 6; i++) + if (searchRequest.srpMacAddr[i] != x[i]) + return; + } #define LEN_SERVICE_FAMILIES 2 #if MASK_VERSION == 0x091A @@ -453,751 +455,752 @@ void IpDataLinkLayer::loopHandleSearchRequestExtended(uint8_t* buffer, uint16_t #endif #endif - //defaults: "Device Information DIB", "Extended Device Information DIB" and "Supported Services DIB". - int dibLength = LEN_DEVICE_INFORMATION_DIB + LEN_SERVICE_DIB + LEN_EXTENDED_DEVICE_INFORMATION_DIB; - - if (searchRequest.srpByService) - { - println("srpByService"); - uint8_t length = searchRequest.srpServiceFamilies[0]; - uint8_t* currentPos = searchRequest.srpServiceFamilies + 2; + //defaults: "Device Information DIB", "Extended Device Information DIB" and "Supported Services DIB". + int dibLength = LEN_DEVICE_INFORMATION_DIB + LEN_SERVICE_DIB + LEN_EXTENDED_DEVICE_INFORMATION_DIB; - for (int i = 0; i < (length - 2) / 2; i++) + if (searchRequest.srpByService) { - uint8_t serviceFamily = (currentPos + i * 2)[0]; - uint8_t version = (currentPos + i * 2)[1]; + println("srpByService"); + uint8_t length = searchRequest.srpServiceFamilies[0]; + uint8_t* currentPos = searchRequest.srpServiceFamilies + 2; - switch (serviceFamily) + for (int i = 0; i < (length - 2) / 2; i++) { - case Core: - if (version > KNX_SERVICE_FAMILY_CORE) - return; + uint8_t serviceFamily = (currentPos + i * 2)[0]; + uint8_t version = (currentPos + i * 2)[1]; - break; + switch (serviceFamily) + { + case Core: + if (version > KNX_SERVICE_FAMILY_CORE) + return; - case DeviceManagement: - if (version > KNX_SERVICE_FAMILY_DEVICE_MANAGEMENT) - return; + break; - break; + case DeviceManagement: + if (version > KNX_SERVICE_FAMILY_DEVICE_MANAGEMENT) + return; - case Tunnelling: - if (version > KNX_SERVICE_FAMILY_TUNNELING) - return; + break; - break; + case Tunnelling: + if (version > KNX_SERVICE_FAMILY_TUNNELING) + return; - case Routing: - if (version > KNX_SERVICE_FAMILY_ROUTING) - return; + break; - break; + case Routing: + if (version > KNX_SERVICE_FAMILY_ROUTING) + return; + + break; + } } } - } - if (searchRequest.srpRequestDIBs) - { - println("srpRequestDIBs"); + if (searchRequest.srpRequestDIBs) + { + println("srpRequestDIBs"); - if (searchRequest.requestedDIB(IP_CONFIG)) - dibLength += LEN_IP_CONFIG_DIB; //16 + if (searchRequest.requestedDIB(IP_CONFIG)) + dibLength += LEN_IP_CONFIG_DIB; //16 - if (searchRequest.requestedDIB(IP_CUR_CONFIG)) - dibLength += LEN_IP_CURRENT_CONFIG_DIB; //20 + if (searchRequest.requestedDIB(IP_CUR_CONFIG)) + dibLength += LEN_IP_CURRENT_CONFIG_DIB; //20 - if (searchRequest.requestedDIB(KNX_ADDRESSES)) - { - uint16_t length = 0; - _ipParameters.readPropertyLength(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, length); - dibLength += 4 + length * 2; - } + if (searchRequest.requestedDIB(KNX_ADDRESSES)) + { + uint16_t length = 0; + _ipParameters.readPropertyLength(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, length); + dibLength += 4 + length * 2; + } - if (searchRequest.requestedDIB(MANUFACTURER_DATA)) - dibLength += 0; //4 + n + if (searchRequest.requestedDIB(MANUFACTURER_DATA)) + dibLength += 0; //4 + n - if (searchRequest.requestedDIB(TUNNELING_INFO)) - { - uint16_t length = 0; - _ipParameters.readPropertyLength(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, length); - dibLength += 4 + length * 4; + if (searchRequest.requestedDIB(TUNNELING_INFO)) + { + uint16_t length = 0; + _ipParameters.readPropertyLength(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, length); + dibLength += 4 + length * 4; + } } - } - KnxIpSearchResponseExtended searchResponse(_ipParameters, _deviceObject, dibLength); + KnxIpSearchResponseExtended searchResponse(_ipParameters, _deviceObject, dibLength); - searchResponse.setDeviceInfo(_ipParameters, _deviceObject); //DescriptionTypeCode::DeviceInfo 1 - searchResponse.setSupportedServices(); //DescriptionTypeCode::SUPP_SVC_FAMILIES 2 - searchResponse.setExtendedDeviceInfo(); //DescriptionTypeCode::EXTENDED_DEVICE_INFO 8 + searchResponse.setDeviceInfo(_ipParameters, _deviceObject); //DescriptionTypeCode::DeviceInfo 1 + searchResponse.setSupportedServices(); //DescriptionTypeCode::SUPP_SVC_FAMILIES 2 + searchResponse.setExtendedDeviceInfo(); //DescriptionTypeCode::EXTENDED_DEVICE_INFO 8 - if (searchRequest.srpRequestDIBs) - { - if (searchRequest.requestedDIB(IP_CONFIG)) - searchResponse.setIpConfig(_ipParameters); + if (searchRequest.srpRequestDIBs) + { + if (searchRequest.requestedDIB(IP_CONFIG)) + searchResponse.setIpConfig(_ipParameters); - if (searchRequest.requestedDIB(IP_CUR_CONFIG)) - searchResponse.setIpCurrentConfig(_ipParameters); + if (searchRequest.requestedDIB(IP_CUR_CONFIG)) + searchResponse.setIpCurrentConfig(_ipParameters); - if (searchRequest.requestedDIB(KNX_ADDRESSES)) - searchResponse.setKnxAddresses(_ipParameters, _deviceObject); + if (searchRequest.requestedDIB(KNX_ADDRESSES)) + searchResponse.setKnxAddresses(_ipParameters, _deviceObject); - if (searchRequest.requestedDIB(MANUFACTURER_DATA)) - { - //println("requested MANUFACTURER_DATA but not implemented"); - } + if (searchRequest.requestedDIB(MANUFACTURER_DATA)) + { + //println("requested MANUFACTURER_DATA but not implemented"); + } #ifdef KNX_TUNNELING - if (searchRequest.requestedDIB(TUNNELING_INFO)) - searchResponse.setTunnelingInfo(_ipParameters, _deviceObject, tunnels); + if (searchRequest.requestedDIB(TUNNELING_INFO)) + searchResponse.setTunnelingInfo(_ipParameters, _deviceObject, tunnels); #endif - } + } - if (searchResponse.totalLength() > 150) - { - println("skipped response cause length is not plausible"); - return; - } + if (searchResponse.totalLength() > 150) + { + println("skipped response cause length is not plausible"); + return; + } - sendUnicast(searchRequest.hpai().ipAddress(), searchRequest.hpai().ipPortNumber(), searchResponse); -} + 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); + void IpDataLinkLayer::loopHandleConnectRequest(uint8_t* buffer, uint16_t length, uint32_t& src_addr, uint16_t& src_port) + { + KnxIpConnectRequest connRequest(buffer, length); #ifdef KNX_LOG_TUNNELING - println("Got Connect Request!"); + println("Got Connect Request!"); - switch (connRequest.cri().type()) - { - case DEVICE_MGMT_CONNECTION: - println("Device Management Connection"); - break; + switch (connRequest.cri().type()) + { + case DEVICE_MGMT_CONNECTION: + println("Device Management Connection"); + break; - case TUNNEL_CONNECTION: - println("Tunnel Connection"); - break; + case TUNNEL_CONNECTION: + println("Tunnel Connection"); + break; - case REMLOG_CONNECTION: - println("RemLog Connection"); - break; + case REMLOG_CONNECTION: + println("RemLog Connection"); + break; - case REMCONF_CONNECTION: - println("RemConf Connection"); - break; + case REMCONF_CONNECTION: + println("RemConf Connection"); + break; - case OBJSVR_CONNECTION: - println("ObjectServer Connection"); - break; - } + case OBJSVR_CONNECTION: + println("ObjectServer Connection"); + break; + } - print("Data Endpoint: "); - uint32_t ip = connRequest.hpaiData().ipAddress(); - print(ip >> 24); - print("."); - print((ip >> 16) & 0xFF); - print("."); - print((ip >> 8) & 0xFF); - print("."); - print(ip & 0xFF); - print(":"); - println(connRequest.hpaiData().ipPortNumber()); - print("Ctrl Endpoint: "); - ip = connRequest.hpaiCtrl().ipAddress(); - print(ip >> 24); - print("."); - print((ip >> 16) & 0xFF); - print("."); - print((ip >> 8) & 0xFF); - print("."); - print(ip & 0xFF); - print(":"); - println(connRequest.hpaiCtrl().ipPortNumber()); + print("Data Endpoint: "); + uint32_t ip = connRequest.hpaiData().ipAddress(); + print(ip >> 24); + print("."); + print((ip >> 16) & 0xFF); + print("."); + print((ip >> 8) & 0xFF); + print("."); + print(ip & 0xFF); + print(":"); + println(connRequest.hpaiData().ipPortNumber()); + print("Ctrl Endpoint: "); + ip = connRequest.hpaiCtrl().ipAddress(); + print(ip >> 24); + print("."); + print((ip >> 16) & 0xFF); + print("."); + print((ip >> 8) & 0xFF); + print("."); + print(ip & 0xFF); + print(":"); + println(connRequest.hpaiCtrl().ipPortNumber()); #endif - //We only support 0x03 and 0x04! - if (connRequest.cri().type() != TUNNEL_CONNECTION && connRequest.cri().type() != DEVICE_MGMT_CONNECTION) - { + //We only support 0x03 and 0x04! + if (connRequest.cri().type() != TUNNEL_CONNECTION && connRequest.cri().type() != DEVICE_MGMT_CONNECTION) + { #ifdef KNX_LOG_TUNNELING - println("Only Tunnel/DeviceMgmt Connection ist supported!"); + println("Only Tunnel/DeviceMgmt Connection ist supported!"); #endif - KnxIpConnectResponse connRes(0x00, E_CONNECTION_TYPE); - sendUnicast(connRequest.hpaiCtrl().ipAddress(), connRequest.hpaiCtrl().ipPortNumber(), connRes); - return; - } + KnxIpConnectResponse connRes(0x00, E_CONNECTION_TYPE); + sendUnicast(connRequest.hpaiCtrl().ipAddress(), connRequest.hpaiCtrl().ipPortNumber(), connRes); + return; + } - if (connRequest.cri().type() == TUNNEL_CONNECTION && connRequest.cri().layer() != 0x02) //LinkLayer - { - //We only support 0x02! + if (connRequest.cri().type() == TUNNEL_CONNECTION && connRequest.cri().layer() != 0x02) //LinkLayer + { + //We only support 0x02! #ifdef KNX_LOG_TUNNELING - println("Only LinkLayer ist supported!"); + println("Only LinkLayer ist supported!"); #endif - KnxIpConnectResponse connRes(0x00, E_TUNNELING_LAYER); - sendUnicast(connRequest.hpaiCtrl().ipAddress(), connRequest.hpaiCtrl().ipPortNumber(), connRes); - return; - } + KnxIpConnectResponse connRes(0x00, E_TUNNELING_LAYER); + sendUnicast(connRequest.hpaiCtrl().ipAddress(), connRequest.hpaiCtrl().ipPortNumber(), connRes); + return; + } - // data preparation + // data preparation - uint32_t srcIP = connRequest.hpaiCtrl().ipAddress() ? connRequest.hpaiCtrl().ipAddress() : src_addr; - uint16_t srcPort = connRequest.hpaiCtrl().ipPortNumber() ? connRequest.hpaiCtrl().ipPortNumber() : src_port; + uint32_t srcIP = connRequest.hpaiCtrl().ipAddress() ? connRequest.hpaiCtrl().ipAddress() : src_addr; + uint16_t srcPort = connRequest.hpaiCtrl().ipPortNumber() ? connRequest.hpaiCtrl().ipPortNumber() : src_port; - // read current elements in PID_ADDITIONAL_INDIVIDUAL_ADDRESSES - uint16_t propCount = 0; - _ipParameters.readPropertyLength(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, propCount); - const uint8_t* addresses; + // read current elements in PID_ADDITIONAL_INDIVIDUAL_ADDRESSES + uint16_t propCount = 0; + _ipParameters.readPropertyLength(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, propCount); + const uint8_t* addresses; - if (propCount == KNX_TUNNELING) - { - addresses = _ipParameters.propertyData(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES); - } - else // no tunnel PA configured, that means device is unconfigured and has 15.15.0 - { - uint8_t addrbuffer[KNX_TUNNELING * 2]; - addresses = (uint8_t*)addrbuffer; - - for (int i = 0; i < KNX_TUNNELING; i++) + if (propCount == KNX_TUNNELING) { - addrbuffer[i * 2 + 1] = i + 1; - addrbuffer[i * 2] = _deviceObject.individualAddress() / 0x0100; + addresses = _ipParameters.propertyData(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES); } + else // no tunnel PA configured, that means device is unconfigured and has 15.15.0 + { + uint8_t addrbuffer[KNX_TUNNELING * 2]; + addresses = (uint8_t*)addrbuffer; + + for (int i = 0; i < KNX_TUNNELING; i++) + { + addrbuffer[i * 2 + 1] = i + 1; + addrbuffer[i * 2] = _deviceObject.individualAddress() / 0x0100; + } - uint8_t count = KNX_TUNNELING; - _ipParameters.writeProperty(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, 1, addrbuffer, count); + uint8_t count = KNX_TUNNELING; + _ipParameters.writeProperty(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, 1, addrbuffer, count); #ifdef KNX_LOG_TUNNELING - println("no Tunnel-PAs configured, using own subnet"); + println("no Tunnel-PAs configured, using own subnet"); #endif - } + } - _ipParameters.readPropertyLength(PID_CUSTOM_RESERVED_TUNNELS_CTRL, propCount); - const uint8_t* tunCtrlBytes = nullptr; + _ipParameters.readPropertyLength(PID_CUSTOM_RESERVED_TUNNELS_CTRL, propCount); + const uint8_t* tunCtrlBytes = nullptr; - if (propCount == KNX_TUNNELING) - tunCtrlBytes = _ipParameters.propertyData(PID_CUSTOM_RESERVED_TUNNELS_CTRL); + if (propCount == KNX_TUNNELING) + tunCtrlBytes = _ipParameters.propertyData(PID_CUSTOM_RESERVED_TUNNELS_CTRL); - _ipParameters.readPropertyLength(PID_CUSTOM_RESERVED_TUNNELS_IP, propCount); - const uint8_t* tunCtrlIp = nullptr; + _ipParameters.readPropertyLength(PID_CUSTOM_RESERVED_TUNNELS_IP, propCount); + const uint8_t* tunCtrlIp = nullptr; - if (propCount == KNX_TUNNELING) - tunCtrlIp = _ipParameters.propertyData(PID_CUSTOM_RESERVED_TUNNELS_IP); + if (propCount == KNX_TUNNELING) + tunCtrlIp = _ipParameters.propertyData(PID_CUSTOM_RESERVED_TUNNELS_IP); - bool resTunActive = (tunCtrlBytes && tunCtrlIp); + bool resTunActive = (tunCtrlBytes && tunCtrlIp); #ifdef KNX_LOG_TUNNELING - if (resTunActive) - println("Reserved Tunnel Feature active"); + if (resTunActive) + println("Reserved Tunnel Feature active"); - if (tunCtrlBytes) - printHex("tunCtrlBytes", tunCtrlBytes, KNX_TUNNELING); + if (tunCtrlBytes) + printHex("tunCtrlBytes", tunCtrlBytes, KNX_TUNNELING); - if (tunCtrlIp) - printHex("tunCtrlIp", tunCtrlIp, KNX_TUNNELING * 4); + if (tunCtrlIp) + printHex("tunCtrlIp", tunCtrlIp, KNX_TUNNELING * 4); #endif - // check if there is a reserved tunnel for the source - int firstFreeTunnel = -1; - int firstResAndFreeTunnel = -1; - int firstResAndOccTunnel = -1; - bool tunnelResActive[KNX_TUNNELING] = {0}; - uint8_t tunnelResOptions[KNX_TUNNELING] = {0}; + // check if there is a reserved tunnel for the source + int firstFreeTunnel = -1; + int firstResAndFreeTunnel = -1; + int firstResAndOccTunnel = -1; + bool tunnelResActive[KNX_TUNNELING] = {0}; + uint8_t tunnelResOptions[KNX_TUNNELING] = {0}; - for (int i = 0; i < KNX_TUNNELING; i++) - { - if (resTunActive) + for (int i = 0; i < KNX_TUNNELING; i++) { - tunnelResActive[i] = *(tunCtrlBytes + i) & 0x80; - tunnelResOptions[i] = (*(tunCtrlBytes + i) & 0x60) >> 5; - } + if (resTunActive) + { + tunnelResActive[i] = *(tunCtrlBytes + i) & 0x80; + tunnelResOptions[i] = (*(tunCtrlBytes + i) & 0x60) >> 5; + } - if (tunnelResActive[i]) // tunnel reserve feature active for this tunnel - { + if (tunnelResActive[i]) // tunnel reserve feature active for this tunnel + { #ifdef KNX_LOG_TUNNELING - print("tunnel reserve feature active for this tunnel: "); - print(tunnelResActive[i]); - print(" options: "); - println(tunnelResOptions[i]); + print("tunnel reserve feature active for this tunnel: "); + print(tunnelResActive[i]); + print(" options: "); + println(tunnelResOptions[i]); #endif - uint32_t rIP = 0; - popInt(rIP, tunCtrlIp + 4 * i); + uint32_t rIP = 0; + popInt(rIP, tunCtrlIp + 4 * i); - if (srcIP == rIP && connRequest.cri().type() == TUNNEL_CONNECTION) - { - // reserved tunnel for this ip found - if (tunnels[i].ChannelId == 0) // check if it is free + if (srcIP == rIP && connRequest.cri().type() == TUNNEL_CONNECTION) { - if (firstResAndFreeTunnel < 0) - firstResAndFreeTunnel = i; - } - else - { - if (firstResAndOccTunnel < 0) - firstResAndOccTunnel = i; + // reserved tunnel for this ip found + if (tunnels[i].ChannelId == 0) // check if it is free + { + if (firstResAndFreeTunnel < 0) + firstResAndFreeTunnel = i; + } + else + { + if (firstResAndOccTunnel < 0) + firstResAndOccTunnel = i; + } } } + else + { + if (tunnels[i].ChannelId == 0 && firstFreeTunnel < 0) + firstFreeTunnel = i; + } } - else - { - if (tunnels[i].ChannelId == 0 && firstFreeTunnel < 0) - firstFreeTunnel = i; - } - } #ifdef KNX_LOG_TUNNELING - print("firstFreeTunnel: "); - print(firstFreeTunnel); - print(" firstResAndFreeTunnel: "); - print(firstResAndFreeTunnel); - print(" firstResAndOccTunnel: "); - println(firstResAndOccTunnel); + print("firstFreeTunnel: "); + print(firstFreeTunnel); + print(" firstResAndFreeTunnel: "); + print(firstResAndFreeTunnel); + print(" firstResAndOccTunnel: "); + println(firstResAndOccTunnel); #endif - uint8_t tunIdx = 0xff; + uint8_t tunIdx = 0xff; - if (resTunActive & (firstResAndFreeTunnel >= 0 || firstResAndOccTunnel >= 0)) // tunnel reserve feature active (for this src) - { - if (firstResAndFreeTunnel >= 0) - { - tunIdx = firstResAndFreeTunnel; - } - else if (firstResAndOccTunnel >= 0) + if (resTunActive & (firstResAndFreeTunnel >= 0 || firstResAndOccTunnel >= 0)) // tunnel reserve feature active (for this src) { - if (tunnelResOptions[firstResAndOccTunnel] == 1) // decline req + if (firstResAndFreeTunnel >= 0) { - ; // do nothing => decline + tunIdx = firstResAndFreeTunnel; } - else if (tunnelResOptions[firstResAndOccTunnel] == 2) // close current tunnel connection on this tunnel and assign to this request + else if (firstResAndOccTunnel >= 0) { - KnxIpDisconnectRequest discReq; - discReq.channelId(tunnels[firstResAndOccTunnel].ChannelId); - discReq.hpaiCtrl().length(LEN_IPHPAI); - discReq.hpaiCtrl().code(IPV4_UDP); - discReq.hpaiCtrl().ipAddress(tunnels[firstResAndOccTunnel].IpAddress); - discReq.hpaiCtrl().ipPortNumber(tunnels[firstResAndOccTunnel].PortCtrl); - sendUnicast(tunnels[firstResAndOccTunnel].IpAddress, tunnels[firstResAndOccTunnel].PortCtrl, discReq); - tunnels[firstResAndOccTunnel].Reset(); + if (tunnelResOptions[firstResAndOccTunnel] == 1) // decline req + { + ; // do nothing => decline + } + else if (tunnelResOptions[firstResAndOccTunnel] == 2) // close current tunnel connection on this tunnel and assign to this request + { + KnxIpDisconnectRequest discReq; + discReq.channelId(tunnels[firstResAndOccTunnel].ChannelId); + discReq.hpaiCtrl().length(LEN_IPHPAI); + discReq.hpaiCtrl().code(IPV4_UDP); + discReq.hpaiCtrl().ipAddress(tunnels[firstResAndOccTunnel].IpAddress); + discReq.hpaiCtrl().ipPortNumber(tunnels[firstResAndOccTunnel].PortCtrl); + sendUnicast(tunnels[firstResAndOccTunnel].IpAddress, tunnels[firstResAndOccTunnel].PortCtrl, discReq); + tunnels[firstResAndOccTunnel].Reset(); - tunIdx = firstResAndOccTunnel; - } - else if (tunnelResOptions[firstResAndOccTunnel] == 3) // use the first unreserved tunnel (if one) - { - if (firstFreeTunnel >= 0) - tunIdx = firstFreeTunnel; - else - ; // do nothing => decline + tunIdx = firstResAndOccTunnel; + } + else if (tunnelResOptions[firstResAndOccTunnel] == 3) // use the first unreserved tunnel (if one) + { + if (firstFreeTunnel >= 0) + tunIdx = firstFreeTunnel; + else + ; // do nothing => decline + } + + //else + // should not happen + // do nothing => decline } //else // should not happen // do nothing => decline } + else + { + if (firstFreeTunnel >= 0) + tunIdx = firstFreeTunnel; - //else - // should not happen - // do nothing => decline - } - else - { - if (firstFreeTunnel >= 0) - tunIdx = firstFreeTunnel; - - //else - // do nothing => decline - } + //else + // do nothing => decline + } - KnxIpTunnelConnection* tun = nullptr; + KnxIpTunnelConnection* tun = nullptr; - if (tunIdx != 0xFF) - { - tun = &tunnels[tunIdx]; + if (tunIdx != 0xFF) + { + tun = &tunnels[tunIdx]; - uint16_t tunPa = 0; - popWord(tunPa, addresses + (tunIdx * 2)); + uint16_t tunPa = 0; + popWord(tunPa, addresses + (tunIdx * 2)); - //check if this PA is in use (should not happen, only when there is one pa wrongly assigned to more then one tunnel) - for (int x = 0; x < KNX_TUNNELING; x++) - if (tunnels[x].IndividualAddress == tunPa) - { + //check if this PA is in use (should not happen, only when there is one pa wrongly assigned to more then one tunnel) + for (int x = 0; x < KNX_TUNNELING; x++) + if (tunnels[x].IndividualAddress == tunPa) + { #ifdef KNX_LOG_TUNNELING - println("cannot use tunnel because PA is already in use"); + println("cannot use tunnel because PA is already in use"); #endif - tunIdx = 0xFF; - tun = nullptr; - break; - } + tunIdx = 0xFF; + tun = nullptr; + break; + } - tun->IndividualAddress = tunPa; - } + tun->IndividualAddress = tunPa; + } - if (tun == nullptr) - { - println("no free tunnel availible"); - KnxIpConnectResponse connRes(0x00, E_NO_MORE_CONNECTIONS); - sendUnicast(connRequest.hpaiCtrl().ipAddress(), connRequest.hpaiCtrl().ipPortNumber(), connRes); - return; - } + if (tun == nullptr) + { + println("no free tunnel availible"); + KnxIpConnectResponse connRes(0x00, E_NO_MORE_CONNECTIONS); + sendUnicast(connRequest.hpaiCtrl().ipAddress(), connRequest.hpaiCtrl().ipPortNumber(), connRes); + return; + } - if (connRequest.cri().type() == DEVICE_MGMT_CONNECTION) - tun->IsConfig = true; + if (connRequest.cri().type() == DEVICE_MGMT_CONNECTION) + tun->IsConfig = true; - // the channel ID shall be unique on this tunnel server. catch the rare case of a double channel ID - bool channelIdInUse; + // the channel ID shall be unique on this tunnel server. catch the rare case of a double channel ID + bool channelIdInUse; - do - { - _lastChannelId++; - channelIdInUse = false; - - for (int x = 0; x < KNX_TUNNELING; x++) - if (tunnels[x].ChannelId == _lastChannelId) - channelIdInUse = true; - } while (channelIdInUse); - - tun->ChannelId = _lastChannelId; - tun->lastHeartbeat = millis(); - - if (_lastChannelId == 255) - _lastChannelId = 0; - - tun->IpAddress = srcIP; - tun->PortData = srcPort; - tun->PortCtrl = connRequest.hpaiCtrl().ipPortNumber() ? connRequest.hpaiCtrl().ipPortNumber() : srcPort; - - print("New Tunnel-Connection["); - print(tunIdx); - print("], Channel: 0x"); - print(tun->ChannelId, 16); - print(" PA: "); - print(tun->IndividualAddress >> 12); - print("."); - print((tun->IndividualAddress >> 8) & 0xF); - print("."); - print(tun->IndividualAddress & 0xFF); - - print(" with "); - print(tun->IpAddress >> 24); - print("."); - print((tun->IpAddress >> 16) & 0xFF); - print("."); - print((tun->IpAddress >> 8) & 0xFF); - print("."); - print(tun->IpAddress & 0xFF); - print(":"); - print(tun->PortData); - - if (tun->PortData != tun->PortCtrl) - { - print(" (Ctrlport: "); - print(tun->PortCtrl); - print(")"); - } + do + { + _lastChannelId++; + channelIdInUse = false; + + for (int x = 0; x < KNX_TUNNELING; x++) + if (tunnels[x].ChannelId == _lastChannelId) + channelIdInUse = true; + } while (channelIdInUse); + + tun->ChannelId = _lastChannelId; + tun->lastHeartbeat = millis(); + + if (_lastChannelId == 255) + _lastChannelId = 0; + + tun->IpAddress = srcIP; + tun->PortData = srcPort; + tun->PortCtrl = connRequest.hpaiCtrl().ipPortNumber() ? connRequest.hpaiCtrl().ipPortNumber() : srcPort; + + print("New Tunnel-Connection["); + print(tunIdx); + print("], Channel: 0x"); + print(tun->ChannelId, 16); + print(" PA: "); + print(tun->IndividualAddress >> 12); + print("."); + print((tun->IndividualAddress >> 8) & 0xF); + print("."); + print(tun->IndividualAddress & 0xFF); + + print(" with "); + print(tun->IpAddress >> 24); + print("."); + print((tun->IpAddress >> 16) & 0xFF); + print("."); + print((tun->IpAddress >> 8) & 0xFF); + print("."); + print(tun->IpAddress & 0xFF); + print(":"); + print(tun->PortData); + + if (tun->PortData != tun->PortCtrl) + { + print(" (Ctrlport: "); + print(tun->PortCtrl); + print(")"); + } - if (tun->IsConfig) - { - print(" (Config-Channel)"); - } + if (tun->IsConfig) + { + print(" (Config-Channel)"); + } - println(); + println(); - KnxIpConnectResponse connRes(_ipParameters, tun->IndividualAddress, 3671, tun->ChannelId, connRequest.cri().type()); - sendUnicast(tun->IpAddress, tun->PortCtrl, connRes); -} + KnxIpConnectResponse connRes(_ipParameters, tun->IndividualAddress, 3671, tun->ChannelId, connRequest.cri().type()); + sendUnicast(tun->IpAddress, tun->PortCtrl, connRes); + } -void IpDataLinkLayer::loopHandleConnectionStateRequest(uint8_t* buffer, uint16_t length) -{ - KnxIpStateRequest stateRequest(buffer, length); + void IpDataLinkLayer::loopHandleConnectionStateRequest(uint8_t* buffer, uint16_t length) + { + KnxIpStateRequest stateRequest(buffer, length); - KnxIpTunnelConnection* tun = nullptr; + KnxIpTunnelConnection* tun = nullptr; - for (int i = 0; i < KNX_TUNNELING; i++) - { - if (tunnels[i].ChannelId == stateRequest.channelId()) + for (int i = 0; i < KNX_TUNNELING; i++) { - tun = &tunnels[i]; - break; + if (tunnels[i].ChannelId == stateRequest.channelId()) + { + tun = &tunnels[i]; + break; + } } - } - if (tun == nullptr) - { + if (tun == nullptr) + { #ifdef KNX_LOG_TUNNELING - print("Channel ID nicht gefunden: "); - println(stateRequest.channelId()); + print("Channel ID nicht gefunden: "); + println(stateRequest.channelId()); #endif - KnxIpStateResponse stateRes(0x00, E_CONNECTION_ID); - sendUnicast(stateRequest.hpaiCtrl().ipAddress(), stateRequest.hpaiCtrl().ipPortNumber(), stateRes); - return; - } + KnxIpStateResponse stateRes(0x00, E_CONNECTION_ID); + sendUnicast(stateRequest.hpaiCtrl().ipAddress(), stateRequest.hpaiCtrl().ipPortNumber(), stateRes); + return; + } - //TODO check knx connection! - //if no connection return E_KNX_CONNECTION + //TODO check knx connection! + //if no connection return E_KNX_CONNECTION - //TODO check when to send E_DATA_CONNECTION + //TODO check when to send E_DATA_CONNECTION - tun->lastHeartbeat = millis(); - KnxIpStateResponse stateRes(tun->ChannelId, E_NO_ERROR); - sendUnicast(stateRequest.hpaiCtrl().ipAddress(), stateRequest.hpaiCtrl().ipPortNumber(), stateRes); -} + tun->lastHeartbeat = millis(); + KnxIpStateResponse stateRes(tun->ChannelId, E_NO_ERROR); + sendUnicast(stateRequest.hpaiCtrl().ipAddress(), stateRequest.hpaiCtrl().ipPortNumber(), stateRes); + } -void IpDataLinkLayer::loopHandleDisconnectRequest(uint8_t* buffer, uint16_t length) -{ - KnxIpDisconnectRequest discReq(buffer, length); + void IpDataLinkLayer::loopHandleDisconnectRequest(uint8_t* buffer, uint16_t length) + { + KnxIpDisconnectRequest discReq(buffer, length); #ifdef KNX_LOG_TUNNELING - print(">>> Disconnect Channel ID: "); - println(discReq.channelId()); + print(">>> Disconnect Channel ID: "); + println(discReq.channelId()); #endif - KnxIpTunnelConnection* tun = nullptr; + KnxIpTunnelConnection* tun = nullptr; - for (int i = 0; i < KNX_TUNNELING; i++) - { - if (tunnels[i].ChannelId == discReq.channelId()) + for (int i = 0; i < KNX_TUNNELING; i++) { - tun = &tunnels[i]; - break; + if (tunnels[i].ChannelId == discReq.channelId()) + { + tun = &tunnels[i]; + break; + } } - } - if (tun == nullptr) - { + if (tun == nullptr) + { #ifdef KNX_LOG_TUNNELING - print("Channel ID nicht gefunden: "); - println(discReq.channelId()); + print("Channel ID nicht gefunden: "); + println(discReq.channelId()); #endif - KnxIpDisconnectResponse discRes(0x00, E_CONNECTION_ID); - sendUnicast(discReq.hpaiCtrl().ipAddress(), discReq.hpaiCtrl().ipPortNumber(), discRes); - return; - } + KnxIpDisconnectResponse discRes(0x00, E_CONNECTION_ID); + sendUnicast(discReq.hpaiCtrl().ipAddress(), discReq.hpaiCtrl().ipPortNumber(), discRes); + return; + } - KnxIpDisconnectResponse discRes(tun->ChannelId, E_NO_ERROR); - sendUnicast(discReq.hpaiCtrl().ipAddress(), discReq.hpaiCtrl().ipPortNumber(), discRes); - tun->Reset(); -} + KnxIpDisconnectResponse discRes(tun->ChannelId, E_NO_ERROR); + sendUnicast(discReq.hpaiCtrl().ipAddress(), discReq.hpaiCtrl().ipPortNumber(), discRes); + tun->Reset(); + } #endif -void IpDataLinkLayer::loopHandleDescriptionRequest(uint8_t* buffer, uint16_t length) -{ - KnxIpDescriptionRequest descReq(buffer, length); - KnxIpDescriptionResponse descRes(_ipParameters, _deviceObject); - sendUnicast(descReq.hpaiCtrl().ipAddress(), descReq.hpaiCtrl().ipPortNumber(), descRes); -} + void IpDataLinkLayer::loopHandleDescriptionRequest(uint8_t* buffer, uint16_t length) + { + KnxIpDescriptionRequest descReq(buffer, length); + KnxIpDescriptionResponse descRes(_ipParameters, _deviceObject); + sendUnicast(descReq.hpaiCtrl().ipAddress(), descReq.hpaiCtrl().ipPortNumber(), descRes); + } #ifdef KNX_TUNNELING -void IpDataLinkLayer::loopHandleDeviceConfigurationRequest(uint8_t* buffer, uint16_t length) -{ - KnxIpConfigRequest confReq(buffer, length); + void IpDataLinkLayer::loopHandleDeviceConfigurationRequest(uint8_t* buffer, uint16_t length) + { + KnxIpConfigRequest confReq(buffer, length); - KnxIpTunnelConnection* tun = nullptr; + KnxIpTunnelConnection* tun = nullptr; - for (int i = 0; i < KNX_TUNNELING; i++) - { - if (tunnels[i].ChannelId == confReq.connectionHeader().channelId()) + for (int i = 0; i < KNX_TUNNELING; i++) { - tun = &tunnels[i]; - break; + if (tunnels[i].ChannelId == confReq.connectionHeader().channelId()) + { + tun = &tunnels[i]; + break; + } } - } - if (tun == nullptr) - { - print("Channel ID nicht gefunden: "); - println(confReq.connectionHeader().channelId()); - KnxIpStateResponse stateRes(0x00, E_CONNECTION_ID); - sendUnicast(0, 0, stateRes); - return; - } + if (tun == nullptr) + { + print("Channel ID nicht gefunden: "); + println(confReq.connectionHeader().channelId()); + KnxIpStateResponse stateRes(0x00, E_CONNECTION_ID); + sendUnicast(0, 0, stateRes); + return; + } - KnxIpTunnelingAck tunnAck; - tunnAck.serviceTypeIdentifier(DeviceConfigurationAck); - tunnAck.connectionHeader().length(4); - tunnAck.connectionHeader().channelId(tun->ChannelId); - tunnAck.connectionHeader().sequenceCounter(confReq.connectionHeader().sequenceCounter()); - tunnAck.connectionHeader().status(E_NO_ERROR); - sendUnicast(tun->IpAddress, tun->PortData, tunnAck); + KnxIpTunnelingAck tunnAck; + tunnAck.serviceTypeIdentifier(DeviceConfigurationAck); + tunnAck.connectionHeader().length(4); + tunnAck.connectionHeader().channelId(tun->ChannelId); + tunnAck.connectionHeader().sequenceCounter(confReq.connectionHeader().sequenceCounter()); + tunnAck.connectionHeader().status(E_NO_ERROR); + sendUnicast(tun->IpAddress, tun->PortData, tunnAck); - tun->lastHeartbeat = millis(); - _cemiServer->frameReceived(confReq.frame()); -} + tun->lastHeartbeat = millis(); + _cemiServer->frameReceived(confReq.frame()); + } -void IpDataLinkLayer::loopHandleTunnelingRequest(uint8_t* buffer, uint16_t length) -{ - KnxIpTunnelingRequest tunnReq(buffer, length); + void IpDataLinkLayer::loopHandleTunnelingRequest(uint8_t* buffer, uint16_t length) + { + KnxIpTunnelingRequest tunnReq(buffer, length); - KnxIpTunnelConnection* tun = nullptr; + KnxIpTunnelConnection* tun = nullptr; - for (int i = 0; i < KNX_TUNNELING; i++) - { - if (tunnels[i].ChannelId == tunnReq.connectionHeader().channelId()) + for (int i = 0; i < KNX_TUNNELING; i++) { - tun = &tunnels[i]; - break; + if (tunnels[i].ChannelId == tunnReq.connectionHeader().channelId()) + { + tun = &tunnels[i]; + break; + } } - } - if (tun == nullptr) - { + if (tun == nullptr) + { #ifdef KNX_LOG_TUNNELING - print("Channel ID nicht gefunden: "); - println(tunnReq.connectionHeader().channelId()); + print("Channel ID nicht gefunden: "); + println(tunnReq.connectionHeader().channelId()); #endif - KnxIpStateResponse stateRes(0x00, E_CONNECTION_ID); - sendUnicast(0, 0, stateRes); - return; - } + KnxIpStateResponse stateRes(0x00, E_CONNECTION_ID); + sendUnicast(0, 0, stateRes); + return; + } - uint8_t sequence = tunnReq.connectionHeader().sequenceCounter(); + uint8_t sequence = tunnReq.connectionHeader().sequenceCounter(); - if (sequence == tun->SequenceCounter_R) - { + if (sequence == tun->SequenceCounter_R) + { +#ifdef KNX_LOG_TUNNELING + print("Received SequenceCounter again: "); + println(tunnReq.connectionHeader().sequenceCounter()); +#endif + //we already got this one + //so just ack it + KnxIpTunnelingAck tunnAck; + tunnAck.connectionHeader().length(4); + tunnAck.connectionHeader().channelId(tun->ChannelId); + tunnAck.connectionHeader().sequenceCounter(tunnReq.connectionHeader().sequenceCounter()); + tunnAck.connectionHeader().status(E_NO_ERROR); + sendUnicast(tun->IpAddress, tun->PortData, tunnAck); + return; + } + else if ((uint8_t)(sequence - 1) != tun->SequenceCounter_R) + { #ifdef KNX_LOG_TUNNELING - print("Received SequenceCounter again: "); - println(tunnReq.connectionHeader().sequenceCounter()); + print("Wrong SequenceCounter: got "); + print(tunnReq.connectionHeader().sequenceCounter()); + print(" expected "); + println((uint8_t)(tun->SequenceCounter_R + 1)); #endif - //we already got this one - //so just ack it + //Dont handle it + return; + } + KnxIpTunnelingAck tunnAck; tunnAck.connectionHeader().length(4); tunnAck.connectionHeader().channelId(tun->ChannelId); tunnAck.connectionHeader().sequenceCounter(tunnReq.connectionHeader().sequenceCounter()); tunnAck.connectionHeader().status(E_NO_ERROR); sendUnicast(tun->IpAddress, tun->PortData, tunnAck); - return; - } - else if ((uint8_t)(sequence - 1) != tun->SequenceCounter_R) - { -#ifdef KNX_LOG_TUNNELING - print("Wrong SequenceCounter: got "); - print(tunnReq.connectionHeader().sequenceCounter()); - print(" expected "); - println((uint8_t)(tun->SequenceCounter_R + 1)); -#endif - //Dont handle it - return; - } - KnxIpTunnelingAck tunnAck; - tunnAck.connectionHeader().length(4); - tunnAck.connectionHeader().channelId(tun->ChannelId); - tunnAck.connectionHeader().sequenceCounter(tunnReq.connectionHeader().sequenceCounter()); - tunnAck.connectionHeader().status(E_NO_ERROR); - sendUnicast(tun->IpAddress, tun->PortData, tunnAck); + tun->SequenceCounter_R = tunnReq.connectionHeader().sequenceCounter(); - tun->SequenceCounter_R = tunnReq.connectionHeader().sequenceCounter(); + if (tunnReq.frame().sourceAddress() == 0) + tunnReq.frame().sourceAddress(tun->IndividualAddress); - if (tunnReq.frame().sourceAddress() == 0) - tunnReq.frame().sourceAddress(tun->IndividualAddress); - - _cemiServer->frameReceived(tunnReq.frame()); -} + _cemiServer->frameReceived(tunnReq.frame()); + } #endif -void IpDataLinkLayer::enabled(bool value) -{ - // _print("own address: "); - // _println(_deviceObject.individualAddress()); - if (value && !_enabled) + void IpDataLinkLayer::enabled(bool value) { - _platform.setupMultiCast(_ipParameters.propertyValue(PID_ROUTING_MULTICAST_ADDRESS), KNXIP_MULTICAST_PORT); - _enabled = true; - return; + // _print("own address: "); + // _println(_deviceObject.individualAddress()); + if (value && !_enabled) + { + _platform.setupMultiCast(_ipParameters.propertyValue(PID_ROUTING_MULTICAST_ADDRESS), KNXIP_MULTICAST_PORT); + _enabled = true; + return; + } + + if (!value && _enabled) + { + _platform.closeMultiCast(); + _enabled = false; + return; + } } - if (!value && _enabled) + bool IpDataLinkLayer::enabled() const { - _platform.closeMultiCast(); - _enabled = false; - return; + return _enabled; } -} -bool IpDataLinkLayer::enabled() const -{ - return _enabled; -} + DptMedium IpDataLinkLayer::mediumType() const + { + return DptMedium::KNX_IP; + } -DptMedium IpDataLinkLayer::mediumType() const -{ - return DptMedium::KNX_IP; -} + bool IpDataLinkLayer::sendMulicast(KnxIpFrame& ipFrame) + { + if (!_enabled) + return false; -bool IpDataLinkLayer::sendMulicast(KnxIpFrame& ipFrame) -{ - if (!_enabled) - return false; + LOGGER.info("sendMulicast %s %s", enum_name(ipFrame.protocolVersion()), enum_name(ipFrame.serviceTypeIdentifier())); - LOGGER.info("sendMulicast %s %s", enum_name(ipFrame.protocolVersion()), enum_name(ipFrame.serviceTypeIdentifier())); + return _platform.sendBytesMultiCast(ipFrame.data(), ipFrame.totalLength()); + } - return _platform.sendBytesMultiCast(ipFrame.data(), ipFrame.totalLength()); -} + bool IpDataLinkLayer::sendUnicast(uint32_t addr, uint16_t port, KnxIpFrame& ipFrame) + { + if (!_enabled) + return false; -bool IpDataLinkLayer::sendUnicast(uint32_t addr, uint16_t port, KnxIpFrame& ipFrame) -{ - if (!_enabled) - return false; + LOGGER.info("sendUnicast to %d.%d.%d.%d:%d %s %s", addr & 0xFF000000 >> 24, addr & 0xFF0000 >> 16, addr & 0xFF00 >> 8, addr & 0xFF + , port, enum_name(ipFrame.protocolVersion()), enum_name(ipFrame.serviceTypeIdentifier())); - LOGGER.info("sendUnicast to %d.%d.%d.%d:%d %s %s", addr & 0xFF000000 >> 24, addr & 0xFF0000 >> 16, addr & 0xFF00 >> 8, addr & 0xFF - , port, enum_name(ipFrame.protocolVersion()), enum_name(ipFrame.serviceTypeIdentifier())); + return _platform.sendBytesMultiCast(ipFrame.data(), ipFrame.totalLength()); + } - return _platform.sendBytesMultiCast(ipFrame.data(), ipFrame.totalLength()); -} + bool IpDataLinkLayer::isSendLimitReached() + { + uint32_t curTime = millis() / 100; -bool IpDataLinkLayer::isSendLimitReached() -{ - uint32_t curTime = millis() / 100; + // check if the countbuffer must be adjusted + if (_frameCountTimeBase >= curTime) + { + uint32_t timeBaseDiff = _frameCountTimeBase - curTime; - // check if the countbuffer must be adjusted - if (_frameCountTimeBase >= curTime) - { - uint32_t timeBaseDiff = _frameCountTimeBase - curTime; + if (timeBaseDiff > 10) + timeBaseDiff = 10; - if (timeBaseDiff > 10) - timeBaseDiff = 10; + for (uint32_t i = 0; i < timeBaseDiff ; i++) + { + _frameCountBase++; + _frameCountBase = _frameCountBase % 10; + _frameCount[_frameCountBase] = 0; + } - for (uint32_t i = 0; i < timeBaseDiff ; i++) - { - _frameCountBase++; - _frameCountBase = _frameCountBase % 10; - _frameCount[_frameCountBase] = 0; + _frameCountTimeBase = curTime; } + else // _frameCountTimeBase < curTime => millis overflow, reset + { + for (int i = 0; i < 10 ; i++) + _frameCount[i] = 0; - _frameCountTimeBase = curTime; - } - else // _frameCountTimeBase < curTime => millis overflow, reset - { - for (int i = 0; i < 10 ; i++) - _frameCount[i] = 0; - - _frameCountBase = 0; - _frameCountTimeBase = curTime; - } + _frameCountBase = 0; + _frameCountTimeBase = curTime; + } - //check if we are over the limit - uint16_t sum = 0; + //check if we are over the limit + uint16_t sum = 0; - for (int i = 0; i < 10 ; i++) - sum += _frameCount[i]; + for (int i = 0; i < 10 ; i++) + sum += _frameCount[i]; - if (sum > 50) - { - LOGGER.warning("Dropping packet due to 50p/s limit"); - return true; // drop packet - } - else - { - _frameCount[_frameCountBase]++; - //print("sent packages in last 1000ms: "); - //print(sum); - //print(" curTime: "); - //println(curTime); - return false; + if (sum > 50) + { + LOGGER.warning("Dropping packet due to 50p/s limit"); + return true; // drop packet + } + else + { + _frameCount[_frameCountBase]++; + //print("sent packages in last 1000ms: "); + //print(sum); + //print(" curTime: "); + //println(curTime); + return false; + } } -} +} \ No newline at end of file diff --git a/src/knx/ip/ip_data_link_layer.h b/src/knx/ip/ip_data_link_layer.h index dee48496..3b610291 100644 --- a/src/knx/ip/ip_data_link_layer.h +++ b/src/knx/ip/ip_data_link_layer.h @@ -7,49 +7,52 @@ #include "service_families.h" #include "knx_ip_frame.h" -class IpDataLinkLayer : public DataLinkLayer +namespace Knx { - using DataLinkLayer::_deviceObject; + class IpDataLinkLayer : public DataLinkLayer + { + using DataLinkLayer::_deviceObject; - public: - IpDataLinkLayer(DeviceObject& devObj, IpParameterObject& ipParam, NetworkLayerEntity& netLayerEntity, - Platform& platform, DataLinkLayerCallbacks* dllcb = nullptr); + public: + IpDataLinkLayer(DeviceObject& devObj, IpParameterObject& ipParam, NetworkLayerEntity& netLayerEntity, + Platform& platform, DataLinkLayerCallbacks* dllcb = nullptr); - void loop(); - void enabled(bool value); - bool enabled() const; - DptMedium mediumType() const override; + void loop(); + 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; + void dataRequestToTunnel(CemiFrame& frame) override; + void dataConfirmationToTunnel(CemiFrame& frame) override; + void dataIndicationToTunnel(CemiFrame& frame) override; + bool isTunnelAddress(uint16_t addr) override; #endif - bool isSentToTunnel(uint16_t address, bool isGrpAddr); + bool isSentToTunnel(uint16_t address, bool isGrpAddr); - private: - bool _enabled = false; - uint8_t _frameCount[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - uint8_t _frameCountBase = 0; - uint32_t _frameCountTimeBase = 0; - bool sendFrame(CemiFrame& frame); + private: + bool _enabled = false; + uint8_t _frameCount[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + 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); - void loopHandleDisconnectRequest(uint8_t* buffer, uint16_t length); - void loopHandleTunnelingRequest(uint8_t* buffer, uint16_t length); - void loopHandleDeviceConfigurationRequest(uint8_t* buffer, uint16_t length); + 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); + void loopHandleDisconnectRequest(uint8_t* buffer, uint16_t length); + void loopHandleTunnelingRequest(uint8_t* buffer, uint16_t length); + void loopHandleDeviceConfigurationRequest(uint8_t* buffer, uint16_t length); #endif - void loopHandleDescriptionRequest(uint8_t* buffer, uint16_t length); - void loopHandleSearchRequestExtended(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; + void loopHandleDescriptionRequest(uint8_t* buffer, uint16_t length); + void loopHandleSearchRequestExtended(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; #ifdef KNX_TUNNELING - KnxIpTunnelConnection tunnels[KNX_TUNNELING]; - uint8_t _lastChannelId = 1; + KnxIpTunnelConnection tunnels[KNX_TUNNELING]; + uint8_t _lastChannelId = 1; #endif -}; \ No newline at end of file + }; +} \ No newline at end of file diff --git a/src/knx/ip/ip_host_protocol_address_information.cpp b/src/knx/ip/ip_host_protocol_address_information.cpp index 67c930f1..e5d855dd 100644 --- a/src/knx/ip/ip_host_protocol_address_information.cpp +++ b/src/knx/ip/ip_host_protocol_address_information.cpp @@ -1,47 +1,50 @@ #include "ip_host_protocol_address_information.h" #include "../bits.h" -IpHostProtocolAddressInformation::IpHostProtocolAddressInformation(uint8_t* data) - : _data(data) -{} - - -uint8_t IpHostProtocolAddressInformation::length() const -{ - return *_data; -} - -void IpHostProtocolAddressInformation::length(uint8_t value) -{ - *_data = value; -} - -HostProtocolCode IpHostProtocolAddressInformation::code() const -{ - return (HostProtocolCode)_data[1]; -} - -void IpHostProtocolAddressInformation::code(HostProtocolCode value) -{ - _data[1] = value; -} - -uint32_t IpHostProtocolAddressInformation::ipAddress() const -{ - return getInt(_data + 2); -} - -void IpHostProtocolAddressInformation::ipAddress(uint32_t value) -{ - pushInt(value, _data + 2); -} - -uint16_t IpHostProtocolAddressInformation::ipPortNumber() const -{ - return getWord(_data + 6); -} - -void IpHostProtocolAddressInformation::ipPortNumber(uint16_t value) -{ - pushWord(value, _data + 6); -} +namespace Knx +{ + IpHostProtocolAddressInformation::IpHostProtocolAddressInformation(uint8_t* data) + : _data(data) + {} + + + uint8_t IpHostProtocolAddressInformation::length() const + { + return *_data; + } + + void IpHostProtocolAddressInformation::length(uint8_t value) + { + *_data = value; + } + + HostProtocolCode IpHostProtocolAddressInformation::code() const + { + return (HostProtocolCode)_data[1]; + } + + void IpHostProtocolAddressInformation::code(HostProtocolCode value) + { + _data[1] = value; + } + + uint32_t IpHostProtocolAddressInformation::ipAddress() const + { + return getInt(_data + 2); + } + + void IpHostProtocolAddressInformation::ipAddress(uint32_t value) + { + pushInt(value, _data + 2); + } + + uint16_t IpHostProtocolAddressInformation::ipPortNumber() const + { + return getWord(_data + 6); + } + + void IpHostProtocolAddressInformation::ipPortNumber(uint16_t value) + { + pushWord(value, _data + 6); + } +} \ No newline at end of file diff --git a/src/knx/ip/ip_host_protocol_address_information.h b/src/knx/ip/ip_host_protocol_address_information.h index 61d35262..640c2f92 100644 --- a/src/knx/ip/ip_host_protocol_address_information.h +++ b/src/knx/ip/ip_host_protocol_address_information.h @@ -2,28 +2,31 @@ #include -enum HostProtocolCode : uint8_t +namespace Knx { - IPV4_UDP = 1, - IPV4_TCP = 2 -}; + enum HostProtocolCode : uint8_t + { + IPV4_UDP = 1, + IPV4_TCP = 2 + }; #define LEN_IPHPAI 8 #define LEN_CRD 4 -class IpHostProtocolAddressInformation -{ - public: - IpHostProtocolAddressInformation(uint8_t* data); - uint8_t length() const; - void length(uint8_t value); - HostProtocolCode code() const; - void code(HostProtocolCode value); - uint32_t ipAddress() const; - void ipAddress(uint32_t value); - uint16_t ipPortNumber() const; - void ipPortNumber(uint16_t value); + class IpHostProtocolAddressInformation + { + public: + IpHostProtocolAddressInformation(uint8_t* data); + uint8_t length() const; + void length(uint8_t value); + HostProtocolCode code() const; + void code(HostProtocolCode value); + uint32_t ipAddress() const; + void ipAddress(uint32_t value); + uint16_t ipPortNumber() const; + void ipPortNumber(uint16_t value); - private: - uint8_t* _data; -}; \ No newline at end of file + private: + uint8_t* _data; + }; +} \ No newline at end of file diff --git a/src/knx/ip/ip_parameter_object.cpp b/src/knx/ip/ip_parameter_object.cpp index ae220c9f..66e74b51 100644 --- a/src/knx/ip/ip_parameter_object.cpp +++ b/src/knx/ip/ip_parameter_object.cpp @@ -5,133 +5,136 @@ // 224.0.23.12 #define DEFAULT_MULTICAST_ADDR ((uint32_t)0xE000170C) -IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platform): _deviceObject(deviceObject), - _platform(platform) +namespace Knx { - Property* properties[] = + IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platform): _deviceObject(deviceObject), + _platform(platform) { - new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_IP_PARAMETER), - new DataProperty(PID_PROJECT_INSTALLATION_ID, true, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv3), - new CallbackProperty(this, PID_KNX_INDIVIDUAL_ADDRESS, true, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv3, - [](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t + Property* properties[] = { - if (start == 0) + new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_IP_PARAMETER), + new DataProperty(PID_PROJECT_INSTALLATION_ID, true, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv3), + new CallbackProperty(this, PID_KNX_INDIVIDUAL_ADDRESS, true, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv3, + [](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); + if (start == 0) + { + uint16_t currentNoOfElements = 1; + pushWord(currentNoOfElements, data); + return 1; + } + // TODO: get property of deviceobject and use it + pushWord(io->_deviceObject.individualAddress(), data); return 1; - } - // TODO: get property of deviceobject and use it - pushWord(io->_deviceObject.individualAddress(), data); - return 1; - }, - [](IpParameterObject * io, uint16_t start, uint8_t count, const uint8_t* data) -> uint8_t - { - io->_deviceObject.individualAddress(getWord(data)); - return 1; - }), + }, + [](IpParameterObject * io, uint16_t start, uint8_t count, const uint8_t* data) -> uint8_t + { + io->_deviceObject.individualAddress(getWord(data)); + return 1; + }), #ifdef KNX_TUNNELING - new DataProperty(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, true, PDT_UNSIGNED_INT, KNX_TUNNELING, ReadLv3 | WriteLv3), - new DataProperty(PID_CUSTOM_RESERVED_TUNNELS_CTRL, true, PDT_UNSIGNED_CHAR, KNX_TUNNELING, ReadLv3 | WriteLv3), // custom propertiy to control the stacks behaviour for reserverd tunnels, not in Spec (PID >= 200) - new DataProperty(PID_CUSTOM_RESERVED_TUNNELS_IP, true, PDT_UNSIGNED_LONG, KNX_TUNNELING, ReadLv3 | WriteLv3), // custom propertiy to control the stacks behaviour for reserverd tunnels, not in Spec (PID >= 200) + new DataProperty(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, true, PDT_UNSIGNED_INT, KNX_TUNNELING, ReadLv3 | WriteLv3), + new DataProperty(PID_CUSTOM_RESERVED_TUNNELS_CTRL, true, PDT_UNSIGNED_CHAR, KNX_TUNNELING, ReadLv3 | WriteLv3), // custom propertiy to control the stacks behaviour for reserverd tunnels, not in Spec (PID >= 200) + new DataProperty(PID_CUSTOM_RESERVED_TUNNELS_IP, true, PDT_UNSIGNED_LONG, KNX_TUNNELING, ReadLv3 | WriteLv3), // custom propertiy to control the stacks behaviour for reserverd tunnels, not in Spec (PID >= 200) #endif - new DataProperty(PID_CURRENT_IP_ASSIGNMENT_METHOD, false, PDT_UNSIGNED_CHAR, 0, ReadLv3 | WriteLv3), - new DataProperty(PID_IP_ASSIGNMENT_METHOD, true, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv3), - new DataProperty(PID_IP_CAPABILITIES, true, PDT_BITSET8, 0, ReadLv3 | WriteLv1), // must be set by application due to capabilities of the used ip stack - new CallbackProperty(this, PID_CURRENT_IP_ADDRESS, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0, - [](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t - { - if (start == 0) + new DataProperty(PID_CURRENT_IP_ASSIGNMENT_METHOD, false, PDT_UNSIGNED_CHAR, 0, ReadLv3 | WriteLv3), + new DataProperty(PID_IP_ASSIGNMENT_METHOD, true, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv3), + new DataProperty(PID_IP_CAPABILITIES, true, PDT_BITSET8, 0, ReadLv3 | WriteLv1), // must be set by application due to capabilities of the used ip stack + new CallbackProperty(this, PID_CURRENT_IP_ADDRESS, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0, + [](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); - return 1; - } + if (start == 0) + { + uint16_t currentNoOfElements = 1; + pushWord(currentNoOfElements, data); + return 1; + } - pushInt(htonl(io->_platform.currentIpAddress()), data); - return 1; - }), - new CallbackProperty(this, PID_CURRENT_SUBNET_MASK, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0, - [](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t - { - if (start == 0) - { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); + pushInt(htonl(io->_platform.currentIpAddress()), data); return 1; - } - - pushInt(htonl(io->_platform.currentSubnetMask()), data); - return 1; - }), - new CallbackProperty(this, PID_CURRENT_DEFAULT_GATEWAY, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0, - [](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t - { - if (start == 0) + }), + new CallbackProperty(this, PID_CURRENT_SUBNET_MASK, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0, + [](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); - return 1; - } + if (start == 0) + { + uint16_t currentNoOfElements = 1; + pushWord(currentNoOfElements, data); + return 1; + } - pushInt(htonl(io->_platform.currentDefaultGateway()), data); - return 1; - }), - new DataProperty(PID_IP_ADDRESS, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3), - new DataProperty(PID_SUBNET_MASK, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3), - new DataProperty(PID_DEFAULT_GATEWAY, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3), - new CallbackProperty(this, PID_MAC_ADDRESS, false, PDT_GENERIC_06, 1, ReadLv3 | WriteLv0, - [](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t - { - if (start == 0) - { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); + pushInt(htonl(io->_platform.currentSubnetMask()), data); return 1; - } - - io->_platform.macAddress(data); - return 1; - }), - new CallbackProperty(this, PID_SYSTEM_SETUP_MULTICAST_ADDRESS, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0, - [](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t - { - if (start == 0) + }), + new CallbackProperty(this, PID_CURRENT_DEFAULT_GATEWAY, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0, + [](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); + if (start == 0) + { + uint16_t currentNoOfElements = 1; + pushWord(currentNoOfElements, data); + return 1; + } + + pushInt(htonl(io->_platform.currentDefaultGateway()), data); return 1; - } + }), + new DataProperty(PID_IP_ADDRESS, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3), + new DataProperty(PID_SUBNET_MASK, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3), + new DataProperty(PID_DEFAULT_GATEWAY, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3), + new CallbackProperty(this, PID_MAC_ADDRESS, false, PDT_GENERIC_06, 1, ReadLv3 | WriteLv0, + [](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t + { + if (start == 0) + { + uint16_t currentNoOfElements = 1; + pushWord(currentNoOfElements, data); + return 1; + } - pushInt(DEFAULT_MULTICAST_ADDR, data); - return 1; - }), - new DataProperty(PID_ROUTING_MULTICAST_ADDRESS, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3, DEFAULT_MULTICAST_ADDR), - new DataProperty(PID_TTL, true, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv3, (uint8_t)16), - new CallbackProperty(this, PID_KNXNETIP_DEVICE_CAPABILITIES, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0, - [](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t - { - if (start == 0) + io->_platform.macAddress(data); + return 1; + }), + new CallbackProperty(this, PID_SYSTEM_SETUP_MULTICAST_ADDRESS, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0, + [](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); + if (start == 0) + { + uint16_t currentNoOfElements = 1; + pushWord(currentNoOfElements, data); + return 1; + } + + pushInt(DEFAULT_MULTICAST_ADDR, data); return 1; - } + }), + new DataProperty(PID_ROUTING_MULTICAST_ADDRESS, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3, DEFAULT_MULTICAST_ADDR), + new DataProperty(PID_TTL, true, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv3, (uint8_t)16), + new CallbackProperty(this, PID_KNXNETIP_DEVICE_CAPABILITIES, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0, + [](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t + { + if (start == 0) + { + uint16_t currentNoOfElements = 1; + pushWord(currentNoOfElements, data); + return 1; + } - pushWord(0x1, data); - return 1; - }), - new DataProperty(PID_FRIENDLY_NAME, true, PDT_UNSIGNED_CHAR, 30, ReadLv3 | WriteLv3) - }; - initializeProperties(sizeof(properties), properties); -} + pushWord(0x1, data); + return 1; + }), + new DataProperty(PID_FRIENDLY_NAME, true, PDT_UNSIGNED_CHAR, 30, ReadLv3 | WriteLv3) + }; + initializeProperties(sizeof(properties), properties); + } -uint16_t* IpParameterObject::additionalIndivualAddresses(uint8_t& numAddresses) -{ -#ifdef KNX_TUNNELING - numAddresses = KNX_TUNNELING; + uint16_t* IpParameterObject::additionalIndivualAddresses(uint8_t& numAddresses) + { +#ifdef KNX_TUNNELING + numAddresses = KNX_TUNNELING; #else - numAddresses = 0; + numAddresses = 0; #endif - return (uint16_t*) propertyData(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES); -} + return (uint16_t*) propertyData(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES); + } +} \ No newline at end of file diff --git a/src/knx/ip/ip_parameter_object.h b/src/knx/ip/ip_parameter_object.h index 7cbfab41..cb5df317 100644 --- a/src/knx/ip/ip_parameter_object.h +++ b/src/knx/ip/ip_parameter_object.h @@ -5,12 +5,15 @@ #define KNXIP_MULTICAST_PORT 3671 -class IpParameterObject : public InterfaceObject +namespace Knx { - public: - IpParameterObject(DeviceObject& deviceObject, Platform& platform); - uint16_t* additionalIndivualAddresses(uint8_t& numAddresses); - private: - DeviceObject& _deviceObject; - Platform& _platform; -}; + class IpParameterObject : public InterfaceObject + { + public: + IpParameterObject(DeviceObject& deviceObject, Platform& platform); + uint16_t* additionalIndivualAddresses(uint8_t& numAddresses); + private: + DeviceObject& _deviceObject; + Platform& _platform; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_ch.cpp b/src/knx/ip/knx_ip_ch.cpp index 29dd9320..8a9ae8b9 100644 --- a/src/knx/ip/knx_ip_ch.cpp +++ b/src/knx/ip/knx_ip_ch.cpp @@ -1,47 +1,50 @@ #include "knx_ip_ch.h" -KnxIpCH::KnxIpCH(uint8_t* data) : _data(data) -{} - -KnxIpCH::~KnxIpCH() -{} - -uint8_t KnxIpCH::length() const -{ - return *_data; -} - -void KnxIpCH::length(uint8_t value) -{ - *_data = value; -} - -void KnxIpCH::channelId(uint8_t value) -{ - _data[1] = value; -} - -uint8_t KnxIpCH::channelId() const -{ - return _data[1]; -} - -void KnxIpCH::sequenceCounter(uint8_t value) -{ - _data[2] = value; -} - -uint8_t KnxIpCH::sequenceCounter() const -{ - return _data[2]; -} - -void KnxIpCH::status(uint8_t value) -{ - _data[3] = value; -} - -uint8_t KnxIpCH::status() const -{ - return _data[3]; -} +namespace Knx +{ + KnxIpCH::KnxIpCH(uint8_t* data) : _data(data) + {} + + KnxIpCH::~KnxIpCH() + {} + + uint8_t KnxIpCH::length() const + { + return *_data; + } + + void KnxIpCH::length(uint8_t value) + { + *_data = value; + } + + void KnxIpCH::channelId(uint8_t value) + { + _data[1] = value; + } + + uint8_t KnxIpCH::channelId() const + { + return _data[1]; + } + + void KnxIpCH::sequenceCounter(uint8_t value) + { + _data[2] = value; + } + + uint8_t KnxIpCH::sequenceCounter() const + { + return _data[2]; + } + + void KnxIpCH::status(uint8_t value) + { + _data[3] = value; + } + + uint8_t KnxIpCH::status() const + { + return _data[3]; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_ch.h b/src/knx/ip/knx_ip_ch.h index e8037a6a..8ea5b341 100644 --- a/src/knx/ip/knx_ip_ch.h +++ b/src/knx/ip/knx_ip_ch.h @@ -4,21 +4,24 @@ #define LEN_CH 4 -// Connection Header -class KnxIpCH +namespace Knx { - public: - KnxIpCH(uint8_t* data); - virtual ~KnxIpCH(); - void channelId(uint8_t channelId); - uint8_t channelId() const; - void sequenceCounter(uint8_t sequenceCounter); - uint8_t sequenceCounter() const; - void status(uint8_t status); - uint8_t status() const; - void length(uint8_t value); - uint8_t length() const; + // Connection Header + class KnxIpCH + { + public: + KnxIpCH(uint8_t* data); + virtual ~KnxIpCH(); + void channelId(uint8_t channelId); + uint8_t channelId() const; + void sequenceCounter(uint8_t sequenceCounter); + uint8_t sequenceCounter() const; + void status(uint8_t status); + uint8_t status() const; + void length(uint8_t value); + uint8_t length() const; - protected: - uint8_t* _data = 0; -}; + protected: + uint8_t* _data = 0; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_config_dib.cpp b/src/knx/ip/knx_ip_config_dib.cpp index fa3ac139..5e9cc9fa 100644 --- a/src/knx/ip/knx_ip_config_dib.cpp +++ b/src/knx/ip/knx_ip_config_dib.cpp @@ -1,93 +1,96 @@ #include "knx_ip_config_dib.h" #include "../bits.h" -KnxIpConfigDIB::KnxIpConfigDIB(uint8_t* data, bool isCurrent) : KnxIpDIB(data) +namespace Knx { - _isCurrent = isCurrent; -} + KnxIpConfigDIB::KnxIpConfigDIB(uint8_t* data, bool isCurrent) : KnxIpDIB(data) + { + _isCurrent = isCurrent; + } -uint32_t KnxIpConfigDIB::address() -{ - uint32_t addr = 0; - popInt(addr, _data + 2); - return addr; -} + uint32_t KnxIpConfigDIB::address() + { + uint32_t addr = 0; + popInt(addr, _data + 2); + return addr; + } -void KnxIpConfigDIB::address(uint32_t addr) -{ - pushInt(addr, _data + 2); -} + void KnxIpConfigDIB::address(uint32_t addr) + { + pushInt(addr, _data + 2); + } -uint32_t KnxIpConfigDIB::subnet() -{ - uint32_t addr = 0; - popInt(addr, _data + 6); - return addr; -} + uint32_t KnxIpConfigDIB::subnet() + { + uint32_t addr = 0; + popInt(addr, _data + 6); + return addr; + } -void KnxIpConfigDIB::subnet(uint32_t addr) -{ - pushInt(addr, _data + 6); -} + void KnxIpConfigDIB::subnet(uint32_t addr) + { + pushInt(addr, _data + 6); + } -uint32_t KnxIpConfigDIB::gateway() -{ - uint32_t addr = 0; - popInt(addr, _data + 10); - return addr; -} + uint32_t KnxIpConfigDIB::gateway() + { + uint32_t addr = 0; + popInt(addr, _data + 10); + return addr; + } -void KnxIpConfigDIB::gateway(uint32_t addr) -{ - pushInt(addr, _data + 10); -} + void KnxIpConfigDIB::gateway(uint32_t addr) + { + pushInt(addr, _data + 10); + } -uint32_t KnxIpConfigDIB::dhcp() -{ - if (!_isCurrent) - return 0; + uint32_t KnxIpConfigDIB::dhcp() + { + if (!_isCurrent) + return 0; - uint32_t addr = 0; - popInt(addr, _data + 14); - return addr; -} + uint32_t addr = 0; + popInt(addr, _data + 14); + return addr; + } -void KnxIpConfigDIB::dhcp(uint32_t addr) -{ - if (!_isCurrent) - return; + void KnxIpConfigDIB::dhcp(uint32_t addr) + { + if (!_isCurrent) + return; - pushInt(addr, _data + 14); -} + pushInt(addr, _data + 14); + } -uint8_t KnxIpConfigDIB::info1() -{ - if (_isCurrent) - return _data[14]; - else - return _data[18]; -} + uint8_t KnxIpConfigDIB::info1() + { + if (_isCurrent) + return _data[14]; + else + return _data[18]; + } -void KnxIpConfigDIB::info1(uint8_t addr) -{ - if (_isCurrent) - _data[14] = addr; - else - _data[18] = addr; -} + void KnxIpConfigDIB::info1(uint8_t addr) + { + if (_isCurrent) + _data[14] = addr; + else + _data[18] = addr; + } -uint8_t KnxIpConfigDIB::info2() -{ - if (_isCurrent) - return _data[15]; - else - return _data[19]; -} + uint8_t KnxIpConfigDIB::info2() + { + if (_isCurrent) + return _data[15]; + else + return _data[19]; + } -void KnxIpConfigDIB::info2(uint8_t addr) -{ - if (_isCurrent) - _data[15] = addr; - else - _data[19] = addr; -} + void KnxIpConfigDIB::info2(uint8_t addr) + { + if (_isCurrent) + _data[15] = addr; + else + _data[19] = addr; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_config_dib.h b/src/knx/ip/knx_ip_config_dib.h index e85d5256..1ba055e8 100644 --- a/src/knx/ip/knx_ip_config_dib.h +++ b/src/knx/ip/knx_ip_config_dib.h @@ -4,22 +4,25 @@ #define LEN_IP_CONFIG_DIB 16 #define LEN_IP_CURRENT_CONFIG_DIB 20 -class KnxIpConfigDIB : public KnxIpDIB +namespace Knx { - public: - KnxIpConfigDIB(uint8_t* data, bool isCurrent = false); - uint32_t address(); - void address(uint32_t addr); - uint32_t subnet(); - void subnet(uint32_t addr); - uint32_t gateway(); - void gateway(uint32_t addr); - uint32_t dhcp(); - void dhcp(uint32_t addr); - uint8_t info1(); - void info1(uint8_t addr); - uint8_t info2(); - void info2(uint8_t addr); - private: - bool _isCurrent = false; -}; \ No newline at end of file + class KnxIpConfigDIB : public KnxIpDIB + { + public: + KnxIpConfigDIB(uint8_t* data, bool isCurrent = false); + uint32_t address(); + void address(uint32_t addr); + uint32_t subnet(); + void subnet(uint32_t addr); + uint32_t gateway(); + void gateway(uint32_t addr); + uint32_t dhcp(); + void dhcp(uint32_t addr); + uint8_t info1(); + void info1(uint8_t addr); + uint8_t info2(); + void info2(uint8_t addr); + private: + bool _isCurrent = false; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_config_request.cpp b/src/knx/ip/knx_ip_config_request.cpp index eb9651e7..9555707d 100644 --- a/src/knx/ip/knx_ip_config_request.cpp +++ b/src/knx/ip/knx_ip_config_request.cpp @@ -1,16 +1,19 @@ #include "knx_ip_config_request.h" -KnxIpConfigRequest::KnxIpConfigRequest(uint8_t* data, uint16_t length) - : KnxIpFrame(data, length), _frame(data + LEN_KNXIP_HEADER + LEN_CH, length - LEN_KNXIP_HEADER - LEN_CH), _ch(data + LEN_KNXIP_HEADER) +namespace Knx { -} + KnxIpConfigRequest::KnxIpConfigRequest(uint8_t* data, uint16_t length) + : KnxIpFrame(data, length), _frame(data + LEN_KNXIP_HEADER + LEN_CH, length - LEN_KNXIP_HEADER - LEN_CH), _ch(data + LEN_KNXIP_HEADER) + { + } -CemiFrame& KnxIpConfigRequest::frame() -{ - return _frame; -} + CemiFrame& KnxIpConfigRequest::frame() + { + return _frame; + } -KnxIpCH& KnxIpConfigRequest::connectionHeader() -{ - return _ch; -} + KnxIpCH& KnxIpConfigRequest::connectionHeader() + { + return _ch; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_config_request.h b/src/knx/ip/knx_ip_config_request.h index 3af9cfee..347846b1 100644 --- a/src/knx/ip/knx_ip_config_request.h +++ b/src/knx/ip/knx_ip_config_request.h @@ -4,13 +4,16 @@ #include "knx_ip_ch.h" #include "ip_host_protocol_address_information.h" -class KnxIpConfigRequest : public KnxIpFrame +namespace Knx { - public: - KnxIpConfigRequest(uint8_t* data, uint16_t length); - CemiFrame& frame(); - KnxIpCH& connectionHeader(); - private: - CemiFrame _frame; - KnxIpCH _ch; -}; + class KnxIpConfigRequest : public KnxIpFrame + { + public: + KnxIpConfigRequest(uint8_t* data, uint16_t length); + CemiFrame& frame(); + KnxIpCH& connectionHeader(); + private: + CemiFrame _frame; + KnxIpCH _ch; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_connect_request.cpp b/src/knx/ip/knx_ip_connect_request.cpp index 9bfa4363..6913f0d8 100644 --- a/src/knx/ip/knx_ip_connect_request.cpp +++ b/src/knx/ip/knx_ip_connect_request.cpp @@ -1,20 +1,23 @@ #include "knx_ip_connect_request.h" -KnxIpConnectRequest::KnxIpConnectRequest(uint8_t* data, uint16_t length) - : KnxIpFrame(data, length), _hpaiCtrl(data + LEN_KNXIP_HEADER), _hpaiData(data + LEN_KNXIP_HEADER + LEN_IPHPAI), _cri(data + LEN_KNXIP_HEADER + 2 * LEN_IPHPAI) +namespace Knx { -} + KnxIpConnectRequest::KnxIpConnectRequest(uint8_t* data, uint16_t length) + : KnxIpFrame(data, length), _hpaiCtrl(data + LEN_KNXIP_HEADER), _hpaiData(data + LEN_KNXIP_HEADER + LEN_IPHPAI), _cri(data + LEN_KNXIP_HEADER + 2 * LEN_IPHPAI) + { + } -IpHostProtocolAddressInformation& KnxIpConnectRequest::hpaiCtrl() -{ - return _hpaiCtrl; -} -IpHostProtocolAddressInformation& KnxIpConnectRequest::hpaiData() -{ - return _hpaiData; -} -KnxIpCRI& KnxIpConnectRequest::cri() -{ - return _cri; -} + IpHostProtocolAddressInformation& KnxIpConnectRequest::hpaiCtrl() + { + return _hpaiCtrl; + } + IpHostProtocolAddressInformation& KnxIpConnectRequest::hpaiData() + { + return _hpaiData; + } + KnxIpCRI& KnxIpConnectRequest::cri() + { + return _cri; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_connect_request.h b/src/knx/ip/knx_ip_connect_request.h index cfa4a3b6..7523395b 100644 --- a/src/knx/ip/knx_ip_connect_request.h +++ b/src/knx/ip/knx_ip_connect_request.h @@ -4,15 +4,18 @@ #include "knx_ip_cri.h" #include "ip_host_protocol_address_information.h" -class KnxIpConnectRequest : public KnxIpFrame +namespace Knx { - public: - KnxIpConnectRequest(uint8_t* data, uint16_t length); - IpHostProtocolAddressInformation& hpaiCtrl(); - IpHostProtocolAddressInformation& hpaiData(); - KnxIpCRI& cri(); - private: - IpHostProtocolAddressInformation _hpaiCtrl; - IpHostProtocolAddressInformation _hpaiData; - KnxIpCRI _cri; -}; + class KnxIpConnectRequest : public KnxIpFrame + { + public: + KnxIpConnectRequest(uint8_t* data, uint16_t length); + IpHostProtocolAddressInformation& hpaiCtrl(); + IpHostProtocolAddressInformation& hpaiData(); + KnxIpCRI& cri(); + private: + IpHostProtocolAddressInformation _hpaiCtrl; + IpHostProtocolAddressInformation _hpaiData; + KnxIpCRI _cri; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_connect_response.cpp b/src/knx/ip/knx_ip_connect_response.cpp index 6d594803..f760a4c7 100644 --- a/src/knx/ip/knx_ip_connect_response.cpp +++ b/src/knx/ip/knx_ip_connect_response.cpp @@ -1,42 +1,45 @@ #include "knx_ip_connect_response.h" -KnxIpConnectResponse::KnxIpConnectResponse(IpParameterObject& parameters, uint16_t address, uint16_t port, uint8_t channel, uint8_t type) - : KnxIpFrame(LEN_KNXIP_HEADER + 1 /*Channel*/ + 1 /*Status*/ + LEN_IPHPAI + ((type == 4) ? 4 : 2)), - _controlEndpoint(_data + LEN_KNXIP_HEADER + 1 /*Channel*/ + 1 /*Status*/), - _crd(_data + LEN_KNXIP_HEADER + 1 /*Channel*/ + 1 /*Status*/ + LEN_IPHPAI) +namespace Knx { - serviceTypeIdentifier(ConnectResponse); - - _data[LEN_KNXIP_HEADER] = channel; - - _controlEndpoint.length(LEN_IPHPAI); - _controlEndpoint.code(IPV4_UDP); - _controlEndpoint.ipAddress(parameters.propertyValue(PID_CURRENT_IP_ADDRESS)); - _controlEndpoint.ipPortNumber(KNXIP_MULTICAST_PORT); - - _crd.length((type == 4) ? 4 : 2); //TunnelConnectionResponse length = 4; ConfigConnectionResponse length = 2; - _crd.type(type); - _crd.address(address); -} - -KnxIpConnectResponse::KnxIpConnectResponse(uint8_t channel, uint8_t errorCode) - : KnxIpFrame(LEN_KNXIP_HEADER + 1 /*Channel*/ + 1 /*Status*/), - _controlEndpoint(nullptr), - _crd(nullptr) -{ - serviceTypeIdentifier(ConnectResponse); - - _data[LEN_KNXIP_HEADER] = channel; - _data[LEN_KNXIP_HEADER + 1] = errorCode; -} - - -IpHostProtocolAddressInformation& KnxIpConnectResponse::controlEndpoint() -{ - return _controlEndpoint; -} - -KnxIpCRD& KnxIpConnectResponse::crd() -{ - return _crd; -} + KnxIpConnectResponse::KnxIpConnectResponse(IpParameterObject& parameters, uint16_t address, uint16_t port, uint8_t channel, uint8_t type) + : KnxIpFrame(LEN_KNXIP_HEADER + 1 /*Channel*/ + 1 /*Status*/ + LEN_IPHPAI + ((type == 4) ? 4 : 2)), + _controlEndpoint(_data + LEN_KNXIP_HEADER + 1 /*Channel*/ + 1 /*Status*/), + _crd(_data + LEN_KNXIP_HEADER + 1 /*Channel*/ + 1 /*Status*/ + LEN_IPHPAI) + { + serviceTypeIdentifier(ConnectResponse); + + _data[LEN_KNXIP_HEADER] = channel; + + _controlEndpoint.length(LEN_IPHPAI); + _controlEndpoint.code(IPV4_UDP); + _controlEndpoint.ipAddress(parameters.propertyValue(PID_CURRENT_IP_ADDRESS)); + _controlEndpoint.ipPortNumber(KNXIP_MULTICAST_PORT); + + _crd.length((type == 4) ? 4 : 2); //TunnelConnectionResponse length = 4; ConfigConnectionResponse length = 2; + _crd.type(type); + _crd.address(address); + } + + KnxIpConnectResponse::KnxIpConnectResponse(uint8_t channel, uint8_t errorCode) + : KnxIpFrame(LEN_KNXIP_HEADER + 1 /*Channel*/ + 1 /*Status*/), + _controlEndpoint(nullptr), + _crd(nullptr) + { + serviceTypeIdentifier(ConnectResponse); + + _data[LEN_KNXIP_HEADER] = channel; + _data[LEN_KNXIP_HEADER + 1] = errorCode; + } + + + IpHostProtocolAddressInformation& KnxIpConnectResponse::controlEndpoint() + { + return _controlEndpoint; + } + + KnxIpCRD& KnxIpConnectResponse::crd() + { + return _crd; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_connect_response.h b/src/knx/ip/knx_ip_connect_response.h index da4f8220..7604766b 100644 --- a/src/knx/ip/knx_ip_connect_response.h +++ b/src/knx/ip/knx_ip_connect_response.h @@ -7,36 +7,39 @@ #include "knx_ip_supported_service_dib.h" #include "ip_parameter_object.h" -enum KnxIpConnectionRequestErrorCodes +namespace Knx { - E_NO_ERROR = 0, + enum KnxIpConnectionRequestErrorCodes + { + E_NO_ERROR = 0, - E_HOST_PROTOCOL_TYPE = 0x01, - E_VERSION_NOT_SUPPORTED = 0x02, - E_SEQUENCE_NUMBER = 0x04, + E_HOST_PROTOCOL_TYPE = 0x01, + E_VERSION_NOT_SUPPORTED = 0x02, + E_SEQUENCE_NUMBER = 0x04, - E_ERROR = 0x0F, + E_ERROR = 0x0F, - E_CONNECTION_ID = 0x21, - E_CONNECTION_TYPE = 0x22, - E_CONNECTION_OPTION = 0x23, - E_NO_MORE_CONNECTIONS = 0x24, - E_DATA_CONNECTION = 0x26, - E_KNX_CONNECTION = 0x27, - E_AUTHORISATION_ERROR = 0x28, - E_TUNNELING_LAYER = 0x29, - E_NO_TUNNELLING_ADDRESS = 0x2D, - E_CONNECTION_IN_USE = 0x2E -}; + E_CONNECTION_ID = 0x21, + E_CONNECTION_TYPE = 0x22, + E_CONNECTION_OPTION = 0x23, + E_NO_MORE_CONNECTIONS = 0x24, + E_DATA_CONNECTION = 0x26, + E_KNX_CONNECTION = 0x27, + E_AUTHORISATION_ERROR = 0x28, + E_TUNNELING_LAYER = 0x29, + E_NO_TUNNELLING_ADDRESS = 0x2D, + E_CONNECTION_IN_USE = 0x2E + }; -class KnxIpConnectResponse : public KnxIpFrame -{ - public: - KnxIpConnectResponse(IpParameterObject& parameters, uint16_t address, uint16_t port, uint8_t channel, uint8_t type); - KnxIpConnectResponse(uint8_t channel, uint8_t errorCode); - IpHostProtocolAddressInformation& controlEndpoint(); - KnxIpCRD& crd(); - private: - IpHostProtocolAddressInformation _controlEndpoint; - KnxIpCRD _crd; -}; + class KnxIpConnectResponse : public KnxIpFrame + { + public: + KnxIpConnectResponse(IpParameterObject& parameters, uint16_t address, uint16_t port, uint8_t channel, uint8_t type); + KnxIpConnectResponse(uint8_t channel, uint8_t errorCode); + IpHostProtocolAddressInformation& controlEndpoint(); + KnxIpCRD& crd(); + private: + IpHostProtocolAddressInformation _controlEndpoint; + KnxIpCRD _crd; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_crd.cpp b/src/knx/ip/knx_ip_crd.cpp index 044a6ad7..a1209e42 100644 --- a/src/knx/ip/knx_ip_crd.cpp +++ b/src/knx/ip/knx_ip_crd.cpp @@ -1,40 +1,43 @@ #include "knx_ip_crd.h" -KnxIpCRD::KnxIpCRD(uint8_t* data) : _data(data) -{} - -KnxIpCRD::~KnxIpCRD() -{} - -uint8_t KnxIpCRD::length() const -{ - return *_data; -} - -void KnxIpCRD::length(uint8_t value) -{ - *_data = value; -} - -uint8_t KnxIpCRD::type() const -{ - return _data[1]; -} - -void KnxIpCRD::type(uint8_t value) -{ - _data[1] = value; -} - -uint16_t KnxIpCRD::address() const -{ - uint16_t addr = _data[3]; - addr |= _data[2] << 8; - return addr; -} - -void KnxIpCRD::address(uint16_t value) +namespace Knx { - _data[2] = value >> 8; - _data[3] = value & 0xFF; -} + KnxIpCRD::KnxIpCRD(uint8_t* data) : _data(data) + {} + + KnxIpCRD::~KnxIpCRD() + {} + + uint8_t KnxIpCRD::length() const + { + return *_data; + } + + void KnxIpCRD::length(uint8_t value) + { + *_data = value; + } + + uint8_t KnxIpCRD::type() const + { + return _data[1]; + } + + void KnxIpCRD::type(uint8_t value) + { + _data[1] = value; + } + + uint16_t KnxIpCRD::address() const + { + uint16_t addr = _data[3]; + addr |= _data[2] << 8; + return addr; + } + + void KnxIpCRD::address(uint16_t value) + { + _data[2] = value >> 8; + _data[3] = value & 0xFF; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_crd.h b/src/knx/ip/knx_ip_crd.h index 14cc1f41..a042d697 100644 --- a/src/knx/ip/knx_ip_crd.h +++ b/src/knx/ip/knx_ip_crd.h @@ -2,18 +2,21 @@ #include -class KnxIpCRD +namespace Knx { - public: - KnxIpCRD(uint8_t* data); - virtual ~KnxIpCRD(); - void address(uint16_t addr); - uint16_t address() const; - void type(uint8_t addr); - uint8_t type() const; - uint8_t length() const; - void length(uint8_t value); + class KnxIpCRD + { + public: + KnxIpCRD(uint8_t* data); + virtual ~KnxIpCRD(); + void address(uint16_t addr); + uint16_t address() const; + void type(uint8_t addr); + uint8_t type() const; + uint8_t length() const; + void length(uint8_t value); - protected: - uint8_t* _data = 0; -}; + protected: + uint8_t* _data = 0; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_cri.cpp b/src/knx/ip/knx_ip_cri.cpp index 6f2903ea..76bbd8f9 100644 --- a/src/knx/ip/knx_ip_cri.cpp +++ b/src/knx/ip/knx_ip_cri.cpp @@ -1,37 +1,40 @@ #include "knx_ip_cri.h" -KnxIpCRI::KnxIpCRI(uint8_t* data) : _data(data) -{} - -KnxIpCRI::~KnxIpCRI() -{} - -uint8_t KnxIpCRI::length() const -{ - return *_data; -} - -void KnxIpCRI::length(uint8_t value) -{ - *_data = value; -} - -ConnectionType KnxIpCRI::type() const -{ - return (ConnectionType)_data[1]; -} - -void KnxIpCRI::type(ConnectionType value) -{ - _data[1] = value; -} - -uint8_t KnxIpCRI::layer() const -{ - return _data[2]; -} - -void KnxIpCRI::layer(uint8_t value) +namespace Knx { - _data[2] = value; -} + KnxIpCRI::KnxIpCRI(uint8_t* data) : _data(data) + {} + + KnxIpCRI::~KnxIpCRI() + {} + + uint8_t KnxIpCRI::length() const + { + return *_data; + } + + void KnxIpCRI::length(uint8_t value) + { + *_data = value; + } + + ConnectionType KnxIpCRI::type() const + { + return (ConnectionType)_data[1]; + } + + void KnxIpCRI::type(ConnectionType value) + { + _data[1] = value; + } + + uint8_t KnxIpCRI::layer() const + { + return _data[2]; + } + + void KnxIpCRI::layer(uint8_t value) + { + _data[2] = value; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_cri.h b/src/knx/ip/knx_ip_cri.h index d845a59a..5a69fb26 100644 --- a/src/knx/ip/knx_ip_cri.h +++ b/src/knx/ip/knx_ip_cri.h @@ -4,29 +4,32 @@ #define LEN_CRI 4 -//TODO vervollständigen -enum ConnectionType : uint8_t +namespace Knx { - DEVICE_MGMT_CONNECTION = 3, - TUNNEL_CONNECTION = 4, - REMLOG_CONNECTION = 6, - REMCONF_CONNECTION = 7, - OBJSVR_CONNECTION = 8 -}; + //TODO vervollständigen + enum ConnectionType : uint8_t + { + DEVICE_MGMT_CONNECTION = 3, + TUNNEL_CONNECTION = 4, + REMLOG_CONNECTION = 6, + REMCONF_CONNECTION = 7, + OBJSVR_CONNECTION = 8 + }; -// Connection Request Information -class KnxIpCRI -{ - public: - KnxIpCRI(uint8_t* data); - virtual ~KnxIpCRI(); - ConnectionType type() const; - void type(ConnectionType value); - void layer(uint8_t layer); - uint8_t layer() const; - uint8_t length() const; - void length(uint8_t value); + // Connection Request Information + class KnxIpCRI + { + public: + KnxIpCRI(uint8_t* data); + virtual ~KnxIpCRI(); + ConnectionType type() const; + void type(ConnectionType value); + void layer(uint8_t layer); + uint8_t layer() const; + uint8_t length() const; + void length(uint8_t value); - protected: - uint8_t* _data = 0; -}; + protected: + uint8_t* _data = 0; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_description_request.cpp b/src/knx/ip/knx_ip_description_request.cpp index 69d79eb8..1b5c06a9 100644 --- a/src/knx/ip/knx_ip_description_request.cpp +++ b/src/knx/ip/knx_ip_description_request.cpp @@ -1,12 +1,15 @@ #include "knx_ip_description_request.h" -KnxIpDescriptionRequest::KnxIpDescriptionRequest(uint8_t* data, uint16_t length) - : KnxIpFrame(data, length), _hpaiCtrl(data + LEN_KNXIP_HEADER) +namespace Knx { -} + KnxIpDescriptionRequest::KnxIpDescriptionRequest(uint8_t* data, uint16_t length) + : KnxIpFrame(data, length), _hpaiCtrl(data + LEN_KNXIP_HEADER) + { + } -IpHostProtocolAddressInformation& KnxIpDescriptionRequest::hpaiCtrl() -{ - return _hpaiCtrl; -} + IpHostProtocolAddressInformation& KnxIpDescriptionRequest::hpaiCtrl() + { + return _hpaiCtrl; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_description_request.h b/src/knx/ip/knx_ip_description_request.h index 669ecd31..51658f31 100644 --- a/src/knx/ip/knx_ip_description_request.h +++ b/src/knx/ip/knx_ip_description_request.h @@ -4,11 +4,15 @@ #include "knx_ip_cri.h" #include "ip_host_protocol_address_information.h" -class KnxIpDescriptionRequest : public KnxIpFrame + +namespace Knx { - public: - KnxIpDescriptionRequest(uint8_t* data, uint16_t length); - IpHostProtocolAddressInformation& hpaiCtrl(); - private: - IpHostProtocolAddressInformation _hpaiCtrl; -}; + class KnxIpDescriptionRequest : public KnxIpFrame + { + public: + KnxIpDescriptionRequest(uint8_t* data, uint16_t length); + IpHostProtocolAddressInformation& hpaiCtrl(); + private: + IpHostProtocolAddressInformation _hpaiCtrl; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_description_response.cpp b/src/knx/ip/knx_ip_description_response.cpp index a59041d5..c0d5ad67 100644 --- a/src/knx/ip/knx_ip_description_response.cpp +++ b/src/knx/ip/knx_ip_description_response.cpp @@ -15,56 +15,59 @@ #endif #endif -KnxIpDescriptionResponse::KnxIpDescriptionResponse(IpParameterObject& parameters, DeviceObject& deviceObject) - : KnxIpFrame(LEN_KNXIP_HEADER + LEN_DEVICE_INFORMATION_DIB + LEN_SERVICE_DIB), - _deviceInfo(_data + LEN_KNXIP_HEADER), - _supportedServices(_data + LEN_KNXIP_HEADER + LEN_DEVICE_INFORMATION_DIB) +namespace Knx { - serviceTypeIdentifier(DescriptionResponse); + KnxIpDescriptionResponse::KnxIpDescriptionResponse(IpParameterObject& parameters, DeviceObject& deviceObject) + : KnxIpFrame(LEN_KNXIP_HEADER + LEN_DEVICE_INFORMATION_DIB + LEN_SERVICE_DIB), + _deviceInfo(_data + LEN_KNXIP_HEADER), + _supportedServices(_data + LEN_KNXIP_HEADER + LEN_DEVICE_INFORMATION_DIB) + { + serviceTypeIdentifier(DescriptionResponse); - _deviceInfo.length(LEN_DEVICE_INFORMATION_DIB); - _deviceInfo.code(DEVICE_INFO); + _deviceInfo.length(LEN_DEVICE_INFORMATION_DIB); + _deviceInfo.code(DEVICE_INFO); #if MASK_VERSION == 0x57B0 - _deviceInfo.medium(0x20); //MediumType is IP (for IP-Only Devices) + _deviceInfo.medium(0x20); //MediumType is IP (for IP-Only Devices) #else - _deviceInfo.medium(0x02); //MediumType is TP + _deviceInfo.medium(0x02); //MediumType is TP #endif - _deviceInfo.status(deviceObject.progMode()); - _deviceInfo.individualAddress(parameters.propertyValue(PID_KNX_INDIVIDUAL_ADDRESS)); - _deviceInfo.projectInstallationIdentifier(parameters.propertyValue(PID_PROJECT_INSTALLATION_ID)); - _deviceInfo.serialNumber(deviceObject.propertyData(PID_SERIAL_NUMBER)); - _deviceInfo.routingMulticastAddress(parameters.propertyValue(PID_ROUTING_MULTICAST_ADDRESS)); - //_deviceInfo.routingMulticastAddress(0); + _deviceInfo.status(deviceObject.progMode()); + _deviceInfo.individualAddress(parameters.propertyValue(PID_KNX_INDIVIDUAL_ADDRESS)); + _deviceInfo.projectInstallationIdentifier(parameters.propertyValue(PID_PROJECT_INSTALLATION_ID)); + _deviceInfo.serialNumber(deviceObject.propertyData(PID_SERIAL_NUMBER)); + _deviceInfo.routingMulticastAddress(parameters.propertyValue(PID_ROUTING_MULTICAST_ADDRESS)); + //_deviceInfo.routingMulticastAddress(0); - uint8_t mac_address[LEN_MAC_ADDRESS] = {0}; - Property* prop = parameters.property(PID_MAC_ADDRESS); - prop->read(mac_address); - _deviceInfo.macAddress(mac_address); + uint8_t mac_address[LEN_MAC_ADDRESS] = {0}; + Property* prop = parameters.property(PID_MAC_ADDRESS); + prop->read(mac_address); + _deviceInfo.macAddress(mac_address); - uint8_t friendlyName[LEN_FRIENDLY_NAME] = {0}; - prop = parameters.property(PID_FRIENDLY_NAME); - prop->read(1, LEN_FRIENDLY_NAME, friendlyName); - _deviceInfo.friendlyName(friendlyName); + uint8_t friendlyName[LEN_FRIENDLY_NAME] = {0}; + prop = parameters.property(PID_FRIENDLY_NAME); + prop->read(1, LEN_FRIENDLY_NAME, friendlyName); + _deviceInfo.friendlyName(friendlyName); - _supportedServices.length(LEN_SERVICE_DIB); - _supportedServices.code(SUPP_SVC_FAMILIES); - _supportedServices.serviceVersion(Core, 1); - _supportedServices.serviceVersion(DeviceManagement, 1); + _supportedServices.length(LEN_SERVICE_DIB); + _supportedServices.code(SUPP_SVC_FAMILIES); + _supportedServices.serviceVersion(Core, 1); + _supportedServices.serviceVersion(DeviceManagement, 1); #ifdef KNX_TUNNELING - _supportedServices.serviceVersion(Tunnelling, 1); + _supportedServices.serviceVersion(Tunnelling, 1); #endif #if MASK_VERSION == 0x091A - _supportedServices.serviceVersion(Routing, 1); + _supportedServices.serviceVersion(Routing, 1); #endif -} + } -KnxIpDeviceInformationDIB& KnxIpDescriptionResponse::deviceInfo() -{ - return _deviceInfo; -} + KnxIpDeviceInformationDIB& KnxIpDescriptionResponse::deviceInfo() + { + return _deviceInfo; + } -KnxIpSupportedServiceDIB& KnxIpDescriptionResponse::supportedServices() -{ - return _supportedServices; -} + KnxIpSupportedServiceDIB& KnxIpDescriptionResponse::supportedServices() + { + return _supportedServices; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_description_response.h b/src/knx/ip/knx_ip_description_response.h index 136eb5cb..07a89812 100644 --- a/src/knx/ip/knx_ip_description_response.h +++ b/src/knx/ip/knx_ip_description_response.h @@ -6,13 +6,16 @@ #include "knx_ip_supported_service_dib.h" #include "ip_parameter_object.h" -class KnxIpDescriptionResponse : public KnxIpFrame +namespace Knx { - public: - KnxIpDescriptionResponse(IpParameterObject& parameters, DeviceObject& deviceObj); - KnxIpDeviceInformationDIB& deviceInfo(); - KnxIpSupportedServiceDIB& supportedServices(); - private: - KnxIpDeviceInformationDIB _deviceInfo; - KnxIpSupportedServiceDIB _supportedServices; -}; + class KnxIpDescriptionResponse : public KnxIpFrame + { + public: + KnxIpDescriptionResponse(IpParameterObject& parameters, DeviceObject& deviceObj); + KnxIpDeviceInformationDIB& deviceInfo(); + KnxIpSupportedServiceDIB& supportedServices(); + private: + KnxIpDeviceInformationDIB _deviceInfo; + KnxIpSupportedServiceDIB _supportedServices; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_device_information_dib.cpp b/src/knx/ip/knx_ip_device_information_dib.cpp index e8d29964..91ad01dd 100644 --- a/src/knx/ip/knx_ip_device_information_dib.cpp +++ b/src/knx/ip/knx_ip_device_information_dib.cpp @@ -1,100 +1,103 @@ #include "knx_ip_device_information_dib.h" #include "../bits.h" -KnxIpDeviceInformationDIB::KnxIpDeviceInformationDIB(uint8_t* data) : KnxIpDIB(data) -{} - -uint8_t KnxIpDeviceInformationDIB::medium() const +namespace Knx { - return _data[2]; -} + KnxIpDeviceInformationDIB::KnxIpDeviceInformationDIB(uint8_t* data) : KnxIpDIB(data) + {} + uint8_t KnxIpDeviceInformationDIB::medium() const + { + return _data[2]; + } -void KnxIpDeviceInformationDIB::medium(uint8_t value) -{ - _data[2] = value; -} + void KnxIpDeviceInformationDIB::medium(uint8_t value) + { + _data[2] = value; + } -uint8_t KnxIpDeviceInformationDIB::status() const -{ - return _data[3]; -} + uint8_t KnxIpDeviceInformationDIB::status() const + { + return _data[3]; + } -void KnxIpDeviceInformationDIB::status(uint8_t value) -{ - _data[3] = value; -} + void KnxIpDeviceInformationDIB::status(uint8_t value) + { + _data[3] = value; + } -uint16_t KnxIpDeviceInformationDIB::individualAddress() const -{ - return getWord(_data + 4); -} + uint16_t KnxIpDeviceInformationDIB::individualAddress() const + { + return getWord(_data + 4); + } -void KnxIpDeviceInformationDIB::individualAddress(uint16_t value) -{ - pushWord(value, _data + 4); -} + void KnxIpDeviceInformationDIB::individualAddress(uint16_t value) + { + pushWord(value, _data + 4); + } -uint16_t KnxIpDeviceInformationDIB::projectInstallationIdentifier() const -{ - return getWord(_data + 6); -} + uint16_t KnxIpDeviceInformationDIB::projectInstallationIdentifier() const + { + return getWord(_data + 6); + } -void KnxIpDeviceInformationDIB::projectInstallationIdentifier(uint16_t value) -{ - pushWord(value, _data + 6); -} + void KnxIpDeviceInformationDIB::projectInstallationIdentifier(uint16_t value) + { + pushWord(value, _data + 6); + } -const uint8_t* KnxIpDeviceInformationDIB::serialNumber() const -{ - return _data + 8; -} + const uint8_t* KnxIpDeviceInformationDIB::serialNumber() const + { + return _data + 8; + } -void KnxIpDeviceInformationDIB::serialNumber(const uint8_t* value) -{ - pushByteArray(value, LEN_SERIAL_NUMBER, _data + 8); -} + void KnxIpDeviceInformationDIB::serialNumber(const uint8_t* value) + { + pushByteArray(value, LEN_SERIAL_NUMBER, _data + 8); + } -uint32_t KnxIpDeviceInformationDIB::routingMulticastAddress() const -{ - return getInt(_data + 14); -} + uint32_t KnxIpDeviceInformationDIB::routingMulticastAddress() const + { + return getInt(_data + 14); + } -void KnxIpDeviceInformationDIB::routingMulticastAddress(uint32_t value) -{ - pushInt(value, _data + 14); -} + void KnxIpDeviceInformationDIB::routingMulticastAddress(uint32_t value) + { + pushInt(value, _data + 14); + } -const uint8_t* KnxIpDeviceInformationDIB::macAddress() const -{ - return _data + 18; -} + const uint8_t* KnxIpDeviceInformationDIB::macAddress() const + { + return _data + 18; + } -void KnxIpDeviceInformationDIB::macAddress(const uint8_t* value) -{ - pushByteArray(value, LEN_MAC_ADDRESS, _data + 18); -} + void KnxIpDeviceInformationDIB::macAddress(const uint8_t* value) + { + pushByteArray(value, LEN_MAC_ADDRESS, _data + 18); + } -const uint8_t* KnxIpDeviceInformationDIB::friendlyName() const -{ - return _data + 24; -} + const uint8_t* KnxIpDeviceInformationDIB::friendlyName() const + { + return _data + 24; + } -void KnxIpDeviceInformationDIB::friendlyName(const uint8_t* value) -{ - pushByteArray(value, LEN_FRIENDLY_NAME, _data + 24); -} + + void KnxIpDeviceInformationDIB::friendlyName(const uint8_t* value) + { + pushByteArray(value, LEN_FRIENDLY_NAME, _data + 24); + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_device_information_dib.h b/src/knx/ip/knx_ip_device_information_dib.h index 0ec5fd84..a4d7652e 100644 --- a/src/knx/ip/knx_ip_device_information_dib.h +++ b/src/knx/ip/knx_ip_device_information_dib.h @@ -6,24 +6,27 @@ #define LEN_MAC_ADDRESS 6 #define LEN_FRIENDLY_NAME 30 -class KnxIpDeviceInformationDIB : public KnxIpDIB +namespace Knx { - public: - KnxIpDeviceInformationDIB(uint8_t* data); - uint8_t medium() const; - void medium(uint8_t value); - uint8_t status() const; - void status(uint8_t value); - uint16_t individualAddress() const; - void individualAddress(uint16_t value); - uint16_t projectInstallationIdentifier() const; - void projectInstallationIdentifier(uint16_t value); - const uint8_t* serialNumber() const; - void serialNumber(const uint8_t* value); - uint32_t routingMulticastAddress() const; - void routingMulticastAddress(uint32_t value); - const uint8_t* macAddress() const; - void macAddress(const uint8_t* value); - const uint8_t* friendlyName() const; - void friendlyName(const uint8_t* value); -}; + class KnxIpDeviceInformationDIB : public KnxIpDIB + { + public: + KnxIpDeviceInformationDIB(uint8_t* data); + uint8_t medium() const; + void medium(uint8_t value); + uint8_t status() const; + void status(uint8_t value); + uint16_t individualAddress() const; + void individualAddress(uint16_t value); + uint16_t projectInstallationIdentifier() const; + void projectInstallationIdentifier(uint16_t value); + const uint8_t* serialNumber() const; + void serialNumber(const uint8_t* value); + uint32_t routingMulticastAddress() const; + void routingMulticastAddress(uint32_t value); + const uint8_t* macAddress() const; + void macAddress(const uint8_t* value); + const uint8_t* friendlyName() const; + void friendlyName(const uint8_t* value); + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_dib.cpp b/src/knx/ip/knx_ip_dib.cpp index e469e2b5..1860dd14 100644 --- a/src/knx/ip/knx_ip_dib.cpp +++ b/src/knx/ip/knx_ip_dib.cpp @@ -1,27 +1,30 @@ #include "knx_ip_dib.h" -KnxIpDIB::KnxIpDIB(uint8_t* data) : _data(data) -{} +namespace Knx +{ + KnxIpDIB::KnxIpDIB(uint8_t* data) : _data(data) + {} -KnxIpDIB::~KnxIpDIB() -{} + KnxIpDIB::~KnxIpDIB() + {} -uint8_t KnxIpDIB::length() const -{ - return *_data; -} + uint8_t KnxIpDIB::length() const + { + return *_data; + } -void KnxIpDIB::length(uint8_t value) -{ - *_data = value; -} + void KnxIpDIB::length(uint8_t value) + { + *_data = value; + } -DescriptionTypeCode KnxIpDIB::code() const -{ - return (DescriptionTypeCode)_data[1]; -} + DescriptionTypeCode KnxIpDIB::code() const + { + return (DescriptionTypeCode)_data[1]; + } -void KnxIpDIB::code(DescriptionTypeCode value) -{ - _data[1] = value; -} + void KnxIpDIB::code(DescriptionTypeCode value) + { + _data[1] = value; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_dib.h b/src/knx/ip/knx_ip_dib.h index ef520c28..e48c3b6c 100644 --- a/src/knx/ip/knx_ip_dib.h +++ b/src/knx/ip/knx_ip_dib.h @@ -2,29 +2,32 @@ #include -enum DescriptionTypeCode : uint8_t +namespace Knx { - DEVICE_INFO = 0x01, - SUPP_SVC_FAMILIES = 0x02, - IP_CONFIG = 0x03, - IP_CUR_CONFIG = 0x04, - KNX_ADDRESSES = 0x05, - MANUFACTURER_DATA = 0x06, - TUNNELING_INFO = 0x07, - EXTENDED_DEVICE_INFO = 0x08, - MFR_DATA = 0xFE -}; + enum DescriptionTypeCode : uint8_t + { + DEVICE_INFO = 0x01, + SUPP_SVC_FAMILIES = 0x02, + IP_CONFIG = 0x03, + IP_CUR_CONFIG = 0x04, + KNX_ADDRESSES = 0x05, + MANUFACTURER_DATA = 0x06, + TUNNELING_INFO = 0x07, + EXTENDED_DEVICE_INFO = 0x08, + MFR_DATA = 0xFE + }; -class KnxIpDIB -{ - public: - KnxIpDIB(uint8_t* data); - virtual ~KnxIpDIB(); - DescriptionTypeCode code() const; - void code(DescriptionTypeCode value); - uint8_t length() const; - void length(uint8_t value); + class KnxIpDIB + { + public: + KnxIpDIB(uint8_t* data); + virtual ~KnxIpDIB(); + DescriptionTypeCode code() const; + void code(DescriptionTypeCode value); + uint8_t length() const; + void length(uint8_t value); - protected: - uint8_t* _data = 0; -}; + protected: + uint8_t* _data = 0; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_disconnect_request.cpp b/src/knx/ip/knx_ip_disconnect_request.cpp index c9908303..0d31931d 100644 --- a/src/knx/ip/knx_ip_disconnect_request.cpp +++ b/src/knx/ip/knx_ip_disconnect_request.cpp @@ -1,25 +1,28 @@ #include "knx_ip_disconnect_request.h" -KnxIpDisconnectRequest::KnxIpDisconnectRequest(uint8_t* data, uint16_t length) - : KnxIpFrame(data, length), _hpaiCtrl(data + LEN_KNXIP_HEADER + 1 /*ChannelId*/ + 1 /*Reserved*/) +namespace Knx { -} + KnxIpDisconnectRequest::KnxIpDisconnectRequest(uint8_t* data, uint16_t length) + : KnxIpFrame(data, length), _hpaiCtrl(data + LEN_KNXIP_HEADER + 1 /*ChannelId*/ + 1 /*Reserved*/) + { + } -KnxIpDisconnectRequest::KnxIpDisconnectRequest() - : KnxIpFrame(1 /*ChannelId*/ + 1 /*Reserved*/ + LEN_KNXIP_HEADER + LEN_IPHPAI), _hpaiCtrl(_data + 1 /*ChannelId*/ + 1 /*Reserved*/ + LEN_KNXIP_HEADER) -{ - serviceTypeIdentifier(DisconnectRequest); -} + KnxIpDisconnectRequest::KnxIpDisconnectRequest() + : KnxIpFrame(1 /*ChannelId*/ + 1 /*Reserved*/ + LEN_KNXIP_HEADER + LEN_IPHPAI), _hpaiCtrl(_data + 1 /*ChannelId*/ + 1 /*Reserved*/ + LEN_KNXIP_HEADER) + { + serviceTypeIdentifier(DisconnectRequest); + } -IpHostProtocolAddressInformation& KnxIpDisconnectRequest::hpaiCtrl() -{ - return _hpaiCtrl; -} -uint8_t KnxIpDisconnectRequest::channelId() -{ - return _data[LEN_KNXIP_HEADER]; -} -void KnxIpDisconnectRequest::channelId(uint8_t channelId) -{ - _data[LEN_KNXIP_HEADER] = channelId; -} + IpHostProtocolAddressInformation& KnxIpDisconnectRequest::hpaiCtrl() + { + return _hpaiCtrl; + } + uint8_t KnxIpDisconnectRequest::channelId() + { + return _data[LEN_KNXIP_HEADER]; + } + void KnxIpDisconnectRequest::channelId(uint8_t channelId) + { + _data[LEN_KNXIP_HEADER] = channelId; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_disconnect_request.h b/src/knx/ip/knx_ip_disconnect_request.h index f351fd44..60a11ed5 100644 --- a/src/knx/ip/knx_ip_disconnect_request.h +++ b/src/knx/ip/knx_ip_disconnect_request.h @@ -3,14 +3,17 @@ #include "knx_ip_frame.h" #include "ip_host_protocol_address_information.h" -class KnxIpDisconnectRequest : public KnxIpFrame +namespace Knx { - public: - KnxIpDisconnectRequest(uint8_t* data, uint16_t length); - KnxIpDisconnectRequest(); - IpHostProtocolAddressInformation& hpaiCtrl(); - uint8_t channelId(); - void channelId(uint8_t channelId); - private: - IpHostProtocolAddressInformation _hpaiCtrl; -}; + class KnxIpDisconnectRequest : public KnxIpFrame + { + public: + KnxIpDisconnectRequest(uint8_t* data, uint16_t length); + KnxIpDisconnectRequest(); + IpHostProtocolAddressInformation& hpaiCtrl(); + uint8_t channelId(); + void channelId(uint8_t channelId); + private: + IpHostProtocolAddressInformation _hpaiCtrl; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_disconnect_response.cpp b/src/knx/ip/knx_ip_disconnect_response.cpp index 6121c7d3..f762eff4 100644 --- a/src/knx/ip/knx_ip_disconnect_response.cpp +++ b/src/knx/ip/knx_ip_disconnect_response.cpp @@ -1,10 +1,13 @@ #include "knx_ip_disconnect_response.h" -KnxIpDisconnectResponse::KnxIpDisconnectResponse(uint8_t channel, uint8_t status) - : KnxIpFrame(LEN_KNXIP_HEADER + 1 /*Channel*/ + 1 /*Status*/) +namespace Knx { - serviceTypeIdentifier(DisconnectResponse); + KnxIpDisconnectResponse::KnxIpDisconnectResponse(uint8_t channel, uint8_t status) + : KnxIpFrame(LEN_KNXIP_HEADER + 1 /*Channel*/ + 1 /*Status*/) + { + serviceTypeIdentifier(DisconnectResponse); - _data[LEN_KNXIP_HEADER] = channel; - _data[LEN_KNXIP_HEADER + 1] = status; -} + _data[LEN_KNXIP_HEADER] = channel; + _data[LEN_KNXIP_HEADER + 1] = status; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_disconnect_response.h b/src/knx/ip/knx_ip_disconnect_response.h index 75030763..e0b1fd2f 100644 --- a/src/knx/ip/knx_ip_disconnect_response.h +++ b/src/knx/ip/knx_ip_disconnect_response.h @@ -2,9 +2,12 @@ #include "knx_ip_frame.h" -class KnxIpDisconnectResponse : public KnxIpFrame +namespace Knx { - public: - KnxIpDisconnectResponse(uint8_t channel, uint8_t status); - private: -}; + class KnxIpDisconnectResponse : public KnxIpFrame + { + public: + KnxIpDisconnectResponse(uint8_t channel, uint8_t status); + private: + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_extended_device_information_dib.cpp b/src/knx/ip/knx_ip_extended_device_information_dib.cpp index 40de5a78..ddc6e204 100644 --- a/src/knx/ip/knx_ip_extended_device_information_dib.cpp +++ b/src/knx/ip/knx_ip_extended_device_information_dib.cpp @@ -1,40 +1,43 @@ #include "knx_ip_extended_device_information_dib.h" #include "../bits.h" -KnxIpExtendedDeviceInformationDIB::KnxIpExtendedDeviceInformationDIB(uint8_t* data) : KnxIpDIB(data) -{} - -uint8_t KnxIpExtendedDeviceInformationDIB::status() const +namespace Knx { - return _data[2]; -} + KnxIpExtendedDeviceInformationDIB::KnxIpExtendedDeviceInformationDIB(uint8_t* data) : KnxIpDIB(data) + {} + uint8_t KnxIpExtendedDeviceInformationDIB::status() const + { + return _data[2]; + } -void KnxIpExtendedDeviceInformationDIB::status(uint8_t value) -{ - _data[2] = value; -} + void KnxIpExtendedDeviceInformationDIB::status(uint8_t value) + { + _data[2] = value; + } -uint16_t KnxIpExtendedDeviceInformationDIB::localMaxApdu() const -{ - return getWord(_data + 4); -} + uint16_t KnxIpExtendedDeviceInformationDIB::localMaxApdu() const + { + return getWord(_data + 4); + } -void KnxIpExtendedDeviceInformationDIB::localMaxApdu(uint16_t value) -{ - pushWord(value, _data + 4); -} + void KnxIpExtendedDeviceInformationDIB::localMaxApdu(uint16_t value) + { + pushWord(value, _data + 4); + } -uint16_t KnxIpExtendedDeviceInformationDIB::deviceDescriptor() const -{ - return getWord(_data + 6); -} + uint16_t KnxIpExtendedDeviceInformationDIB::deviceDescriptor() const + { + return getWord(_data + 6); + } -void KnxIpExtendedDeviceInformationDIB::deviceDescriptor(uint16_t value) -{ - pushWord(value, _data + 6); -} + + void KnxIpExtendedDeviceInformationDIB::deviceDescriptor(uint16_t value) + { + pushWord(value, _data + 6); + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_extended_device_information_dib.h b/src/knx/ip/knx_ip_extended_device_information_dib.h index abbebae4..3d9efc06 100644 --- a/src/knx/ip/knx_ip_extended_device_information_dib.h +++ b/src/knx/ip/knx_ip_extended_device_information_dib.h @@ -3,14 +3,17 @@ #define LEN_EXTENDED_DEVICE_INFORMATION_DIB 8 -class KnxIpExtendedDeviceInformationDIB : public KnxIpDIB +namespace Knx { - public: - KnxIpExtendedDeviceInformationDIB(uint8_t* data); - uint8_t status() const; - void status(uint8_t value); - uint16_t localMaxApdu() const; - void localMaxApdu(uint16_t value); - uint16_t deviceDescriptor() const; - void deviceDescriptor(uint16_t value); -}; + class KnxIpExtendedDeviceInformationDIB : public KnxIpDIB + { + public: + KnxIpExtendedDeviceInformationDIB(uint8_t* data); + uint8_t status() const; + void status(uint8_t value); + uint16_t localMaxApdu() const; + void localMaxApdu(uint16_t value); + uint16_t deviceDescriptor() const; + void deviceDescriptor(uint16_t value); + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_frame.cpp b/src/knx/ip/knx_ip_frame.cpp index 83bc8cb1..4a68b04f 100644 --- a/src/knx/ip/knx_ip_frame.cpp +++ b/src/knx/ip/knx_ip_frame.cpp @@ -6,147 +6,150 @@ #define KNXIP_HEADER_LEN 0x6 #define KNXIP_PROTOCOL_VERSION 0x10 -KnxIpFrame::KnxIpFrame(uint8_t* data, - uint16_t length) +namespace Knx { - _data = data; - _dataLength = length; -} + KnxIpFrame::KnxIpFrame(uint8_t* data, + uint16_t length) + { + _data = data; + _dataLength = length; + } -uint8_t KnxIpFrame::headerLength() const -{ - return _data[0]; -} + uint8_t KnxIpFrame::headerLength() const + { + return _data[0]; + } -void KnxIpFrame::headerLength(uint8_t length) -{ - _data[0] = length; -} + void KnxIpFrame::headerLength(uint8_t length) + { + _data[0] = length; + } -KnxIpVersion KnxIpFrame::protocolVersion() const -{ - return (KnxIpVersion)_data[1]; -} + KnxIpVersion KnxIpFrame::protocolVersion() const + { + return (KnxIpVersion)_data[1]; + } -void KnxIpFrame::protocolVersion(KnxIpVersion version) -{ - _data[1] = (uint8_t)version; -} + void KnxIpFrame::protocolVersion(KnxIpVersion version) + { + _data[1] = (uint8_t)version; + } -KnxIpServiceType KnxIpFrame::serviceTypeIdentifier() const -{ - return (KnxIpServiceType)getWord(_data + 2); -} + KnxIpServiceType KnxIpFrame::serviceTypeIdentifier() const + { + return (KnxIpServiceType)getWord(_data + 2); + } -void KnxIpFrame::serviceTypeIdentifier(KnxIpServiceType identifier) -{ - pushWord((uint16_t) identifier, _data + 2); -} + void KnxIpFrame::serviceTypeIdentifier(KnxIpServiceType identifier) + { + pushWord((uint16_t) identifier, _data + 2); + } -uint16_t KnxIpFrame::totalLength() const -{ - return getWord(_data + 4); -} + uint16_t KnxIpFrame::totalLength() const + { + return getWord(_data + 4); + } -void KnxIpFrame::totalLength(uint16_t length) -{ - pushWord(length, _data + 4); -} + void KnxIpFrame::totalLength(uint16_t length) + { + pushWord(length, _data + 4); + } -uint8_t* KnxIpFrame::data() -{ - return _data; -} + uint8_t* KnxIpFrame::data() + { + return _data; + } -KnxIpFrame::~KnxIpFrame() -{ - if (_freeData) - delete[] _data; -} + KnxIpFrame::~KnxIpFrame() + { + if (_freeData) + delete[] _data; + } -KnxIpFrame::KnxIpFrame(uint16_t length) -{ - _data = new uint8_t[length]; - _dataLength = length; - _freeData = true; - memset(_data, 0, length); - headerLength(LEN_KNXIP_HEADER); - protocolVersion(KnxIp1_0); - totalLength(length); -} -#ifndef KNX_NO_PRINT -const char* enum_name(const KnxIpVersion enum_val) -{ - switch (enum_val) + KnxIpFrame::KnxIpFrame(uint16_t length) { - case KnxIp1_0: - return "KnxIp1_0"; + _data = new uint8_t[length]; + _dataLength = length; + _freeData = true; + memset(_data, 0, length); + headerLength(LEN_KNXIP_HEADER); + protocolVersion(KnxIp1_0); + totalLength(length); } +#ifndef KNX_NO_PRINT + const char* enum_name(const KnxIpVersion enum_val) + { + switch (enum_val) + { + case KnxIp1_0: + return "KnxIp1_0"; + } - return ""; -} + return ""; + } -const char* enum_name(const KnxIpServiceType enum_val) -{ - switch (enum_val) + const char* enum_name(const KnxIpServiceType enum_val) { - case SearchRequest: - return "SearchRequest"; + switch (enum_val) + { + case SearchRequest: + return "SearchRequest"; - case SearchResponse: - return "SearchResponse"; + case SearchResponse: + return "SearchResponse"; - case DescriptionRequest: - return "DescriptionRequest"; + case DescriptionRequest: + return "DescriptionRequest"; - case DescriptionResponse: - return "DescriptionResponse"; + case DescriptionResponse: + return "DescriptionResponse"; - case ConnectRequest: - return "ConnectRequest"; + case ConnectRequest: + return "ConnectRequest"; - case ConnectResponse: - return "ConnectResponse"; + case ConnectResponse: + return "ConnectResponse"; - case ConnectionStateRequest: - return "ConnectionStateRequest"; + case ConnectionStateRequest: + return "ConnectionStateRequest"; - case ConnectionStateResponse: - return "ConnectionStateResponse"; + case ConnectionStateResponse: + return "ConnectionStateResponse"; - case DisconnectRequest: - return "DisconnectRequest"; + case DisconnectRequest: + return "DisconnectRequest"; - case DisconnectResponse: - return "DisconnectResponse"; + case DisconnectResponse: + return "DisconnectResponse"; - case SearchRequestExt: - return "SearchRequestExt"; + case SearchRequestExt: + return "SearchRequestExt"; - case SearchResponseExt: - return "SearchResponseExt"; + case SearchResponseExt: + return "SearchResponseExt"; - case DeviceConfigurationRequest: - return "DeviceConfigurationRequest"; + case DeviceConfigurationRequest: + return "DeviceConfigurationRequest"; - case DeviceConfigurationAck: - return "DeviceConfigurationAck"; + case DeviceConfigurationAck: + return "DeviceConfigurationAck"; - case TunnelingRequest: - return "TunnelingRequest"; + case TunnelingRequest: + return "TunnelingRequest"; - case TunnelingAck: - return "TunnelingAck"; + case TunnelingAck: + return "TunnelingAck"; - case RoutingIndication: - return "RoutingIndication"; + case RoutingIndication: + return "RoutingIndication"; - case RoutingLostMessage: - return "RoutingLostMessage"; - } + case RoutingLostMessage: + return "RoutingLostMessage"; + } - return ""; -} -#endif \ No newline at end of file + return ""; + } +#endif +} \ 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 e351c214..dd35737e 100644 --- a/src/knx/ip/knx_ip_frame.h +++ b/src/knx/ip/knx_ip_frame.h @@ -4,52 +4,55 @@ #define LEN_KNXIP_HEADER 0x6 -enum KnxIpVersion +namespace Knx { - KnxIp1_0 = 0x10 -}; -const char* enum_name(const KnxIpVersion enum_val); + enum KnxIpVersion + { + KnxIp1_0 = 0x10 + }; + const char* enum_name(const KnxIpVersion enum_val); -enum KnxIpServiceType -{ - SearchRequest = 0x201, - SearchResponse = 0x202, - DescriptionRequest = 0x203, - DescriptionResponse = 0x204, - ConnectRequest = 0x205, - ConnectResponse = 0x206, - ConnectionStateRequest = 0x207, - ConnectionStateResponse = 0x208, - DisconnectRequest = 0x209, - DisconnectResponse = 0x20A, - SearchRequestExt = 0x20B, - SearchResponseExt = 0x20C, - DeviceConfigurationRequest = 0x310, - DeviceConfigurationAck = 0x311, - TunnelingRequest = 0x420, - TunnelingAck = 0x421, - RoutingIndication = 0x530, - RoutingLostMessage = 0x531, -}; -const char* enum_name(const KnxIpServiceType enum_val); + enum KnxIpServiceType + { + SearchRequest = 0x201, + SearchResponse = 0x202, + DescriptionRequest = 0x203, + DescriptionResponse = 0x204, + ConnectRequest = 0x205, + ConnectResponse = 0x206, + ConnectionStateRequest = 0x207, + ConnectionStateResponse = 0x208, + DisconnectRequest = 0x209, + DisconnectResponse = 0x20A, + SearchRequestExt = 0x20B, + SearchResponseExt = 0x20C, + DeviceConfigurationRequest = 0x310, + DeviceConfigurationAck = 0x311, + TunnelingRequest = 0x420, + TunnelingAck = 0x421, + RoutingIndication = 0x530, + RoutingLostMessage = 0x531, + }; + const char* enum_name(const KnxIpServiceType enum_val); -class KnxIpFrame -{ - public: - KnxIpFrame(uint8_t* data, uint16_t length); - KnxIpFrame(uint16_t totalLength); - virtual ~KnxIpFrame(); - uint8_t headerLength() const; - void headerLength(uint8_t length); - KnxIpVersion protocolVersion() const; - void protocolVersion(KnxIpVersion version); - KnxIpServiceType serviceTypeIdentifier() const; - void serviceTypeIdentifier(KnxIpServiceType identifier); - uint16_t totalLength() const; - void totalLength(uint16_t length); - uint8_t* data(); - protected: - bool _freeData = false; - uint8_t* _data = 0; - uint16_t _dataLength; -}; + class KnxIpFrame + { + public: + KnxIpFrame(uint8_t* data, uint16_t length); + KnxIpFrame(uint16_t totalLength); + virtual ~KnxIpFrame(); + uint8_t headerLength() const; + void headerLength(uint8_t length); + KnxIpVersion protocolVersion() const; + void protocolVersion(KnxIpVersion version); + KnxIpServiceType serviceTypeIdentifier() const; + void serviceTypeIdentifier(KnxIpServiceType identifier); + uint16_t totalLength() const; + void totalLength(uint16_t length); + uint8_t* data(); + protected: + bool _freeData = false; + uint8_t* _data = 0; + uint16_t _dataLength; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_knx_addresses_dib.cpp b/src/knx/ip/knx_ip_knx_addresses_dib.cpp index c5239a30..cd43e03b 100644 --- a/src/knx/ip/knx_ip_knx_addresses_dib.cpp +++ b/src/knx/ip/knx_ip_knx_addresses_dib.cpp @@ -1,26 +1,29 @@ #include "knx_ip_knx_addresses_dib.h" #include "../bits.h" -KnxIpKnxAddressesDIB::KnxIpKnxAddressesDIB(uint8_t* data) : KnxIpDIB(data) +namespace Knx { - currentPos = data + 4; -} + KnxIpKnxAddressesDIB::KnxIpKnxAddressesDIB(uint8_t* data) : KnxIpDIB(data) + { + currentPos = data + 4; + } -uint16_t KnxIpKnxAddressesDIB::individualAddress() -{ - uint16_t addr = 0; - popWord(addr, _data + 2); - return addr; -} + uint16_t KnxIpKnxAddressesDIB::individualAddress() + { + uint16_t addr = 0; + popWord(addr, _data + 2); + return addr; + } -void KnxIpKnxAddressesDIB::individualAddress(uint16_t addr) -{ - pushInt(addr, _data + 2); -} + void KnxIpKnxAddressesDIB::individualAddress(uint16_t addr) + { + pushInt(addr, _data + 2); + } -void KnxIpKnxAddressesDIB::additional(uint16_t addr) -{ - pushWord(addr, currentPos); - currentPos += 2; - length(currentPos - _data); -} + void KnxIpKnxAddressesDIB::additional(uint16_t addr) + { + pushWord(addr, currentPos); + currentPos += 2; + length(currentPos - _data); + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_knx_addresses_dib.h b/src/knx/ip/knx_ip_knx_addresses_dib.h index e8ce38d5..ceec06b5 100644 --- a/src/knx/ip/knx_ip_knx_addresses_dib.h +++ b/src/knx/ip/knx_ip_knx_addresses_dib.h @@ -1,13 +1,16 @@ #pragma once #include "knx_ip_dib.h" -class KnxIpKnxAddressesDIB : public KnxIpDIB +namespace Knx { - public: - KnxIpKnxAddressesDIB(uint8_t* data); - uint16_t individualAddress(); - void individualAddress(uint16_t addr); - void additional(uint16_t addr); - private: - uint8_t* currentPos = 0; -}; + class KnxIpKnxAddressesDIB : public KnxIpDIB + { + public: + KnxIpKnxAddressesDIB(uint8_t* data); + uint16_t individualAddress(); + void individualAddress(uint16_t addr); + void additional(uint16_t addr); + private: + uint8_t* currentPos = 0; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_routing_indication.cpp b/src/knx/ip/knx_ip_routing_indication.cpp index f9d2776c..ab6e148e 100644 --- a/src/knx/ip/knx_ip_routing_indication.cpp +++ b/src/knx/ip/knx_ip_routing_indication.cpp @@ -1,20 +1,23 @@ #include "knx_ip_routing_indication.h" #include -CemiFrame& KnxIpRoutingIndication::frame() +namespace Knx { - return _frame; -} + CemiFrame& KnxIpRoutingIndication::frame() + { + return _frame; + } -KnxIpRoutingIndication::KnxIpRoutingIndication(uint8_t* data, - uint16_t length) : KnxIpFrame(data, length), _frame(data + headerLength(), length - headerLength()) -{ -} + KnxIpRoutingIndication::KnxIpRoutingIndication(uint8_t* data, + uint16_t length) : KnxIpFrame(data, length), _frame(data + headerLength(), length - headerLength()) + { + } -KnxIpRoutingIndication::KnxIpRoutingIndication(CemiFrame frame) - : KnxIpFrame(frame.totalLenght() + LEN_KNXIP_HEADER), _frame(_data + headerLength(), frame.totalLenght()) -{ - serviceTypeIdentifier(RoutingIndication); - memcpy(_data + LEN_KNXIP_HEADER, frame.data(), frame.totalLenght()); -} + KnxIpRoutingIndication::KnxIpRoutingIndication(CemiFrame frame) + : KnxIpFrame(frame.totalLenght() + LEN_KNXIP_HEADER), _frame(_data + headerLength(), frame.totalLenght()) + { + serviceTypeIdentifier(RoutingIndication); + memcpy(_data + LEN_KNXIP_HEADER, frame.data(), frame.totalLenght()); + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_routing_indication.h b/src/knx/ip/knx_ip_routing_indication.h index e9324231..cfb9b047 100644 --- a/src/knx/ip/knx_ip_routing_indication.h +++ b/src/knx/ip/knx_ip_routing_indication.h @@ -3,12 +3,15 @@ #include "knx_ip_frame.h" #include "../datalink_layer/cemi_frame.h" -class KnxIpRoutingIndication : public KnxIpFrame +namespace Knx { - public: - KnxIpRoutingIndication(uint8_t* data, uint16_t length); - KnxIpRoutingIndication(CemiFrame frame); - CemiFrame& frame(); - private: - CemiFrame _frame; -}; \ No newline at end of file + class KnxIpRoutingIndication : public KnxIpFrame + { + public: + KnxIpRoutingIndication(uint8_t* data, uint16_t length); + KnxIpRoutingIndication(CemiFrame frame); + CemiFrame& frame(); + private: + CemiFrame _frame; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_search_request.cpp b/src/knx/ip/knx_ip_search_request.cpp index 7478c92f..31827e4f 100644 --- a/src/knx/ip/knx_ip_search_request.cpp +++ b/src/knx/ip/knx_ip_search_request.cpp @@ -1,12 +1,15 @@ #include "knx_ip_search_request.h" -KnxIpSearchRequest::KnxIpSearchRequest(uint8_t* data, uint16_t length) - : KnxIpFrame(data, length), _hpai(data + LEN_KNXIP_HEADER) +namespace Knx { -} + KnxIpSearchRequest::KnxIpSearchRequest(uint8_t* data, uint16_t length) + : KnxIpFrame(data, length), _hpai(data + LEN_KNXIP_HEADER) + { + } -IpHostProtocolAddressInformation& KnxIpSearchRequest::hpai() -{ - return _hpai; -} + IpHostProtocolAddressInformation& KnxIpSearchRequest::hpai() + { + return _hpai; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_search_request.h b/src/knx/ip/knx_ip_search_request.h index c5d867ba..542b49a8 100644 --- a/src/knx/ip/knx_ip_search_request.h +++ b/src/knx/ip/knx_ip_search_request.h @@ -3,11 +3,14 @@ #include "knx_ip_frame.h" #include "ip_host_protocol_address_information.h" -class KnxIpSearchRequest : public KnxIpFrame +namespace Knx { - public: - KnxIpSearchRequest(uint8_t* data, uint16_t length); - IpHostProtocolAddressInformation& hpai(); - private: - IpHostProtocolAddressInformation _hpai; -}; + class KnxIpSearchRequest : public KnxIpFrame + { + public: + KnxIpSearchRequest(uint8_t* data, uint16_t length); + IpHostProtocolAddressInformation& hpai(); + private: + IpHostProtocolAddressInformation _hpai; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_search_request_extended.cpp b/src/knx/ip/knx_ip_search_request_extended.cpp index 7c7e80b0..a57c1d28 100644 --- a/src/knx/ip/knx_ip_search_request_extended.cpp +++ b/src/knx/ip/knx_ip_search_request_extended.cpp @@ -2,65 +2,68 @@ #include "../bits.h" #include "service_families.h" -KnxIpSearchRequestExtended::KnxIpSearchRequestExtended(uint8_t* data, uint16_t length) - : KnxIpFrame(data, length), _hpai(data + LEN_KNXIP_HEADER) +namespace Knx { - if (length == LEN_KNXIP_HEADER + LEN_IPHPAI) - return; //we dont have SRPs + KnxIpSearchRequestExtended::KnxIpSearchRequestExtended(uint8_t* data, uint16_t length) + : KnxIpFrame(data, length), _hpai(data + LEN_KNXIP_HEADER) + { + if (length == LEN_KNXIP_HEADER + LEN_IPHPAI) + return; //we dont have SRPs - int currentPos = LEN_KNXIP_HEADER + LEN_IPHPAI; + int currentPos = LEN_KNXIP_HEADER + LEN_IPHPAI; - while (currentPos < length) - { - switch (data[currentPos + 1]) + while (currentPos < length) { - case 0x01: - srpByProgMode = true; - break; - - case 0x02: - srpByMacAddr = true; - srpMacAddr = data + currentPos + 2; - break; + switch (data[currentPos + 1]) + { + case 0x01: + srpByProgMode = true; + break; - case 0x03: - srpByService = true; - srpServiceFamilies = data + currentPos; - break; + case 0x02: + srpByMacAddr = true; + srpMacAddr = data + currentPos + 2; + break; - case 0x04: - srpRequestDIBs = true; + case 0x03: + srpByService = true; + srpServiceFamilies = data + currentPos; + break; - for (int i = 0; i < data[currentPos] - 2; i++) - { - if (data[currentPos + i + 2] == 0) - continue; + case 0x04: + srpRequestDIBs = true; - if (data[currentPos + i + 2] > REQUESTED_DIBS_MAX) + for (int i = 0; i < data[currentPos] - 2; i++) { - print("Requested DIBs too high "); - continue; - } + if (data[currentPos + i + 2] == 0) + continue; + + if (data[currentPos + i + 2] > REQUESTED_DIBS_MAX) + { + print("Requested DIBs too high "); + continue; + } - requestedDIBs[data[currentPos + i + 2]] = true; - } + requestedDIBs[data[currentPos + i + 2]] = true; + } - break; - } + break; + } - currentPos += data[currentPos]; - }; -} + currentPos += data[currentPos]; + }; + } -IpHostProtocolAddressInformation& KnxIpSearchRequestExtended::hpai() -{ - return _hpai; -} + IpHostProtocolAddressInformation& KnxIpSearchRequestExtended::hpai() + { + return _hpai; + } -bool KnxIpSearchRequestExtended::requestedDIB(uint8_t code) -{ - if (code > REQUESTED_DIBS_MAX) - return false; + bool KnxIpSearchRequestExtended::requestedDIB(uint8_t code) + { + if (code > REQUESTED_DIBS_MAX) + return false; - return requestedDIBs[code]; -} + return requestedDIBs[code]; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_search_request_extended.h b/src/knx/ip/knx_ip_search_request_extended.h index 36f7e755..234b5070 100644 --- a/src/knx/ip/knx_ip_search_request_extended.h +++ b/src/knx/ip/knx_ip_search_request_extended.h @@ -4,20 +4,23 @@ #include "knx_ip_frame.h" #include "ip_host_protocol_address_information.h" -#define REQUESTED_DIBS_MAX 9 -class KnxIpSearchRequestExtended : public KnxIpFrame +namespace Knx { - public: - KnxIpSearchRequestExtended(uint8_t* data, uint16_t length); - IpHostProtocolAddressInformation& hpai(); - bool requestedDIB(uint8_t code); - bool srpByProgMode = false; - bool srpByMacAddr = false; - bool srpByService = false; - bool srpRequestDIBs = false; - uint8_t* srpMacAddr = nullptr; - uint8_t* srpServiceFamilies = nullptr; - private: - IpHostProtocolAddressInformation _hpai; - bool requestedDIBs[REQUESTED_DIBS_MAX]; //for now only 1 to 8 -}; +#define REQUESTED_DIBS_MAX 9 + class KnxIpSearchRequestExtended : public KnxIpFrame + { + public: + KnxIpSearchRequestExtended(uint8_t* data, uint16_t length); + IpHostProtocolAddressInformation& hpai(); + bool requestedDIB(uint8_t code); + bool srpByProgMode = false; + bool srpByMacAddr = false; + bool srpByService = false; + bool srpRequestDIBs = false; + uint8_t* srpMacAddr = nullptr; + uint8_t* srpServiceFamilies = nullptr; + private: + IpHostProtocolAddressInformation _hpai; + bool requestedDIBs[REQUESTED_DIBS_MAX]; //for now only 1 to 8 + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_search_response.cpp b/src/knx/ip/knx_ip_search_response.cpp index 6d91460f..01f50275 100644 --- a/src/knx/ip/knx_ip_search_response.cpp +++ b/src/knx/ip/knx_ip_search_response.cpp @@ -15,68 +15,71 @@ #endif #endif -KnxIpSearchResponse::KnxIpSearchResponse(IpParameterObject& parameters, DeviceObject& deviceObject) - : KnxIpFrame(LEN_KNXIP_HEADER + LEN_IPHPAI + LEN_DEVICE_INFORMATION_DIB + LEN_SERVICE_DIB), - _controlEndpoint(_data + LEN_KNXIP_HEADER), _deviceInfo(_data + LEN_KNXIP_HEADER + LEN_IPHPAI), - _supportedServices(_data + LEN_KNXIP_HEADER + LEN_IPHPAI + LEN_DEVICE_INFORMATION_DIB) +namespace Knx { - serviceTypeIdentifier(SearchResponse); + KnxIpSearchResponse::KnxIpSearchResponse(IpParameterObject& parameters, DeviceObject& deviceObject) + : KnxIpFrame(LEN_KNXIP_HEADER + LEN_IPHPAI + LEN_DEVICE_INFORMATION_DIB + LEN_SERVICE_DIB), + _controlEndpoint(_data + LEN_KNXIP_HEADER), _deviceInfo(_data + LEN_KNXIP_HEADER + LEN_IPHPAI), + _supportedServices(_data + LEN_KNXIP_HEADER + LEN_IPHPAI + LEN_DEVICE_INFORMATION_DIB) + { + serviceTypeIdentifier(SearchResponse); - _controlEndpoint.length(LEN_IPHPAI); - _controlEndpoint.code(IPV4_UDP); - _controlEndpoint.ipAddress(parameters.propertyValue(PID_CURRENT_IP_ADDRESS)); - _controlEndpoint.ipPortNumber(KNXIP_MULTICAST_PORT); + _controlEndpoint.length(LEN_IPHPAI); + _controlEndpoint.code(IPV4_UDP); + _controlEndpoint.ipAddress(parameters.propertyValue(PID_CURRENT_IP_ADDRESS)); + _controlEndpoint.ipPortNumber(KNXIP_MULTICAST_PORT); - _deviceInfo.length(LEN_DEVICE_INFORMATION_DIB); - _deviceInfo.code(DEVICE_INFO); + _deviceInfo.length(LEN_DEVICE_INFORMATION_DIB); + _deviceInfo.code(DEVICE_INFO); #if MASK_VERSION == 0x57B0 - _deviceInfo.medium(0x20); //MediumType is IP (for IP-Only Devices) + _deviceInfo.medium(0x20); //MediumType is IP (for IP-Only Devices) #else - _deviceInfo.medium(0x02); //MediumType is TP + _deviceInfo.medium(0x02); //MediumType is TP #endif - _deviceInfo.status(deviceObject.progMode()); - _deviceInfo.individualAddress(parameters.propertyValue(PID_KNX_INDIVIDUAL_ADDRESS)); - _deviceInfo.projectInstallationIdentifier(parameters.propertyValue(PID_PROJECT_INSTALLATION_ID)); - _deviceInfo.serialNumber(deviceObject.propertyData(PID_SERIAL_NUMBER)); - _deviceInfo.routingMulticastAddress(parameters.propertyValue(PID_ROUTING_MULTICAST_ADDRESS)); - //_deviceInfo.routingMulticastAddress(0); + _deviceInfo.status(deviceObject.progMode()); + _deviceInfo.individualAddress(parameters.propertyValue(PID_KNX_INDIVIDUAL_ADDRESS)); + _deviceInfo.projectInstallationIdentifier(parameters.propertyValue(PID_PROJECT_INSTALLATION_ID)); + _deviceInfo.serialNumber(deviceObject.propertyData(PID_SERIAL_NUMBER)); + _deviceInfo.routingMulticastAddress(parameters.propertyValue(PID_ROUTING_MULTICAST_ADDRESS)); + //_deviceInfo.routingMulticastAddress(0); - uint8_t mac_address[LEN_MAC_ADDRESS] = {0}; - Property* prop = parameters.property(PID_MAC_ADDRESS); - prop->read(mac_address); - _deviceInfo.macAddress(mac_address); + uint8_t mac_address[LEN_MAC_ADDRESS] = {0}; + Property* prop = parameters.property(PID_MAC_ADDRESS); + prop->read(mac_address); + _deviceInfo.macAddress(mac_address); - uint8_t friendlyName[LEN_FRIENDLY_NAME] = {0}; - prop = parameters.property(PID_FRIENDLY_NAME); - prop->read(1, LEN_FRIENDLY_NAME, friendlyName); - _deviceInfo.friendlyName(friendlyName); + uint8_t friendlyName[LEN_FRIENDLY_NAME] = {0}; + prop = parameters.property(PID_FRIENDLY_NAME); + prop->read(1, LEN_FRIENDLY_NAME, friendlyName); + _deviceInfo.friendlyName(friendlyName); - _supportedServices.length(LEN_SERVICE_DIB); - _supportedServices.code(SUPP_SVC_FAMILIES); - _supportedServices.serviceVersion(Core, KNX_SERVICE_FAMILY_CORE); - _supportedServices.serviceVersion(DeviceManagement, KNX_SERVICE_FAMILY_DEVICE_MANAGEMENT); + _supportedServices.length(LEN_SERVICE_DIB); + _supportedServices.code(SUPP_SVC_FAMILIES); + _supportedServices.serviceVersion(Core, KNX_SERVICE_FAMILY_CORE); + _supportedServices.serviceVersion(DeviceManagement, KNX_SERVICE_FAMILY_DEVICE_MANAGEMENT); #ifdef KNX_TUNNELING - _supportedServices.serviceVersion(Tunnelling, KNX_SERVICE_FAMILY_TUNNELING); + _supportedServices.serviceVersion(Tunnelling, KNX_SERVICE_FAMILY_TUNNELING); #endif #if MASK_VERSION == 0x091A - _supportedServices.serviceVersion(Routing, KNX_SERVICE_FAMILY_ROUTING); + _supportedServices.serviceVersion(Routing, KNX_SERVICE_FAMILY_ROUTING); #endif -} + } -IpHostProtocolAddressInformation& KnxIpSearchResponse::controlEndpoint() -{ - return _controlEndpoint; -} + IpHostProtocolAddressInformation& KnxIpSearchResponse::controlEndpoint() + { + return _controlEndpoint; + } -KnxIpDeviceInformationDIB& KnxIpSearchResponse::deviceInfo() -{ - return _deviceInfo; -} + KnxIpDeviceInformationDIB& KnxIpSearchResponse::deviceInfo() + { + return _deviceInfo; + } -KnxIpSupportedServiceDIB& KnxIpSearchResponse::supportedServices() -{ - return _supportedServices; -} + KnxIpSupportedServiceDIB& KnxIpSearchResponse::supportedServices() + { + return _supportedServices; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_search_response.h b/src/knx/ip/knx_ip_search_response.h index 13814bb9..a89b5620 100644 --- a/src/knx/ip/knx_ip_search_response.h +++ b/src/knx/ip/knx_ip_search_response.h @@ -7,15 +7,18 @@ #include "ip_parameter_object.h" #include "service_families.h" -class KnxIpSearchResponse : public KnxIpFrame +namespace Knx { - public: - KnxIpSearchResponse(IpParameterObject& parameters, DeviceObject& deviceObj); - IpHostProtocolAddressInformation& controlEndpoint(); - KnxIpDeviceInformationDIB& deviceInfo(); - KnxIpSupportedServiceDIB& supportedServices(); - private: - IpHostProtocolAddressInformation _controlEndpoint; - KnxIpDeviceInformationDIB _deviceInfo; - KnxIpSupportedServiceDIB _supportedServices; -}; + class KnxIpSearchResponse : public KnxIpFrame + { + public: + KnxIpSearchResponse(IpParameterObject& parameters, DeviceObject& deviceObj); + IpHostProtocolAddressInformation& controlEndpoint(); + KnxIpDeviceInformationDIB& deviceInfo(); + KnxIpSupportedServiceDIB& supportedServices(); + private: + IpHostProtocolAddressInformation _controlEndpoint; + KnxIpDeviceInformationDIB _deviceInfo; + KnxIpSupportedServiceDIB _supportedServices; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_search_response_extended.cpp b/src/knx/ip/knx_ip_search_response_extended.cpp index 4a562126..52d9b0e1 100644 --- a/src/knx/ip/knx_ip_search_response_extended.cpp +++ b/src/knx/ip/knx_ip_search_response_extended.cpp @@ -18,211 +18,214 @@ #endif #endif -KnxIpSearchResponseExtended::KnxIpSearchResponseExtended(IpParameterObject& parameters, DeviceObject& deviceObject, int dibLength) - : KnxIpFrame(LEN_KNXIP_HEADER + LEN_IPHPAI + dibLength), - _controlEndpoint(_data + LEN_KNXIP_HEADER) +namespace Knx { - serviceTypeIdentifier(SearchResponseExt); + KnxIpSearchResponseExtended::KnxIpSearchResponseExtended(IpParameterObject& parameters, DeviceObject& deviceObject, int dibLength) + : KnxIpFrame(LEN_KNXIP_HEADER + LEN_IPHPAI + dibLength), + _controlEndpoint(_data + LEN_KNXIP_HEADER) + { + serviceTypeIdentifier(SearchResponseExt); - _controlEndpoint.length(LEN_IPHPAI); - _controlEndpoint.code(IPV4_UDP); - _controlEndpoint.ipAddress(parameters.propertyValue(PID_CURRENT_IP_ADDRESS)); - _controlEndpoint.ipPortNumber(KNXIP_MULTICAST_PORT); + _controlEndpoint.length(LEN_IPHPAI); + _controlEndpoint.code(IPV4_UDP); + _controlEndpoint.ipAddress(parameters.propertyValue(PID_CURRENT_IP_ADDRESS)); + _controlEndpoint.ipPortNumber(KNXIP_MULTICAST_PORT); - currentPos = LEN_KNXIP_HEADER + LEN_IPHPAI; -} + currentPos = LEN_KNXIP_HEADER + LEN_IPHPAI; + } -void KnxIpSearchResponseExtended::setDeviceInfo(IpParameterObject& parameters, DeviceObject& deviceObject) -{ - println("setDeviceInfo"); - KnxIpDeviceInformationDIB _deviceInfo(_data + currentPos); - _deviceInfo.length(LEN_DEVICE_INFORMATION_DIB); - _deviceInfo.code(DEVICE_INFO); + void KnxIpSearchResponseExtended::setDeviceInfo(IpParameterObject& parameters, DeviceObject& deviceObject) + { + println("setDeviceInfo"); + KnxIpDeviceInformationDIB _deviceInfo(_data + currentPos); + _deviceInfo.length(LEN_DEVICE_INFORMATION_DIB); + _deviceInfo.code(DEVICE_INFO); #if MASK_VERSION == 0x57B0 - _deviceInfo.medium(0x20); //MediumType is IP (for IP-Only Devices) + _deviceInfo.medium(0x20); //MediumType is IP (for IP-Only Devices) #else - _deviceInfo.medium(0x02); //MediumType is TP + _deviceInfo.medium(0x02); //MediumType is TP #endif - _deviceInfo.status(deviceObject.progMode()); - _deviceInfo.individualAddress(parameters.propertyValue(PID_KNX_INDIVIDUAL_ADDRESS)); - _deviceInfo.projectInstallationIdentifier(parameters.propertyValue(PID_PROJECT_INSTALLATION_ID)); - _deviceInfo.serialNumber(deviceObject.propertyData(PID_SERIAL_NUMBER)); - _deviceInfo.routingMulticastAddress(parameters.propertyValue(PID_ROUTING_MULTICAST_ADDRESS)); - //_deviceInfo.routingMulticastAddress(0); - - uint8_t mac_address[LEN_MAC_ADDRESS] = {0}; - Property* prop = parameters.property(PID_MAC_ADDRESS); - prop->read(mac_address); - _deviceInfo.macAddress(mac_address); - - uint8_t friendlyName[LEN_FRIENDLY_NAME] = {0}; - prop = parameters.property(PID_FRIENDLY_NAME); - prop->read(1, LEN_FRIENDLY_NAME, friendlyName); - _deviceInfo.friendlyName(friendlyName); - - currentPos += LEN_DEVICE_INFORMATION_DIB; -} - -void KnxIpSearchResponseExtended::setSupportedServices() -{ - println("setSupportedServices"); - KnxIpSupportedServiceDIB _supportedServices(_data + currentPos); - _supportedServices.length(LEN_SERVICE_DIB); - _supportedServices.code(SUPP_SVC_FAMILIES); - _supportedServices.serviceVersion(Core, KNX_SERVICE_FAMILY_CORE); - _supportedServices.serviceVersion(DeviceManagement, KNX_SERVICE_FAMILY_DEVICE_MANAGEMENT); + _deviceInfo.status(deviceObject.progMode()); + _deviceInfo.individualAddress(parameters.propertyValue(PID_KNX_INDIVIDUAL_ADDRESS)); + _deviceInfo.projectInstallationIdentifier(parameters.propertyValue(PID_PROJECT_INSTALLATION_ID)); + _deviceInfo.serialNumber(deviceObject.propertyData(PID_SERIAL_NUMBER)); + _deviceInfo.routingMulticastAddress(parameters.propertyValue(PID_ROUTING_MULTICAST_ADDRESS)); + //_deviceInfo.routingMulticastAddress(0); + + uint8_t mac_address[LEN_MAC_ADDRESS] = {0}; + Property* prop = parameters.property(PID_MAC_ADDRESS); + prop->read(mac_address); + _deviceInfo.macAddress(mac_address); + + uint8_t friendlyName[LEN_FRIENDLY_NAME] = {0}; + prop = parameters.property(PID_FRIENDLY_NAME); + prop->read(1, LEN_FRIENDLY_NAME, friendlyName); + _deviceInfo.friendlyName(friendlyName); + + currentPos += LEN_DEVICE_INFORMATION_DIB; + } + + void KnxIpSearchResponseExtended::setSupportedServices() + { + println("setSupportedServices"); + KnxIpSupportedServiceDIB _supportedServices(_data + currentPos); + _supportedServices.length(LEN_SERVICE_DIB); + _supportedServices.code(SUPP_SVC_FAMILIES); + _supportedServices.serviceVersion(Core, KNX_SERVICE_FAMILY_CORE); + _supportedServices.serviceVersion(DeviceManagement, KNX_SERVICE_FAMILY_DEVICE_MANAGEMENT); #ifdef KNX_TUNNELING - _supportedServices.serviceVersion(Tunnelling, KNX_SERVICE_FAMILY_TUNNELING); + _supportedServices.serviceVersion(Tunnelling, KNX_SERVICE_FAMILY_TUNNELING); #endif #if MASK_VERSION == 0x091A - _supportedServices.serviceVersion(Routing, KNX_SERVICE_FAMILY_ROUTING); + _supportedServices.serviceVersion(Routing, KNX_SERVICE_FAMILY_ROUTING); #endif - currentPos += LEN_SERVICE_DIB; -} - -void KnxIpSearchResponseExtended::setIpConfig(IpParameterObject& parameters) -{ - println("setIpConfig"); - KnxIpConfigDIB _ipConfig(_data + currentPos); - _ipConfig.length(LEN_IP_CONFIG_DIB); - _ipConfig.code(IP_CONFIG); - _ipConfig.address(parameters.propertyValue(PID_IP_ADDRESS)); - _ipConfig.subnet(parameters.propertyValue(PID_SUBNET_MASK)); - _ipConfig.gateway(parameters.propertyValue(PID_DEFAULT_GATEWAY)); - _ipConfig.info1(parameters.propertyValue(PID_IP_CAPABILITIES)); - _ipConfig.info2(parameters.propertyValue(PID_IP_ASSIGNMENT_METHOD)); - - currentPos += LEN_IP_CONFIG_DIB; -} - -void KnxIpSearchResponseExtended::setIpCurrentConfig(IpParameterObject& parameters) -{ - println("setIpCurrentConfig"); - KnxIpConfigDIB _ipCurConfig(_data + currentPos, true); - _ipCurConfig.length(LEN_IP_CURRENT_CONFIG_DIB); - _ipCurConfig.code(IP_CUR_CONFIG); - _ipCurConfig.address(parameters.propertyValue(PID_CURRENT_IP_ADDRESS)); - _ipCurConfig.subnet(parameters.propertyValue(PID_CURRENT_SUBNET_MASK)); - _ipCurConfig.gateway(parameters.propertyValue(PID_CURRENT_DEFAULT_GATEWAY)); - _ipCurConfig.dhcp(parameters.propertyValue(PID_DHCP_BOOTP_SERVER)); - _ipCurConfig.info1(parameters.propertyValue(PID_CURRENT_IP_ASSIGNMENT_METHOD)); - _ipCurConfig.info2(0x00); //Reserved - - currentPos += LEN_IP_CURRENT_CONFIG_DIB; -} - -void KnxIpSearchResponseExtended::setKnxAddresses(IpParameterObject& parameters, DeviceObject& deviceObject) -{ - println("setKnxAddresses"); - KnxIpKnxAddressesDIB _knxAddresses(_data + currentPos); - _knxAddresses.length(4); //minimum - _knxAddresses.code(KNX_ADDRESSES); - _knxAddresses.individualAddress(deviceObject.individualAddress()); - - uint16_t length = 0; - parameters.readPropertyLength(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, length); + currentPos += LEN_SERVICE_DIB; + } - const uint8_t* addresses = parameters.propertyData(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES); + void KnxIpSearchResponseExtended::setIpConfig(IpParameterObject& parameters) + { + println("setIpConfig"); + KnxIpConfigDIB _ipConfig(_data + currentPos); + _ipConfig.length(LEN_IP_CONFIG_DIB); + _ipConfig.code(IP_CONFIG); + _ipConfig.address(parameters.propertyValue(PID_IP_ADDRESS)); + _ipConfig.subnet(parameters.propertyValue(PID_SUBNET_MASK)); + _ipConfig.gateway(parameters.propertyValue(PID_DEFAULT_GATEWAY)); + _ipConfig.info1(parameters.propertyValue(PID_IP_CAPABILITIES)); + _ipConfig.info2(parameters.propertyValue(PID_IP_ASSIGNMENT_METHOD)); + + currentPos += LEN_IP_CONFIG_DIB; + } - for (int i = 0; i < length; i++) + void KnxIpSearchResponseExtended::setIpCurrentConfig(IpParameterObject& parameters) { - uint16_t additional = 0; - popWord(additional, addresses + i * 2); - _knxAddresses.additional(additional); + println("setIpCurrentConfig"); + KnxIpConfigDIB _ipCurConfig(_data + currentPos, true); + _ipCurConfig.length(LEN_IP_CURRENT_CONFIG_DIB); + _ipCurConfig.code(IP_CUR_CONFIG); + _ipCurConfig.address(parameters.propertyValue(PID_CURRENT_IP_ADDRESS)); + _ipCurConfig.subnet(parameters.propertyValue(PID_CURRENT_SUBNET_MASK)); + _ipCurConfig.gateway(parameters.propertyValue(PID_CURRENT_DEFAULT_GATEWAY)); + _ipCurConfig.dhcp(parameters.propertyValue(PID_DHCP_BOOTP_SERVER)); + _ipCurConfig.info1(parameters.propertyValue(PID_CURRENT_IP_ASSIGNMENT_METHOD)); + _ipCurConfig.info2(0x00); //Reserved + + currentPos += LEN_IP_CURRENT_CONFIG_DIB; } - currentPos += _knxAddresses.length(); -} -#ifdef KNX_TUNNELING -void KnxIpSearchResponseExtended::setTunnelingInfo(IpParameterObject& parameters, DeviceObject& deviceObject, KnxIpTunnelConnection tunnels[]) -{ - println("setTunnelingInfo"); - KnxIpTunnelingInfoDIB _tunnelInfo(_data + currentPos); - _tunnelInfo.length(4); //minlength - _tunnelInfo.code(TUNNELING_INFO); - _tunnelInfo.apduLength(254); //FIXME where to get from + void KnxIpSearchResponseExtended::setKnxAddresses(IpParameterObject& parameters, DeviceObject& deviceObject) + { + println("setKnxAddresses"); + KnxIpKnxAddressesDIB _knxAddresses(_data + currentPos); + _knxAddresses.length(4); //minimum + _knxAddresses.code(KNX_ADDRESSES); + _knxAddresses.individualAddress(deviceObject.individualAddress()); - uint16_t length = 0; - parameters.readPropertyLength(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, length); + uint16_t length = 0; + parameters.readPropertyLength(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, length); - const uint8_t* addresses; + const uint8_t* addresses = parameters.propertyData(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES); - if (length == KNX_TUNNELING) - { - addresses = parameters.propertyData(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES); + for (int i = 0; i < length; i++) + { + uint16_t additional = 0; + popWord(additional, addresses + i * 2); + _knxAddresses.additional(additional); + } + + currentPos += _knxAddresses.length(); } - else +#ifdef KNX_TUNNELING + void KnxIpSearchResponseExtended::setTunnelingInfo(IpParameterObject& parameters, DeviceObject& deviceObject, KnxIpTunnelConnection tunnels[]) { - uint8_t addrbuffer[KNX_TUNNELING * 2]; - addresses = (uint8_t*)addrbuffer; + println("setTunnelingInfo"); + KnxIpTunnelingInfoDIB _tunnelInfo(_data + currentPos); + _tunnelInfo.length(4); //minlength + _tunnelInfo.code(TUNNELING_INFO); + _tunnelInfo.apduLength(254); //FIXME where to get from + + uint16_t length = 0; + parameters.readPropertyLength(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, length); + + const uint8_t* addresses; - for (int i = 0; i < KNX_TUNNELING; i++) + if (length == KNX_TUNNELING) { - addrbuffer[i * 2 + 1] = i + 1; - addrbuffer[i * 2] = deviceObject.individualAddress() / 0x0100; + addresses = parameters.propertyData(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES); } - } - - for (int i = 0; i < length; i++) - { - uint16_t additional = 0; - popWord(additional, addresses + i * 2); - uint16_t flags = 0; + else + { + uint8_t addrbuffer[KNX_TUNNELING * 2]; + addresses = (uint8_t*)addrbuffer; - uint8_t doubleCounter = 0; - bool used = false; + for (int i = 0; i < KNX_TUNNELING; i++) + { + addrbuffer[i * 2 + 1] = i + 1; + addrbuffer[i * 2] = deviceObject.individualAddress() / 0x0100; + } + } - for (int i = 0; i < KNX_TUNNELING; i++) + for (int i = 0; i < length; i++) { - if (tunnels[i].IndividualAddress == additional) + uint16_t additional = 0; + popWord(additional, addresses + i * 2); + uint16_t flags = 0; + + uint8_t doubleCounter = 0; + bool used = false; + + for (int i = 0; i < KNX_TUNNELING; i++) { - doubleCounter += 1; + if (tunnels[i].IndividualAddress == additional) + { + doubleCounter += 1; - if (tunnels[i].ChannelId != 0) - used = true; + if (tunnels[i].ChannelId != 0) + used = true; + } } - } - if (doubleCounter > 1 && used) - flags |= 1 << 2; //Slot is not usable; double PA is already used + if (doubleCounter > 1 && used) + flags |= 1 << 2; //Slot is not usable; double PA is already used - if (used) - { - flags |= 1 << 2; //Slot is not usable; PA is already used - flags |= 1; //Slot is not free - } + if (used) + { + flags |= 1 << 2; //Slot is not usable; PA is already used + flags |= 1; //Slot is not free + } - flags = ~flags; + flags = ~flags; - _tunnelInfo.tunnelingSlot(additional, flags); - } + _tunnelInfo.tunnelingSlot(additional, flags); + } - currentPos += _tunnelInfo.length(); -} + currentPos += _tunnelInfo.length(); + } #endif -void KnxIpSearchResponseExtended::setExtendedDeviceInfo() -{ - println("setExtendedDeviceInfo"); - KnxIpExtendedDeviceInformationDIB _extended(_data + currentPos); - _extended.length(LEN_EXTENDED_DEVICE_INFORMATION_DIB); - _extended.code(EXTENDED_DEVICE_INFO); - _extended.status(0x01); //FIXME dont know encoding PID_MEDIUM_STATUS=51 RouterObject - _extended.localMaxApdu(254); //FIXME is this correct? + void KnxIpSearchResponseExtended::setExtendedDeviceInfo() + { + println("setExtendedDeviceInfo"); + KnxIpExtendedDeviceInformationDIB _extended(_data + currentPos); + _extended.length(LEN_EXTENDED_DEVICE_INFORMATION_DIB); + _extended.code(EXTENDED_DEVICE_INFO); + _extended.status(0x01); //FIXME dont know encoding PID_MEDIUM_STATUS=51 RouterObject + _extended.localMaxApdu(254); //FIXME is this correct? #ifdef MASK_VERSION - _extended.deviceDescriptor(MASK_VERSION); + _extended.deviceDescriptor(MASK_VERSION); #else - _extended.deviceDescriptor(0x57B0); + _extended.deviceDescriptor(0x57B0); #endif - currentPos += LEN_EXTENDED_DEVICE_INFORMATION_DIB; -} + currentPos += LEN_EXTENDED_DEVICE_INFORMATION_DIB; + } -IpHostProtocolAddressInformation& KnxIpSearchResponseExtended::controlEndpoint() -{ - return _controlEndpoint; -} + IpHostProtocolAddressInformation& KnxIpSearchResponseExtended::controlEndpoint() + { + return _controlEndpoint; + } -uint8_t* KnxIpSearchResponseExtended::DIBs() -{ - return _data + LEN_KNXIP_HEADER + LEN_IPHPAI; -} + uint8_t* KnxIpSearchResponseExtended::DIBs() + { + return _data + LEN_KNXIP_HEADER + LEN_IPHPAI; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_search_response_extended.h b/src/knx/ip/knx_ip_search_response_extended.h index 5cf9ee6a..5de67e2d 100644 --- a/src/knx/ip/knx_ip_search_response_extended.h +++ b/src/knx/ip/knx_ip_search_response_extended.h @@ -13,21 +13,24 @@ #include "ip_parameter_object.h" #include "knx_ip_tunnel_connection.h" -class KnxIpSearchResponseExtended : public KnxIpFrame +namespace Knx { - public: - KnxIpSearchResponseExtended(IpParameterObject& parameters, DeviceObject& deviceObj, int dibLength); - IpHostProtocolAddressInformation& controlEndpoint(); - void setDeviceInfo(IpParameterObject& parameters, DeviceObject& deviceObject); - void setSupportedServices(); - void setIpConfig(IpParameterObject& parameters); - void setIpCurrentConfig(IpParameterObject& parameters); - void setKnxAddresses(IpParameterObject& parameters, DeviceObject& deviceObject); - //setManuData - void setTunnelingInfo(IpParameterObject& parameters, DeviceObject& deviceObject, KnxIpTunnelConnection tunnels[]); - void setExtendedDeviceInfo(); - uint8_t* DIBs(); - private: - IpHostProtocolAddressInformation _controlEndpoint; - int currentPos = 0; -}; + class KnxIpSearchResponseExtended : public KnxIpFrame + { + public: + KnxIpSearchResponseExtended(IpParameterObject& parameters, DeviceObject& deviceObj, int dibLength); + IpHostProtocolAddressInformation& controlEndpoint(); + void setDeviceInfo(IpParameterObject& parameters, DeviceObject& deviceObject); + void setSupportedServices(); + void setIpConfig(IpParameterObject& parameters); + void setIpCurrentConfig(IpParameterObject& parameters); + void setKnxAddresses(IpParameterObject& parameters, DeviceObject& deviceObject); + //setManuData + void setTunnelingInfo(IpParameterObject& parameters, DeviceObject& deviceObject, KnxIpTunnelConnection tunnels[]); + void setExtendedDeviceInfo(); + uint8_t* DIBs(); + private: + IpHostProtocolAddressInformation _controlEndpoint; + int currentPos = 0; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_state_request.cpp b/src/knx/ip/knx_ip_state_request.cpp index 816955cb..15827b72 100644 --- a/src/knx/ip/knx_ip_state_request.cpp +++ b/src/knx/ip/knx_ip_state_request.cpp @@ -1,15 +1,18 @@ #include "knx_ip_state_request.h" -KnxIpStateRequest::KnxIpStateRequest(uint8_t* data, uint16_t length) - : KnxIpFrame(data, length), _hpaiCtrl(data + LEN_KNXIP_HEADER + 1 /*ChannelId*/ + 1 /*Reserved*/) +namespace Knx { -} + KnxIpStateRequest::KnxIpStateRequest(uint8_t* data, uint16_t length) + : KnxIpFrame(data, length), _hpaiCtrl(data + LEN_KNXIP_HEADER + 1 /*ChannelId*/ + 1 /*Reserved*/) + { + } -IpHostProtocolAddressInformation& KnxIpStateRequest::hpaiCtrl() -{ - return _hpaiCtrl; -} -uint8_t KnxIpStateRequest::channelId() -{ - return _data[LEN_KNXIP_HEADER]; -} + IpHostProtocolAddressInformation& KnxIpStateRequest::hpaiCtrl() + { + return _hpaiCtrl; + } + uint8_t KnxIpStateRequest::channelId() + { + return _data[LEN_KNXIP_HEADER]; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_state_request.h b/src/knx/ip/knx_ip_state_request.h index 9bb7c3bc..087eb0bc 100644 --- a/src/knx/ip/knx_ip_state_request.h +++ b/src/knx/ip/knx_ip_state_request.h @@ -4,13 +4,16 @@ #include "knx_ip_cri.h" #include "ip_host_protocol_address_information.h" -class KnxIpStateRequest : public KnxIpFrame +namespace Knx { - public: - KnxIpStateRequest(uint8_t* data, uint16_t length); - IpHostProtocolAddressInformation& hpaiCtrl(); - uint8_t channelId(); - private: - IpHostProtocolAddressInformation _hpaiCtrl; + class KnxIpStateRequest : public KnxIpFrame + { + public: + KnxIpStateRequest(uint8_t* data, uint16_t length); + IpHostProtocolAddressInformation& hpaiCtrl(); + uint8_t channelId(); + private: + IpHostProtocolAddressInformation _hpaiCtrl; -}; \ No newline at end of file + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_state_response.cpp b/src/knx/ip/knx_ip_state_response.cpp index 10068803..4e8ef6b5 100644 --- a/src/knx/ip/knx_ip_state_response.cpp +++ b/src/knx/ip/knx_ip_state_response.cpp @@ -15,10 +15,13 @@ #endif #endif -KnxIpStateResponse::KnxIpStateResponse(uint8_t channelId, uint8_t errorCode) - : KnxIpFrame(LEN_KNXIP_HEADER + 2) +namespace Knx { - serviceTypeIdentifier(ConnectionStateResponse); - _data[LEN_KNXIP_HEADER] = channelId; - _data[LEN_KNXIP_HEADER + 1] = errorCode; -} + KnxIpStateResponse::KnxIpStateResponse(uint8_t channelId, uint8_t errorCode) + : KnxIpFrame(LEN_KNXIP_HEADER + 2) + { + serviceTypeIdentifier(ConnectionStateResponse); + _data[LEN_KNXIP_HEADER] = channelId; + _data[LEN_KNXIP_HEADER + 1] = errorCode; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_state_response.h b/src/knx/ip/knx_ip_state_response.h index 56f83bef..8a465b27 100644 --- a/src/knx/ip/knx_ip_state_response.h +++ b/src/knx/ip/knx_ip_state_response.h @@ -2,9 +2,12 @@ #include "knx_ip_frame.h" -class KnxIpStateResponse : public KnxIpFrame +namespace Knx { - public: - KnxIpStateResponse(uint8_t channelId, uint8_t errorCode); - private: -}; + class KnxIpStateResponse : public KnxIpFrame + { + public: + KnxIpStateResponse(uint8_t channelId, uint8_t errorCode); + private: + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_supported_service_dib.cpp b/src/knx/ip/knx_ip_supported_service_dib.cpp index 901964b1..baba7557 100644 --- a/src/knx/ip/knx_ip_supported_service_dib.cpp +++ b/src/knx/ip/knx_ip_supported_service_dib.cpp @@ -1,42 +1,45 @@ #include "knx_ip_supported_service_dib.h" -KnxIpSupportedServiceDIB::KnxIpSupportedServiceDIB(uint8_t* data) : KnxIpDIB(data) -{} - - -uint8_t KnxIpSupportedServiceDIB::serviceVersion(ServiceFamily family) +namespace Knx { - uint8_t* start = _data + 2; - uint8_t* end = _data + length(); + KnxIpSupportedServiceDIB::KnxIpSupportedServiceDIB(uint8_t* data) : KnxIpDIB(data) + {} + - for (uint8_t* it = start; it < end; it += 2) + uint8_t KnxIpSupportedServiceDIB::serviceVersion(ServiceFamily family) { - if (*it == family) - return it[1]; - } + uint8_t* start = _data + 2; + uint8_t* end = _data + length(); - return 0; -} + for (uint8_t* it = start; it < end; it += 2) + { + if (*it == family) + return it[1]; + } + return 0; + } -void KnxIpSupportedServiceDIB::serviceVersion(ServiceFamily family, uint8_t version) -{ - uint8_t* start = _data + 2; - uint8_t* end = _data + length(); - for (uint8_t* it = start; it < end; it += 2) + void KnxIpSupportedServiceDIB::serviceVersion(ServiceFamily family, uint8_t version) { - if (*it == family) - { - it[1] = version; - break; - } + uint8_t* start = _data + 2; + uint8_t* end = _data + length(); - if (*it == 0) + for (uint8_t* it = start; it < end; it += 2) { - *it = family; - it[1] = version; - break; + if (*it == family) + { + it[1] = version; + break; + } + + if (*it == 0) + { + *it = family; + it[1] = version; + break; + } } } -} +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_supported_service_dib.h b/src/knx/ip/knx_ip_supported_service_dib.h index 4d7da007..61fc27a9 100644 --- a/src/knx/ip/knx_ip_supported_service_dib.h +++ b/src/knx/ip/knx_ip_supported_service_dib.h @@ -1,21 +1,24 @@ #pragma once #include "knx_ip_dib.h" -enum ServiceFamily : uint8_t +namespace Knx { - Core = 2, - DeviceManagement = 3, - Tunnelling = 4, - Routing = 5, - RemoteLogging = 6, - RemoteConfigDiag = 7, - ObjectServer = 8 -}; + enum ServiceFamily : uint8_t + { + Core = 2, + DeviceManagement = 3, + Tunnelling = 4, + Routing = 5, + RemoteLogging = 6, + RemoteConfigDiag = 7, + ObjectServer = 8 + }; -class KnxIpSupportedServiceDIB : public KnxIpDIB -{ - public: - KnxIpSupportedServiceDIB(uint8_t* data); - uint8_t serviceVersion(ServiceFamily family); - void serviceVersion(ServiceFamily family, uint8_t version); -}; + class KnxIpSupportedServiceDIB : public KnxIpDIB + { + public: + KnxIpSupportedServiceDIB(uint8_t* data); + uint8_t serviceVersion(ServiceFamily family); + void serviceVersion(ServiceFamily family, uint8_t version); + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_tunnel_connection.cpp b/src/knx/ip/knx_ip_tunnel_connection.cpp index 9d4fe2a1..7e3af466 100644 --- a/src/knx/ip/knx_ip_tunnel_connection.cpp +++ b/src/knx/ip/knx_ip_tunnel_connection.cpp @@ -1,19 +1,22 @@ #include "knx_ip_tunnel_connection.h" -KnxIpTunnelConnection::KnxIpTunnelConnection() +namespace Knx { + KnxIpTunnelConnection::KnxIpTunnelConnection() + { -} + } -void KnxIpTunnelConnection::Reset() -{ - ChannelId = 0; - IpAddress = 0; - PortData = 0; - PortCtrl = 0; - lastHeartbeat = 0; - SequenceCounter_S = 0; - SequenceCounter_R = 255; - IndividualAddress = 0; - IsConfig = false; -} + void KnxIpTunnelConnection::Reset() + { + ChannelId = 0; + IpAddress = 0; + PortData = 0; + PortCtrl = 0; + lastHeartbeat = 0; + SequenceCounter_S = 0; + SequenceCounter_R = 255; + IndividualAddress = 0; + IsConfig = false; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_tunnel_connection.h b/src/knx/ip/knx_ip_tunnel_connection.h index eb4a0e72..0af21b63 100644 --- a/src/knx/ip/knx_ip_tunnel_connection.h +++ b/src/knx/ip/knx_ip_tunnel_connection.h @@ -1,22 +1,25 @@ #pragma once #include "../platform/platform.h" -class KnxIpTunnelConnection +namespace Knx { - public: - KnxIpTunnelConnection(); - uint8_t ChannelId = 0; - uint16_t IndividualAddress = 0; - uint32_t IpAddress = 0; - uint16_t PortData = 0; - uint16_t PortCtrl = 0; - uint8_t SequenceCounter_S = 0; - uint8_t SequenceCounter_R = 255; - unsigned long lastHeartbeat = 0; - bool IsConfig = false; + class KnxIpTunnelConnection + { + public: + KnxIpTunnelConnection(); + uint8_t ChannelId = 0; + uint16_t IndividualAddress = 0; + uint32_t IpAddress = 0; + uint16_t PortData = 0; + uint16_t PortCtrl = 0; + uint8_t SequenceCounter_S = 0; + uint8_t SequenceCounter_R = 255; + unsigned long lastHeartbeat = 0; + bool IsConfig = false; - void Reset(); + void Reset(); - private: + private: -}; \ No newline at end of file + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_tunneling_ack.cpp b/src/knx/ip/knx_ip_tunneling_ack.cpp index f29add1f..0c7bb94d 100644 --- a/src/knx/ip/knx_ip_tunneling_ack.cpp +++ b/src/knx/ip/knx_ip_tunneling_ack.cpp @@ -1,18 +1,21 @@ #include "knx_ip_tunneling_ack.h" #include -KnxIpTunnelingAck::KnxIpTunnelingAck(uint8_t* data, - uint16_t length) : KnxIpFrame(data, length), _ch(_data + LEN_KNXIP_HEADER) +namespace Knx { -} + KnxIpTunnelingAck::KnxIpTunnelingAck(uint8_t* data, + uint16_t length) : KnxIpFrame(data, length), _ch(_data + LEN_KNXIP_HEADER) + { + } -KnxIpTunnelingAck::KnxIpTunnelingAck() - : KnxIpFrame(LEN_KNXIP_HEADER + LEN_CH), _ch(_data + LEN_KNXIP_HEADER) -{ - serviceTypeIdentifier(TunnelingAck); -} + KnxIpTunnelingAck::KnxIpTunnelingAck() + : KnxIpFrame(LEN_KNXIP_HEADER + LEN_CH), _ch(_data + LEN_KNXIP_HEADER) + { + serviceTypeIdentifier(TunnelingAck); + } -KnxIpCH& KnxIpTunnelingAck::connectionHeader() -{ - return _ch; -} + KnxIpCH& KnxIpTunnelingAck::connectionHeader() + { + return _ch; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_tunneling_ack.h b/src/knx/ip/knx_ip_tunneling_ack.h index 0f617235..1da362f1 100644 --- a/src/knx/ip/knx_ip_tunneling_ack.h +++ b/src/knx/ip/knx_ip_tunneling_ack.h @@ -3,12 +3,17 @@ #include "knx_ip_frame.h" #include "knx_ip_ch.h" #include "../datalink_layer/cemi_frame.h" -class KnxIpTunnelingAck : public KnxIpFrame + + +namespace Knx { - public: - KnxIpTunnelingAck(uint8_t* data, uint16_t length); - KnxIpTunnelingAck(); - KnxIpCH& connectionHeader(); - private: - KnxIpCH _ch; -}; + class KnxIpTunnelingAck : public KnxIpFrame + { + public: + KnxIpTunnelingAck(uint8_t* data, uint16_t length); + KnxIpTunnelingAck(); + KnxIpCH& connectionHeader(); + private: + KnxIpCH _ch; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_tunneling_info_dib.cpp b/src/knx/ip/knx_ip_tunneling_info_dib.cpp index 12a3babf..e7b4b771 100644 --- a/src/knx/ip/knx_ip_tunneling_info_dib.cpp +++ b/src/knx/ip/knx_ip_tunneling_info_dib.cpp @@ -3,27 +3,30 @@ #include "../bits.h" -KnxIpTunnelingInfoDIB::KnxIpTunnelingInfoDIB(uint8_t* data) : KnxIpDIB(data) +namespace Knx { - currentPos = data + 4; -} + KnxIpTunnelingInfoDIB::KnxIpTunnelingInfoDIB(uint8_t* data) : KnxIpDIB(data) + { + currentPos = data + 4; + } -uint16_t KnxIpTunnelingInfoDIB::apduLength() -{ - uint16_t addr = 0; - popWord(addr, _data + 2); - return addr; -} + uint16_t KnxIpTunnelingInfoDIB::apduLength() + { + uint16_t addr = 0; + popWord(addr, _data + 2); + return addr; + } -void KnxIpTunnelingInfoDIB::apduLength(uint16_t addr) -{ - pushWord(addr, _data + 2); -} + void KnxIpTunnelingInfoDIB::apduLength(uint16_t addr) + { + pushWord(addr, _data + 2); + } -void KnxIpTunnelingInfoDIB::tunnelingSlot(uint16_t addr, uint16_t state) -{ - pushWord(addr, currentPos); - pushWord(state, currentPos + 2); - currentPos += 4; - length(currentPos - _data); -} + void KnxIpTunnelingInfoDIB::tunnelingSlot(uint16_t addr, uint16_t state) + { + pushWord(addr, currentPos); + pushWord(state, currentPos + 2); + currentPos += 4; + length(currentPos - _data); + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_tunneling_info_dib.h b/src/knx/ip/knx_ip_tunneling_info_dib.h index 623d6d95..2011f237 100644 --- a/src/knx/ip/knx_ip_tunneling_info_dib.h +++ b/src/knx/ip/knx_ip_tunneling_info_dib.h @@ -2,13 +2,16 @@ #include "knx_ip_dib.h" #include "service_families.h" -class KnxIpTunnelingInfoDIB : public KnxIpDIB +namespace Knx { - public: - KnxIpTunnelingInfoDIB(uint8_t* data); - uint16_t apduLength(); - void apduLength(uint16_t addr); - void tunnelingSlot(uint16_t addr, uint16_t state); - private: - uint8_t* currentPos = 0; -}; + class KnxIpTunnelingInfoDIB : public KnxIpDIB + { + public: + KnxIpTunnelingInfoDIB(uint8_t* data); + uint16_t apduLength(); + void apduLength(uint16_t addr); + void tunnelingSlot(uint16_t addr, uint16_t state); + private: + uint8_t* currentPos = 0; + }; +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_tunneling_request.cpp b/src/knx/ip/knx_ip_tunneling_request.cpp index 8beb2492..66be8337 100644 --- a/src/knx/ip/knx_ip_tunneling_request.cpp +++ b/src/knx/ip/knx_ip_tunneling_request.cpp @@ -1,24 +1,27 @@ #include "knx_ip_tunneling_request.h" #include -KnxIpTunnelingRequest::KnxIpTunnelingRequest(uint8_t* data, - uint16_t length) : KnxIpFrame(data, length), _frame(data + LEN_CH + headerLength(), length - LEN_CH - headerLength()), _ch(_data + headerLength()) +namespace Knx { -} + KnxIpTunnelingRequest::KnxIpTunnelingRequest(uint8_t* data, + uint16_t length) : KnxIpFrame(data, length), _frame(data + LEN_CH + headerLength(), length - LEN_CH - headerLength()), _ch(_data + headerLength()) + { + } -KnxIpTunnelingRequest::KnxIpTunnelingRequest(CemiFrame frame) - : KnxIpFrame(frame.totalLenght() + LEN_CH + LEN_KNXIP_HEADER), _frame(_data + LEN_CH + LEN_KNXIP_HEADER, frame.totalLenght()), _ch(_data + LEN_KNXIP_HEADER) -{ - serviceTypeIdentifier(TunnelingRequest); - memcpy(_data + LEN_KNXIP_HEADER + LEN_CH, frame.data(), frame.totalLenght()); -} + KnxIpTunnelingRequest::KnxIpTunnelingRequest(CemiFrame frame) + : KnxIpFrame(frame.totalLenght() + LEN_CH + LEN_KNXIP_HEADER), _frame(_data + LEN_CH + LEN_KNXIP_HEADER, frame.totalLenght()), _ch(_data + LEN_KNXIP_HEADER) + { + serviceTypeIdentifier(TunnelingRequest); + memcpy(_data + LEN_KNXIP_HEADER + LEN_CH, frame.data(), frame.totalLenght()); + } -CemiFrame& KnxIpTunnelingRequest::frame() -{ - return _frame; -} + CemiFrame& KnxIpTunnelingRequest::frame() + { + return _frame; + } -KnxIpCH& KnxIpTunnelingRequest::connectionHeader() -{ - return _ch; -} + KnxIpCH& KnxIpTunnelingRequest::connectionHeader() + { + return _ch; + } +} \ No newline at end of file diff --git a/src/knx/ip/knx_ip_tunneling_request.h b/src/knx/ip/knx_ip_tunneling_request.h index 05f8b056..55bb3628 100644 --- a/src/knx/ip/knx_ip_tunneling_request.h +++ b/src/knx/ip/knx_ip_tunneling_request.h @@ -3,14 +3,18 @@ #include "knx_ip_frame.h" #include "knx_ip_ch.h" #include "../datalink_layer/cemi_frame.h" -class KnxIpTunnelingRequest : public KnxIpFrame + +namespace Knx { - public: - KnxIpTunnelingRequest(uint8_t* data, uint16_t length); - KnxIpTunnelingRequest(CemiFrame frame); - CemiFrame& frame(); - KnxIpCH& connectionHeader(); - private: - CemiFrame _frame; - KnxIpCH _ch; -}; + class KnxIpTunnelingRequest : public KnxIpFrame + { + public: + KnxIpTunnelingRequest(uint8_t* data, uint16_t length); + KnxIpTunnelingRequest(CemiFrame frame); + CemiFrame& frame(); + KnxIpCH& connectionHeader(); + private: + CemiFrame _frame; + KnxIpCH _ch; + }; +} \ No newline at end of file diff --git a/src/knx/knx_facade.h b/src/knx/knx_facade.h index f43aa816..74b5097b 100644 --- a/src/knx/knx_facade.h +++ b/src/knx/knx_facade.h @@ -30,10 +30,6 @@ #include "platform/cc1310_platform.h" #endif -#ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE - extern void buttonUp(); -#endif - #ifndef KNX_LED #ifdef LED_BUILTIN #define KNX_LED LED_BUILTIN @@ -50,6 +46,12 @@ #define KNX_BUTTON -1 #endif +namespace Knx { + +#ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE + extern void buttonUp(); +#endif + typedef const uint8_t* (*RestoreCallback)(const uint8_t* buffer); typedef uint8_t* (*SaveCallback)(uint8_t* buffer); typedef void (*IsrFunctionPtr)(); @@ -452,7 +454,7 @@ template class KnxFacade : private SaveRestore _progLedCallback(false); } }; - +} #ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE #ifdef ARDUINO_ARCH_SAMD // predefined global instance for TP or RF or TP/RF coupler diff --git a/src/knx/knx_types.cpp b/src/knx/knx_types.cpp index 38d367a3..ca9a4d0f 100644 --- a/src/knx/knx_types.cpp +++ b/src/knx/knx_types.cpp @@ -1,713 +1,718 @@ #include "knx_types.h" #include "bits.h" -#ifndef KNX_NO_PRINT -const char* enum_name(const LCCONFIG enum_val) +namespace Knx { - switch (enum_val) + +#ifndef KNX_NO_PRINT + const char* enum_name(const LCCONFIG enum_val) { - case PHYS_FRAME: - return "PHYS_FRAME(ROUT)"; + switch (enum_val) + { + case PHYS_FRAME: + return "PHYS_FRAME(ROUT)"; - case PHYS_FRAME_UNLOCK: - return "PHYS_FRAME_UNLOCK"; + case PHYS_FRAME_UNLOCK: + return "PHYS_FRAME_UNLOCK"; - case PHYS_FRAME_LOCK: - return "PHYS_FRAME_LOCK"; + case PHYS_FRAME_LOCK: + return "PHYS_FRAME_LOCK"; - case PHYS_REPEAT: - return "PHYS_REPEAT"; + case PHYS_REPEAT: + return "PHYS_REPEAT"; - case BROADCAST_LOCK: - return "BROADCAST_LOCK"; + case BROADCAST_LOCK: + return "BROADCAST_LOCK"; - case BROADCAST_REPEAT: - return "BROADCAST_REPEAT"; + case BROADCAST_REPEAT: + return "BROADCAST_REPEAT"; - case GROUP_IACK_ROUT: - return "GROUP_IACK_ROUT"; + case GROUP_IACK_ROUT: + return "GROUP_IACK_ROUT"; - case PHYS_IACK: - return "PHYS_IACK/NACK"; + case PHYS_IACK: + return "PHYS_IACK/NACK"; - case PHYS_IACK_NORMAL: - return "PHYS_IACK_NORMAL"; + case PHYS_IACK_NORMAL: + return "PHYS_IACK_NORMAL"; - case PHYS_IACK_ALL: - return "PHYS_IACK_ALL"; - } + case PHYS_IACK_ALL: + return "PHYS_IACK_ALL"; + } - return ""; -} + return ""; + } -const char* enum_name(const LCGRPCONFIG enum_val) -{ - switch (enum_val) + const char* enum_name(const LCGRPCONFIG enum_val) { - case GROUP_6FFF: - return "GROUP_6FFF(ROUTE)"; + switch (enum_val) + { + case GROUP_6FFF: + return "GROUP_6FFF(ROUTE)"; - case GROUP_7000: - return "GROUP_7000(ROUTE)"; + case GROUP_7000: + return "GROUP_7000(ROUTE)"; - case GROUP_REPEAT: - return "GROUP_REPEAT"; + case GROUP_REPEAT: + return "GROUP_REPEAT"; - case GROUP_6FFFUNLOCK: - return "GROUP_6FFFUNLOCK"; + case GROUP_6FFFUNLOCK: + return "GROUP_6FFFUNLOCK"; - case GROUP_6FFFLOCK: - return "GROUP_6FFFLOCK"; + case GROUP_6FFFLOCK: + return "GROUP_6FFFLOCK"; - case GROUP_7000UNLOCK: - return "GROUP_7000UNLOCK"; + case GROUP_7000UNLOCK: + return "GROUP_7000UNLOCK"; - case GROUP_7000LOCK: - return "GROUP_7000LOCK"; - } + case GROUP_7000LOCK: + return "GROUP_7000LOCK"; + } - return ""; -} + return ""; + } -const char* enum_name(const DptMedium enum_val) -{ - switch (enum_val) + const char* enum_name(const DptMedium enum_val) { - case KNX_TP1: - return "KNX_TP1"; + switch (enum_val) + { + case KNX_TP1: + return "KNX_TP1"; - case KNX_PL110: - return "KNX_PL110"; + case KNX_PL110: + return "KNX_PL110"; - case KNX_RF: - return "KNX_RF"; + case KNX_RF: + return "KNX_RF"; - case KNX_IP: - return "KNX_IP"; - } + case KNX_IP: + return "KNX_IP"; + } - return ""; -} + return ""; + } -const char* enum_name(const EraseCode enum_val) -{ - switch (enum_val) + const char* enum_name(const EraseCode enum_val) { - case Void: - return "Void"; + switch (enum_val) + { + case Void: + return "Void"; - case ConfirmedRestart: - return "ConfirmedRestart"; + case ConfirmedRestart: + return "ConfirmedRestart"; - case FactoryReset: - return "FactoryReset"; + case FactoryReset: + return "FactoryReset"; - case ResetIA: - return "ResetIA"; + case ResetIA: + return "ResetIA"; - case ResetAP: - return "ResetAP"; + case ResetAP: + return "ResetAP"; - case ResetParam: - return "ResetParam"; + case ResetParam: + return "ResetParam"; - case ResetLinks: - return "ResetLinks"; + case ResetLinks: + return "ResetLinks"; - case FactoryResetWithoutIA: - return "FactoryResetWithoutIA"; - } + case FactoryResetWithoutIA: + return "FactoryResetWithoutIA"; + } - return ""; -} + return ""; + } -const char* enum_name(const RestartType enum_val) -{ - switch (enum_val) + const char* enum_name(const RestartType enum_val) { - case BasicRestart: - return "BasicRestart"; + switch (enum_val) + { + case BasicRestart: + return "BasicRestart"; - case MasterReset: - return "MasterReset"; - } + case MasterReset: + return "MasterReset"; + } - return ""; -} + return ""; + } -const char* enum_name(const DataSecurity enum_val) -{ - switch (enum_val) + const char* enum_name(const DataSecurity enum_val) { - case None: - return "None"; + switch (enum_val) + { + case None: + return "None"; - case Auth: - return "Auth"; + case Auth: + return "Auth"; - case AuthConf: - return "AuthConf"; - } + case AuthConf: + return "AuthConf"; + } - return ""; -} + return ""; + } -const char* enum_name(const ApduType enum_val) -{ - switch (enum_val) + const char* enum_name(const ApduType enum_val) { - case GroupValueRead: - return "GroupValueRead"; + switch (enum_val) + { + case GroupValueRead: + return "GroupValueRead"; - case GroupValueResponse: - return "GroupValueResponse"; + case GroupValueResponse: + return "GroupValueResponse"; - case GroupValueWrite: - return "GroupValueWrite"; + case GroupValueWrite: + return "GroupValueWrite"; - case IndividualAddressWrite: - return "IndividualAddressWrite"; + case IndividualAddressWrite: + return "IndividualAddressWrite"; - case IndividualAddressRead: - return "IndividualAddressRead"; + case IndividualAddressRead: + return "IndividualAddressRead"; - case IndividualAddressResponse: - return "IndividualAddressResponse"; + case IndividualAddressResponse: + return "IndividualAddressResponse"; - case IndividualAddressSerialNumberRead: - return "IndividualAddressSerialNumberRead"; + case IndividualAddressSerialNumberRead: + return "IndividualAddressSerialNumberRead"; - case IndividualAddressSerialNumberResponse: - return "IndividualAddressSerialNumberResponse"; + case IndividualAddressSerialNumberResponse: + return "IndividualAddressSerialNumberResponse"; - case IndividualAddressSerialNumberWrite: - return "IndividualAddressSerialNumberWrite"; + case IndividualAddressSerialNumberWrite: + return "IndividualAddressSerialNumberWrite"; - case SystemNetworkParameterRead: - return "SystemNetworkParameterRead"; + case SystemNetworkParameterRead: + return "SystemNetworkParameterRead"; - case SystemNetworkParameterResponse: - return "SystemNetworkParameterResponse"; + case SystemNetworkParameterResponse: + return "SystemNetworkParameterResponse"; - case SystemNetworkParameterWrite: - return "SystemNetworkParameterWrite"; + case SystemNetworkParameterWrite: + return "SystemNetworkParameterWrite"; - case DomainAddressWrite: - return "DomainAddressWrite"; + case DomainAddressWrite: + return "DomainAddressWrite"; - case DomainAddressRead: - return "DomainAddressRead"; + case DomainAddressRead: + return "DomainAddressRead"; - case DomainAddressResponse: - return "DomainAddressResponse"; + case DomainAddressResponse: + return "DomainAddressResponse"; - case DomainAddressSelectiveRead: - return "DomainAddressSelectiveRead"; + case DomainAddressSelectiveRead: + return "DomainAddressSelectiveRead"; - case DomainAddressSerialNumberRead: - return "DomainAddressSerialNumberRead"; + case DomainAddressSerialNumberRead: + return "DomainAddressSerialNumberRead"; - case DomainAddressSerialNumberResponse: - return "DomainAddressSerialNumberResponse"; + case DomainAddressSerialNumberResponse: + return "DomainAddressSerialNumberResponse"; - case DomainAddressSerialNumberWrite: - return "DomainAddressSerialNumberWrite"; + case DomainAddressSerialNumberWrite: + return "DomainAddressSerialNumberWrite"; - case ADCRead: - return "ADCRead"; + case ADCRead: + return "ADCRead"; - case ADCResponse: - return "ADCResponse"; + case ADCResponse: + return "ADCResponse"; - case PropertyValueExtRead: - return "PropertyValueExtRead"; + case PropertyValueExtRead: + return "PropertyValueExtRead"; - case PropertyValueExtResponse: - return "PropertyValueExtResponse"; + case PropertyValueExtResponse: + return "PropertyValueExtResponse"; - case PropertyValueExtWriteCon: - return "PropertyValueExtWriteCon"; + case PropertyValueExtWriteCon: + return "PropertyValueExtWriteCon"; - case PropertyValueExtWriteConResponse: - return "PropertyValueExtWriteConResponse"; + case PropertyValueExtWriteConResponse: + return "PropertyValueExtWriteConResponse"; - case PropertyValueExtWriteUnCon: - return "PropertyValueExtWriteUnCon"; + case PropertyValueExtWriteUnCon: + return "PropertyValueExtWriteUnCon"; - case PropertyExtDescriptionRead: - return "PropertyExtDescriptionRead"; + case PropertyExtDescriptionRead: + return "PropertyExtDescriptionRead"; - case PropertyExtDescriptionResponse: - return "PropertyExtDescriptionResponse"; + case PropertyExtDescriptionResponse: + return "PropertyExtDescriptionResponse"; - case FunctionPropertyExtCommand: - return "FunctionPropertyExtCommand"; + case FunctionPropertyExtCommand: + return "FunctionPropertyExtCommand"; - case FunctionPropertyExtState: - return "FunctionPropertyExtState"; + case FunctionPropertyExtState: + return "FunctionPropertyExtState"; - case FunctionPropertyExtStateResponse: - return "FunctionPropertyExtStateResponse"; + case FunctionPropertyExtStateResponse: + return "FunctionPropertyExtStateResponse"; - case MemoryExtWrite: - return "MemoryExtWrite"; + case MemoryExtWrite: + return "MemoryExtWrite"; - case MemoryExtWriteResponse: - return "MemoryExtWriteResponse"; + case MemoryExtWriteResponse: + return "MemoryExtWriteResponse"; - case MemoryExtRead: - return "MemoryExtRead"; + case MemoryExtRead: + return "MemoryExtRead"; - case MemoryExtReadResponse: - return "MemoryExtReadResponse"; + case MemoryExtReadResponse: + return "MemoryExtReadResponse"; - case MemoryRead: - return "MemoryRead"; + case MemoryRead: + return "MemoryRead"; - case MemoryResponse: - return "MemoryResponse"; + case MemoryResponse: + return "MemoryResponse"; - case MemoryWrite: - return "MemoryWrite"; + case MemoryWrite: + return "MemoryWrite"; - case UserMemoryRead: - return "UserMemoryRead"; + case UserMemoryRead: + return "UserMemoryRead"; - case UserMemoryResponse: - return "UserMemoryResponse"; + case UserMemoryResponse: + return "UserMemoryResponse"; - case UserMemoryWrite: - return "UserMemoryWrite"; + case UserMemoryWrite: + return "UserMemoryWrite"; - case UserManufacturerInfoRead: - return "UserManufacturerInfoRead"; + case UserManufacturerInfoRead: + return "UserManufacturerInfoRead"; - case UserManufacturerInfoResponse: - return "UserManufacturerInfoResponse"; + case UserManufacturerInfoResponse: + return "UserManufacturerInfoResponse"; - case FunctionPropertyCommand: - return "FunctionPropertyCommand"; + case FunctionPropertyCommand: + return "FunctionPropertyCommand"; - case FunctionPropertyState: - return "FunctionPropertyState"; + case FunctionPropertyState: + return "FunctionPropertyState"; - case FunctionPropertyStateResponse: - return "FunctionPropertyStateResponse"; + case FunctionPropertyStateResponse: + return "FunctionPropertyStateResponse"; - case DeviceDescriptorRead: - return "DeviceDescriptorRead"; + case DeviceDescriptorRead: + return "DeviceDescriptorRead"; - case DeviceDescriptorResponse: - return "DeviceDescriptorResponse"; + case DeviceDescriptorResponse: + return "DeviceDescriptorResponse"; - case Restart: - return "Restart"; + case Restart: + return "Restart"; - case RestartMasterReset: - return "RestartMasterReset"; + case RestartMasterReset: + return "RestartMasterReset"; - case RoutingTableOpen: - return "RoutingTableOpen"; + case RoutingTableOpen: + return "RoutingTableOpen"; - case RoutingTableRead: - return "RoutingTableRead"; + case RoutingTableRead: + return "RoutingTableRead"; - case RoutingTableReadResponse: - return "RoutingTableReadResponse"; + case RoutingTableReadResponse: + return "RoutingTableReadResponse"; - case RoutingTableWrite: - return "RoutingTableWrite"; + case RoutingTableWrite: + return "RoutingTableWrite"; - case MemoryRouterWrite: - return "MemoryRouterWrite"; + case MemoryRouterWrite: + return "MemoryRouterWrite"; - case MemoryRouterReadResponse: - return "MemoryRouterReadResponse"; + case MemoryRouterReadResponse: + return "MemoryRouterReadResponse"; - case AuthorizeRequest: - return "AuthorizeRequest"; + case AuthorizeRequest: + return "AuthorizeRequest"; - case AuthorizeResponse: - return "AuthorizeResponse"; + case AuthorizeResponse: + return "AuthorizeResponse"; - case KeyWrite: - return "KeyWrite"; + case KeyWrite: + return "KeyWrite"; - case KeyResponse: - return "KeyResponse"; + case KeyResponse: + return "KeyResponse"; - case PropertyValueRead: - return "PropertyValueRead"; + case PropertyValueRead: + return "PropertyValueRead"; - case PropertyValueResponse: - return "PropertyValueResponse"; + case PropertyValueResponse: + return "PropertyValueResponse"; - case PropertyValueWrite: - return "PropertyValueWrite"; + case PropertyValueWrite: + return "PropertyValueWrite"; - case PropertyDescriptionRead: - return "PropertyDescriptionRead"; + case PropertyDescriptionRead: + return "PropertyDescriptionRead"; - case PropertyDescriptionResponse: - return "PropertyDescriptionResponse"; + case PropertyDescriptionResponse: + return "PropertyDescriptionResponse"; - case SecureService: - return "SecureService"; - } + case SecureService: + return "SecureService"; + } - return ""; -} + return ""; + } -const char* enum_name(const TpduType enum_val) -{ - switch (enum_val) + const char* enum_name(const TpduType enum_val) { - case DataBroadcast: - return "DataBroadcast"; + switch (enum_val) + { + case DataBroadcast: + return "DataBroadcast"; - case DataGroup: - return "DataGroup"; + case DataGroup: + return "DataGroup"; - case DataInduvidual: - return "DataInduvidual"; + case DataInduvidual: + return "DataInduvidual"; - case DataConnected: - return "DataConnected"; + case DataConnected: + return "DataConnected"; - case Connect: - return "Connect"; + case Connect: + return "Connect"; - case Disconnect: - return "Disconnect"; + case Disconnect: + return "Disconnect"; - case Ack: - return "Ack"; + case Ack: + return "Ack"; - case Nack: - return "Nack"; - } + case Nack: + return "Nack"; + } - return ""; -} + return ""; + } -const char* enum_name(const HopCountType enum_val) -{ - switch (enum_val) + const char* enum_name(const HopCountType enum_val) { - case UnlimitedRouting: - return "UnlimitedRouting"; + switch (enum_val) + { + case UnlimitedRouting: + return "UnlimitedRouting"; - case NetworkLayerParameter: - return "NetworkLayerParameter"; - } + case NetworkLayerParameter: + return "NetworkLayerParameter"; + } - return ""; -} + return ""; + } -const char* enum_name(const Confirm enum_val) -{ - switch (enum_val) + const char* enum_name(const Confirm enum_val) { - case ConfirmNoError: - return "ConfirmNoError"; + switch (enum_val) + { + case ConfirmNoError: + return "ConfirmNoError"; - case ConfirmError: - return "ConfirmError"; - } + case ConfirmError: + return "ConfirmError"; + } - return ""; -} + return ""; + } -const char* enum_name(const SystemBroadcast enum_val) -{ - switch (enum_val) + const char* enum_name(const SystemBroadcast enum_val) { - case SysBroadcast: - return "SysBroadcast"; + switch (enum_val) + { + case SysBroadcast: + return "SysBroadcast"; - case Broadcast: - return "Broadcast"; - } + case Broadcast: + return "Broadcast"; + } - return ""; -} + return ""; + } -const char* enum_name(Repetition enum_val) -{ - switch (enum_val) + const char* enum_name(Repetition enum_val) { - case WasRepeated: - return "WasRepeated/NoRepetiion"; + switch (enum_val) + { + case WasRepeated: + return "WasRepeated/NoRepetiion"; - case WasNotRepeated: - return "WasNotRepeated/RepetitionAllowed"; - } + case WasNotRepeated: + return "WasNotRepeated/RepetitionAllowed"; + } - return ""; -} + return ""; + } -const char* enum_name(const ReturnCodes enum_val) -{ - switch (enum_val) + const char* enum_name(const ReturnCodes enum_val) { - case Success: - return "Success"; + switch (enum_val) + { + case Success: + return "Success"; - case SuccessWithCrc: - return "SuccessWithCrc"; + case SuccessWithCrc: + return "SuccessWithCrc"; - case MemoryError: - return "MemoryError"; + case MemoryError: + return "MemoryError"; - case InvalidCommand: - return "InvalidCommand"; + case InvalidCommand: + return "InvalidCommand"; - case ImpossibleCommand: - return "ImpossibleCommand"; + case ImpossibleCommand: + return "ImpossibleCommand"; - case ExceedsMaxApduLength: - return "ExceedsMaxApduLength"; + case ExceedsMaxApduLength: + return "ExceedsMaxApduLength"; - case DataOverflow: - return "DataOverflow"; + case DataOverflow: + return "DataOverflow"; - case OutOfMinRange: - return "OutOfMinRange"; + case OutOfMinRange: + return "OutOfMinRange"; - case OutOfMaxRange: - return "OutOfMaxRange"; + case OutOfMaxRange: + return "OutOfMaxRange"; - case DataVoid: - return "DataVoid"; + case DataVoid: + return "DataVoid"; - case TemporarilyNotAvailable: - return "TemporarilyNotAvailable"; + case TemporarilyNotAvailable: + return "TemporarilyNotAvailable"; - case AccessWriteOnly: - return "AccessWriteOnly"; + case AccessWriteOnly: + return "AccessWriteOnly"; - case AccessReadOnly: - return "AccessReadOnly"; + case AccessReadOnly: + return "AccessReadOnly"; - case AccessDenied: - return "AccessDenied"; + case AccessDenied: + return "AccessDenied"; - case AddressVoid: - return "AddressVoid"; + case AddressVoid: + return "AddressVoid"; - case DataTypeConflict: - return "DataTypeConflict"; + case DataTypeConflict: + return "DataTypeConflict"; - case GenericError: - return "GenericError"; - } + case GenericError: + return "GenericError"; + } - return ""; -} + return ""; + } -const char* enum_name(const cEmiErrorCode enum_val) -{ - switch (enum_val) + const char* enum_name(const cEmiErrorCode enum_val) { - case Unspecified_Error: - return "Unspecified_Error"; + switch (enum_val) + { + case Unspecified_Error: + return "Unspecified_Error"; - case Out_Of_Range: - return "Out_Of_Range"; + case Out_Of_Range: + return "Out_Of_Range"; - case Out_Of_Max_Range: - return "Out_Of_Max_Range"; + case Out_Of_Max_Range: + return "Out_Of_Max_Range"; - case Out_Of_Min_Range: - return "Out_Of_Min_Range"; + case Out_Of_Min_Range: + return "Out_Of_Min_Range"; - case Memory_Error: - return "Memory_Error"; + case Memory_Error: + return "Memory_Error"; - case Read_Only: - return "Read_Only"; + case Read_Only: + return "Read_Only"; - case Illegal_Command: - return "Illegal_Command"; + case Illegal_Command: + return "Illegal_Command"; - case Void_DP: - return "Void_DP"; + case Void_DP: + return "Void_DP"; - case Type_Conflict: - return "Type_Conflict"; + case Type_Conflict: + return "Type_Conflict"; - case Prop_Index_Range_Error: - return "Prop_Index_Range_Error"; + case Prop_Index_Range_Error: + return "Prop_Index_Range_Error"; - case Value_temp_not_writeable: - return "Value_temp_not_writeable"; - } + case Value_temp_not_writeable: + return "Value_temp_not_writeable"; + } - return ""; -} + return ""; + } -const char* enum_name(const MessageCode enum_val) -{ - switch (enum_val) + const char* enum_name(const MessageCode enum_val) { - case L_data_req: - return "L_data_req"; + switch (enum_val) + { + case L_data_req: + return "L_data_req"; - case L_data_con: - return "L_data_con"; + case L_data_con: + return "L_data_con"; - case L_data_ind: - return "L_data_ind"; + case L_data_ind: + return "L_data_ind"; - case M_PropRead_req: - return "M_PropRead_req"; + case M_PropRead_req: + return "M_PropRead_req"; - case M_PropRead_con: - return "M_PropRead_con"; + case M_PropRead_con: + return "M_PropRead_con"; - case M_PropWrite_req: - return "M_PropWrite_req"; + case M_PropWrite_req: + return "M_PropWrite_req"; - case M_PropWrite_con: - return "M_PropWrite_con"; + case M_PropWrite_con: + return "M_PropWrite_con"; - case M_PropInfo_ind: - return "M_PropInfo_ind"; + case M_PropInfo_ind: + return "M_PropInfo_ind"; - case M_FuncPropCommand_req: - return "M_FuncPropCommand_req"; + case M_FuncPropCommand_req: + return "M_FuncPropCommand_req"; - case M_FuncPropCommand_con: - return "M_FuncPropCommand/StateRead_con"; + case M_FuncPropCommand_con: + return "M_FuncPropCommand/StateRead_con"; - case M_FuncPropStateRead_req: - return "M_FuncPropStateRead_req"; + case M_FuncPropStateRead_req: + return "M_FuncPropStateRead_req"; - case M_Reset_req: - return "M_Reset_req"; + case M_Reset_req: + return "M_Reset_req"; - case M_Reset_ind: - return "M_Reset_ind"; - } + case M_Reset_ind: + return "M_Reset_ind"; + } - return ""; -} + return ""; + } -const char* enum_name(const AddressType enum_val) -{ - switch (enum_val) + const char* enum_name(const AddressType enum_val) { - case IndividualAddress: - return "IndividualAddress"; + switch (enum_val) + { + case IndividualAddress: + return "IndividualAddress"; - case GroupAddress: - return "GroupAddress"; - } + case GroupAddress: + return "GroupAddress"; + } - return ""; -} + return ""; + } -const char* enum_name(const TPAckType enum_val) -{ - switch (enum_val) + const char* enum_name(const TPAckType enum_val) { - case AckReqNack: - return "AckReqNack"; + switch (enum_val) + { + case AckReqNack: + return "AckReqNack"; - case AckReqBusy: - return "AckReqBusy"; + case AckReqBusy: + return "AckReqBusy"; - case AckReqAck: - return "AckReqAck"; + case AckReqAck: + return "AckReqAck"; - case AckReqNone: - return "AckReqNone"; - } + case AckReqNone: + return "AckReqNone"; + } - return ""; -} + return ""; + } -const char* enum_name(const AckType enum_val) -{ - switch (enum_val) + const char* enum_name(const AckType enum_val) { - case AckDontCare: - return "AckDontCare"; + switch (enum_val) + { + case AckDontCare: + return "AckDontCare"; - case AckRequested: - return "AckRequested"; - } + case AckRequested: + return "AckRequested"; + } - return ""; -} + return ""; + } -const char* enum_name(const Priority enum_val) -{ - switch (enum_val) + const char* enum_name(const Priority enum_val) { - case LowPriority: - return "LowPriority"; + switch (enum_val) + { + case LowPriority: + return "LowPriority"; - case NormalPriority: - return "NormalPriority"; + case NormalPriority: + return "NormalPriority"; - case UrgentPriority: - return "UrgentPriority"; + case UrgentPriority: + return "UrgentPriority"; - case SystemPriority: - return "SystemPriority"; - } + case SystemPriority: + return "SystemPriority"; + } - return ""; -} + return ""; + } -const char* enum_name(const FrameFormat enum_val) -{ - switch (enum_val) + const char* enum_name(const FrameFormat enum_val) { - case ExtendedFrame: - return "ExtendedFrame"; + switch (enum_val) + { + case ExtendedFrame: + return "ExtendedFrame"; - case StandardFrame: - return "StandardFrame"; + case StandardFrame: + return "StandardFrame"; + } + + return ""; } - return ""; -} + void print_ia(const uint16_t ia) + { + print(ia & 0xF000 >> 24); + print("/"); + print(ia & 0x0F00 >> 16); + print("/"); + print(ia & 0x00FF); + } -void print_ia(const uint16_t ia) -{ - print(ia & 0xF000 >> 24); - print("/"); - print(ia & 0x0F00 >> 16); - print("/"); - print(ia & 0x00FF); -} - -void print_ga(const uint16_t ga) -{ - print(ga & 0xF800 >> 23); - print("/"); - print(ga & 0x70 >> 16); - print("/"); - print(ga & 0x00FF); -} -#endif \ No newline at end of file + void print_ga(const uint16_t ga) + { + print(ga & 0xF800 >> 23); + print("/"); + print(ga & 0x70 >> 16); + print("/"); + print(ga & 0x00FF); + } +#endif + +} \ No newline at end of file diff --git a/src/knx/knx_types.h b/src/knx/knx_types.h index 3cf1e13f..2fcb87ef 100644 --- a/src/knx/knx_types.h +++ b/src/knx/knx_types.h @@ -1,315 +1,318 @@ #pragma once #include -using namespace std; -enum FrameFormat +namespace Knx { - ExtendedFrame = 0, - StandardFrame = 0x80 -}; -const char* enum_name(const FrameFormat enum_val); -enum Priority -{ - LowPriority = 0xC, //!< Normal priority of group communication. - NormalPriority = 0x4, //!< More important telegrams like central functions - UrgentPriority = 0x8, //!< Used for alarms. - SystemPriority = 0x0 //!< Mainly used by ETS for device programming. -}; -const char* enum_name(const Priority enum_val); + enum FrameFormat + { + ExtendedFrame = 0, + StandardFrame = 0x80 + }; + const char* enum_name(const FrameFormat enum_val); -enum AckType -{ - AckDontCare = 0, //!< We don't care about DataLinkLayer acknowledgement. - AckRequested = 0x2, //!< We want a DataLinkLayer acknowledgement. -}; -const char* enum_name(const AckType enum_val); + enum Priority + { + LowPriority = 0xC, //!< Normal priority of group communication. + NormalPriority = 0x4, //!< More important telegrams like central functions + UrgentPriority = 0x8, //!< Used for alarms. + SystemPriority = 0x0 //!< Mainly used by ETS for device programming. + }; + const char* enum_name(const Priority enum_val); -enum TPAckType -{ - // see U_ACK_REQ defines in tpuart_data_link_layer.cpp - AckReqNack = 0x04, - AckReqBusy = 0x02, - AckReqAck = 0x01, - AckReqNone = 0x0, -}; -const char* enum_name(const TPAckType enum_val); + enum AckType + { + AckDontCare = 0, //!< We don't care about DataLinkLayer acknowledgement. + AckRequested = 0x2, //!< We want a DataLinkLayer acknowledgement. + }; + const char* enum_name(const AckType enum_val); -enum AddressType -{ - IndividualAddress = 0, - GroupAddress = 0x80, -}; -const char* enum_name(const AddressType enum_val); + enum TPAckType + { + // see U_ACK_REQ defines in tpuart_data_link_layer.cpp + AckReqNack = 0x04, + AckReqBusy = 0x02, + AckReqAck = 0x01, + AckReqNone = 0x0, + }; + const char* enum_name(const TPAckType enum_val); -enum MessageCode -{ - // L_Data services - L_data_req = 0x11, - L_data_con = 0x2E, - L_data_ind = 0x29, + enum AddressType + { + IndividualAddress = 0, + GroupAddress = 0x80, + }; + const char* enum_name(const AddressType enum_val); - // Data Properties - M_PropRead_req = 0xFC, - M_PropRead_con = 0xFB, - M_PropWrite_req = 0xF6, - M_PropWrite_con = 0xF5, - M_PropInfo_ind = 0xF7, + enum MessageCode + { + // L_Data services + L_data_req = 0x11, + L_data_con = 0x2E, + L_data_ind = 0x29, - // Function Properties - M_FuncPropCommand_req = 0xF8, - M_FuncPropCommand_con = 0xFA, - M_FuncPropStateRead_req = 0xF9, - M_FuncPropStateRead_con = 0xFA, // same as M_FuncPropStateRead_con (see 3/6/3 p.105) + // Data Properties + M_PropRead_req = 0xFC, + M_PropRead_con = 0xFB, + M_PropWrite_req = 0xF6, + M_PropWrite_con = 0xF5, + M_PropInfo_ind = 0xF7, - // Further cEMI servies - M_Reset_req = 0xF1, - M_Reset_ind = 0xF0, -}; -const char* enum_name(const MessageCode enum_val); + // Function Properties + M_FuncPropCommand_req = 0xF8, + M_FuncPropCommand_con = 0xFA, + M_FuncPropStateRead_req = 0xF9, + M_FuncPropStateRead_con = 0xFA, // same as M_FuncPropStateRead_con (see 3/6/3 p.105) -enum cEmiErrorCode -{ - Unspecified_Error = 0x00, // unknown error (R/W) - Out_Of_Range = 0x01, // write value not allowed (general, if not error 2 or 3) (W) - Out_Of_Max_Range = 0x02, // write value to high (W) - Out_Of_Min_Range = 0x03, // write value to low (W) - Memory_Error = 0x04, // memory can not be written or only with fault(s) (W) - Read_Only = 0x05, // write access to a ‘read only’ or a write protected Property (W) - Illegal_Command = 0x06, // COMMAND not valid or not supported (W) - Void_DP = 0x07, // read or write access to an non existing Property (R/W) - Type_Conflict = 0x08, // write access with a wrong data type (Datapoint length) (W) - Prop_Index_Range_Error = 0x09, // read or write access to a non existing Property array index (R/W) - Value_temp_not_writeable = 0x0A, // The Property exists but can at this moment not be written with a new value (W) -}; -const char* enum_name(const cEmiErrorCode enum_val); + // Further cEMI servies + M_Reset_req = 0xF1, + M_Reset_ind = 0xF0, + }; + const char* enum_name(const MessageCode enum_val); -// Unified return codes for KNX services and functions -// Note, that several older KNX services and functions do not use these return codes. -enum ReturnCodes -{ - // Generic positive return codes - Success = 0x00, // service, function or command executed sucessfully - SuccessWithCrc = 0x01, // positive message confirmation, CRC over original data - // Generic negative return codes - MemoryError = 0xF1, // memory cannot be accessed or only with fault(s) - InvalidCommand = 0xF2, // server does not support the requested command. ets: also non-existing or protected resource - ImpossibleCommand = 0xF3, // command cannot be executed because a dependency is not fulfilled - ExceedsMaxApduLength = 0xF4, // data will not fit into a frame supported by this server - DataOverflow = 0xF5, // attempt to write data beyond what is reserved for the addressed resource - OutOfMinRange = 0xF6, // write value below minimum supported value - OutOfMaxRange = 0xF7, // write value exceeds maximum supported value - DataVoid = 0xF8, // request contains invalid data - TemporarilyNotAvailable = 0xF9, // data access not possible at this time - AccessWriteOnly = 0xFA, // read access to write-only resource - AccessReadOnly = 0xFB, // write access to read-only resource - AccessDenied = 0xFC, // access to recource is not allowed because of authorization/security - AddressVoid = 0xFD, // resource is not present, address does not exist - DataTypeConflict = 0xFE, // write access with wrong datatype (datapoint length) - GenericError = 0xFF // service, function or command failed -}; -const char* enum_name(const ReturnCodes enum_val); + enum cEmiErrorCode + { + Unspecified_Error = 0x00, // unknown error (R/W) + Out_Of_Range = 0x01, // write value not allowed (general, if not error 2 or 3) (W) + Out_Of_Max_Range = 0x02, // write value to high (W) + Out_Of_Min_Range = 0x03, // write value to low (W) + Memory_Error = 0x04, // memory can not be written or only with fault(s) (W) + Read_Only = 0x05, // write access to a ‘read only’ or a write protected Property (W) + Illegal_Command = 0x06, // COMMAND not valid or not supported (W) + Void_DP = 0x07, // read or write access to an non existing Property (R/W) + Type_Conflict = 0x08, // write access with a wrong data type (Datapoint length) (W) + Prop_Index_Range_Error = 0x09, // read or write access to a non existing Property array index (R/W) + Value_temp_not_writeable = 0x0A, // The Property exists but can at this moment not be written with a new value (W) + }; + const char* enum_name(const cEmiErrorCode enum_val); -enum Repetition -{ - NoRepetiion = 0, - WasRepeated = 0, - RepetitionAllowed = 0x20, - WasNotRepeated = 0x20, -}; -const char* enum_name(Repetition enum_val); + // Unified return codes for KNX services and functions + // Note, that several older KNX services and functions do not use these return codes. + enum ReturnCodes + { + // Generic positive return codes + Success = 0x00, // service, function or command executed sucessfully + SuccessWithCrc = 0x01, // positive message confirmation, CRC over original data + // Generic negative return codes + MemoryError = 0xF1, // memory cannot be accessed or only with fault(s) + InvalidCommand = 0xF2, // server does not support the requested command. ets: also non-existing or protected resource + ImpossibleCommand = 0xF3, // command cannot be executed because a dependency is not fulfilled + ExceedsMaxApduLength = 0xF4, // data will not fit into a frame supported by this server + DataOverflow = 0xF5, // attempt to write data beyond what is reserved for the addressed resource + OutOfMinRange = 0xF6, // write value below minimum supported value + OutOfMaxRange = 0xF7, // write value exceeds maximum supported value + DataVoid = 0xF8, // request contains invalid data + TemporarilyNotAvailable = 0xF9, // data access not possible at this time + AccessWriteOnly = 0xFA, // read access to write-only resource + AccessReadOnly = 0xFB, // write access to read-only resource + AccessDenied = 0xFC, // access to recource is not allowed because of authorization/security + AddressVoid = 0xFD, // resource is not present, address does not exist + DataTypeConflict = 0xFE, // write access with wrong datatype (datapoint length) + GenericError = 0xFF // service, function or command failed + }; + const char* enum_name(const ReturnCodes enum_val); -enum SystemBroadcast -{ - SysBroadcast = 0, - Broadcast = 0x10, -}; -const char* enum_name(const SystemBroadcast enum_val); + enum Repetition + { + NoRepetiion = 0, + WasRepeated = 0, + RepetitionAllowed = 0x20, + WasNotRepeated = 0x20, + }; + const char* enum_name(Repetition enum_val); -enum Confirm -{ - ConfirmNoError = 0, - ConfirmError = 1, -}; -const char* enum_name(const Confirm enum_val); + enum SystemBroadcast + { + SysBroadcast = 0, + Broadcast = 0x10, + }; + const char* enum_name(const SystemBroadcast enum_val); -enum HopCountType -{ - UnlimitedRouting, //!< NPDU::hopCount is set to 7. This means that the frame never expires. This could be a problem if your bus contains a circle. - NetworkLayerParameter //!< use NetworkLayer::hopCount as NPDU::hopCount -}; -const char* enum_name(const HopCountType enum_val); + enum Confirm + { + ConfirmNoError = 0, + ConfirmError = 1, + }; + const char* enum_name(const Confirm enum_val); -enum TpduType -{ - DataBroadcast, - DataGroup, - DataInduvidual, - DataConnected, - Connect, - Disconnect, - Ack, - Nack, -}; -const char* enum_name(const TpduType enum_val); + enum HopCountType + { + UnlimitedRouting, //!< NPDU::hopCount is set to 7. This means that the frame never expires. This could be a problem if your bus contains a circle. + NetworkLayerParameter //!< use NetworkLayer::hopCount as NPDU::hopCount + }; + const char* enum_name(const HopCountType enum_val); -enum ApduType -{ - // Application Layer services on Multicast Communication Mode - GroupValueRead = 0x000, - GroupValueResponse = 0x040, - GroupValueWrite = 0x080, + enum TpduType + { + DataBroadcast, + DataGroup, + DataInduvidual, + DataConnected, + Connect, + Disconnect, + Ack, + Nack, + }; + const char* enum_name(const TpduType enum_val); - // Application Layer services on Broadcast Communication Mode - IndividualAddressWrite = 0x0c0, - IndividualAddressRead = 0x100, - IndividualAddressResponse = 0x140, - IndividualAddressSerialNumberRead = 0x3dc, - IndividualAddressSerialNumberResponse = 0x3dd, - IndividualAddressSerialNumberWrite = 0x3de, + enum ApduType + { + // Application Layer services on Multicast Communication Mode + GroupValueRead = 0x000, + GroupValueResponse = 0x040, + GroupValueWrite = 0x080, - // Application Layer Services on System Broadcast communication mode - SystemNetworkParameterRead = 0x1c8, - SystemNetworkParameterResponse = 0x1c9, - SystemNetworkParameterWrite = 0x1ca, - // Open media specific Application Layer Services on System Broadcast communication mode - DomainAddressWrite = 0x3e0, - DomainAddressRead = 0x3e1, - DomainAddressResponse = 0x3e2, - DomainAddressSelectiveRead = 0x3e3, - DomainAddressSerialNumberRead = 0x3ec, - DomainAddressSerialNumberResponse = 0x3ed, - DomainAddressSerialNumberWrite = 0x3ee, + // Application Layer services on Broadcast Communication Mode + IndividualAddressWrite = 0x0c0, + IndividualAddressRead = 0x100, + IndividualAddressResponse = 0x140, + IndividualAddressSerialNumberRead = 0x3dc, + IndividualAddressSerialNumberResponse = 0x3dd, + IndividualAddressSerialNumberWrite = 0x3de, - // Application Layer Services on Point-to-point Connection-Oriented Communication Mode (mandatory) - // Application Layer Services on Point-to-point Connectionless Communication Mode (either optional or mandatory) - ADCRead = 0x0180, - ADCResponse = 0x01C0, - PropertyValueExtRead = 0x1CC, - PropertyValueExtResponse = 0x1CD, - PropertyValueExtWriteCon = 0x1CE, - PropertyValueExtWriteConResponse = 0x1CF, - PropertyValueExtWriteUnCon = 0x1D0, - PropertyExtDescriptionRead = 0x1D2, - PropertyExtDescriptionResponse = 0x1D3, - FunctionPropertyExtCommand = 0x1D4, - FunctionPropertyExtState = 0x1D5, - FunctionPropertyExtStateResponse = 0x1D6, - MemoryExtWrite = 0x1FB, - MemoryExtWriteResponse = 0x1FC, - MemoryExtRead = 0x1FD, - MemoryExtReadResponse = 0x1FE, - MemoryRead = 0x200, - MemoryResponse = 0x240, - MemoryWrite = 0x280, - UserMemoryRead = 0x2C0, - UserMemoryResponse = 0x2C1, - UserMemoryWrite = 0x2C2, - UserManufacturerInfoRead = 0x2C5, - UserManufacturerInfoResponse = 0x2C6, - FunctionPropertyCommand = 0x2C7, - FunctionPropertyState = 0x2C8, - FunctionPropertyStateResponse = 0x2C9, - DeviceDescriptorRead = 0x300, - DeviceDescriptorResponse = 0x340, - Restart = 0x380, - RestartMasterReset = 0x381, - RoutingTableOpen = 0x3C0, - RoutingTableRead = 0x3C1, - RoutingTableReadResponse = 0x3C2, - RoutingTableWrite = 0x3C3, - MemoryRouterWrite = 0x3CA, - MemoryRouterReadResponse = 0x3C9, - AuthorizeRequest = 0x3d1, - AuthorizeResponse = 0x3d2, - KeyWrite = 0x3d3, - KeyResponse = 0x3d4, - PropertyValueRead = 0x3d5, - PropertyValueResponse = 0x3d6, - PropertyValueWrite = 0x3d7, - PropertyDescriptionRead = 0x3d8, - PropertyDescriptionResponse = 0x3d9, + // Application Layer Services on System Broadcast communication mode + SystemNetworkParameterRead = 0x1c8, + SystemNetworkParameterResponse = 0x1c9, + SystemNetworkParameterWrite = 0x1ca, + // Open media specific Application Layer Services on System Broadcast communication mode + DomainAddressWrite = 0x3e0, + DomainAddressRead = 0x3e1, + DomainAddressResponse = 0x3e2, + DomainAddressSelectiveRead = 0x3e3, + DomainAddressSerialNumberRead = 0x3ec, + DomainAddressSerialNumberResponse = 0x3ed, + DomainAddressSerialNumberWrite = 0x3ee, - // Secure Service - SecureService = 0x3F1 -}; -const char* enum_name(const ApduType enum_val); + // Application Layer Services on Point-to-point Connection-Oriented Communication Mode (mandatory) + // Application Layer Services on Point-to-point Connectionless Communication Mode (either optional or mandatory) + ADCRead = 0x0180, + ADCResponse = 0x01C0, + PropertyValueExtRead = 0x1CC, + PropertyValueExtResponse = 0x1CD, + PropertyValueExtWriteCon = 0x1CE, + PropertyValueExtWriteConResponse = 0x1CF, + PropertyValueExtWriteUnCon = 0x1D0, + PropertyExtDescriptionRead = 0x1D2, + PropertyExtDescriptionResponse = 0x1D3, + FunctionPropertyExtCommand = 0x1D4, + FunctionPropertyExtState = 0x1D5, + FunctionPropertyExtStateResponse = 0x1D6, + MemoryExtWrite = 0x1FB, + MemoryExtWriteResponse = 0x1FC, + MemoryExtRead = 0x1FD, + MemoryExtReadResponse = 0x1FE, + MemoryRead = 0x200, + MemoryResponse = 0x240, + MemoryWrite = 0x280, + UserMemoryRead = 0x2C0, + UserMemoryResponse = 0x2C1, + UserMemoryWrite = 0x2C2, + UserManufacturerInfoRead = 0x2C5, + UserManufacturerInfoResponse = 0x2C6, + FunctionPropertyCommand = 0x2C7, + FunctionPropertyState = 0x2C8, + FunctionPropertyStateResponse = 0x2C9, + DeviceDescriptorRead = 0x300, + DeviceDescriptorResponse = 0x340, + Restart = 0x380, + RestartMasterReset = 0x381, + RoutingTableOpen = 0x3C0, + RoutingTableRead = 0x3C1, + RoutingTableReadResponse = 0x3C2, + RoutingTableWrite = 0x3C3, + MemoryRouterWrite = 0x3CA, + MemoryRouterReadResponse = 0x3C9, + AuthorizeRequest = 0x3d1, + AuthorizeResponse = 0x3d2, + KeyWrite = 0x3d3, + KeyResponse = 0x3d4, + PropertyValueRead = 0x3d5, + PropertyValueResponse = 0x3d6, + PropertyValueWrite = 0x3d7, + PropertyDescriptionRead = 0x3d8, + PropertyDescriptionResponse = 0x3d9, -enum DataSecurity -{ - None, - Auth, - AuthConf -}; -const char* enum_name(const DataSecurity enum_val); + // Secure Service + SecureService = 0x3F1 + }; + const char* enum_name(const ApduType enum_val); -struct SecurityControl -{ - bool toolAccess; - DataSecurity dataSecurity; -}; + enum DataSecurity + { + None, + Auth, + AuthConf + }; + const char* enum_name(const DataSecurity enum_val); -enum RestartType -{ - BasicRestart = 0x0, - MasterReset = 0x1 -}; -const char* enum_name(const RestartType enum_val); + struct SecurityControl + { + bool toolAccess; + DataSecurity dataSecurity; + }; -enum EraseCode -{ - Void = 0x00, - ConfirmedRestart = 0x01, - FactoryReset = 0x02, - ResetIA = 0x03, - ResetAP = 0x04, - ResetParam = 0x05, - ResetLinks = 0x06, - FactoryResetWithoutIA = 0x07 -}; -const char* enum_name(const EraseCode enum_val); + enum RestartType + { + BasicRestart = 0x0, + MasterReset = 0x1 + }; + const char* enum_name(const RestartType enum_val); -enum DptMedium -{ - // DPT_Medium (20.1004), range 0-255 - // All other values are reserved. - KNX_TP1 = 0x00, - KNX_PL110 = 0x01, - KNX_RF = 0x02, - KNX_IP = 0x05 -}; -const char* enum_name(const DptMedium enum_val); + enum EraseCode + { + Void = 0x00, + ConfirmedRestart = 0x01, + FactoryReset = 0x02, + ResetIA = 0x03, + ResetAP = 0x04, + ResetParam = 0x05, + ResetLinks = 0x06, + FactoryResetWithoutIA = 0x07 + }; + const char* enum_name(const EraseCode enum_val); -enum LCGRPCONFIG -{ - GROUP_6FFF = 0b00000011, - GROUP_7000 = 0b00001100, - GROUP_REPEAT = 0b00010000, - GROUP_6FFFUNLOCK = 0b00000001, - GROUP_6FFFLOCK = 0b00000010, - GROUP_6FFFROUTE = 0b00000011, - GROUP_7000UNLOCK = 0b00000100, - GROUP_7000LOCK = 0b00001000, - GROUP_7000ROUTE = 0b00001100 -}; -const char* enum_name(const LCGRPCONFIG enum_val); + enum DptMedium + { + // DPT_Medium (20.1004), range 0-255 + // All other values are reserved. + KNX_TP1 = 0x00, + KNX_PL110 = 0x01, + KNX_RF = 0x02, + KNX_IP = 0x05 + }; + const char* enum_name(const DptMedium enum_val); -enum LCCONFIG -{ - PHYS_FRAME = 0b00000011, - PHYS_FRAME_UNLOCK = 0b00000001, - PHYS_FRAME_LOCK = 0b00000010, - PHYS_FRAME_ROUT = 0b00000011, - PHYS_REPEAT = 0b00000100, - BROADCAST_LOCK = 0b00001000, - BROADCAST_REPEAT = 0b00010000, - GROUP_IACK_ROUT = 0b00100000, - PHYS_IACK = 0b11000000, - PHYS_IACK_NORMAL = 0b01000000, - PHYS_IACK_ALL = 0b10000000, - PHYS_IACK_NACK = 0b11000000 -}; -const char* enum_name(const LCCONFIG enum_val); + enum LCGRPCONFIG + { + GROUP_6FFF = 0b00000011, + GROUP_7000 = 0b00001100, + GROUP_REPEAT = 0b00010000, + GROUP_6FFFUNLOCK = 0b00000001, + GROUP_6FFFLOCK = 0b00000010, + GROUP_6FFFROUTE = 0b00000011, + GROUP_7000UNLOCK = 0b00000100, + GROUP_7000LOCK = 0b00001000, + GROUP_7000ROUTE = 0b00001100 + }; + const char* enum_name(const LCGRPCONFIG enum_val); + + enum LCCONFIG + { + PHYS_FRAME = 0b00000011, + PHYS_FRAME_UNLOCK = 0b00000001, + PHYS_FRAME_LOCK = 0b00000010, + PHYS_FRAME_ROUT = 0b00000011, + PHYS_REPEAT = 0b00000100, + BROADCAST_LOCK = 0b00001000, + BROADCAST_REPEAT = 0b00010000, + GROUP_IACK_ROUT = 0b00100000, + PHYS_IACK = 0b11000000, + PHYS_IACK_NORMAL = 0b01000000, + PHYS_IACK_ALL = 0b10000000, + PHYS_IACK_NACK = 0b11000000 + }; + const char* enum_name(const LCCONFIG enum_val); -void print_ia(uint16_t ia); -void print_ga(uint16_t ga); \ No newline at end of file + void print_ia(uint16_t ia); + void print_ga(uint16_t ga); +} \ No newline at end of file diff --git a/src/knx/network_layer/network_layer.cpp b/src/knx/network_layer/network_layer.cpp index d9d0840d..6cc24c60 100644 --- a/src/knx/network_layer/network_layer.cpp +++ b/src/knx/network_layer/network_layer.cpp @@ -5,41 +5,43 @@ #include "../transport_layer/tpdu.h" #include "../bits.h" -NetworkLayer::NetworkLayer(DeviceObject& deviceObj, TransportLayer& layer) : - _deviceObj(deviceObj), - _transportLayer(layer) +namespace Knx { - _hopCount = _deviceObj.defaultHopCount(); -} - -uint8_t NetworkLayer::hopCount() const -{ - return _hopCount; -} - -bool NetworkLayer::isApciSystemBroadcast(APDU& apdu) -{ - switch (apdu.type()) + NetworkLayer::NetworkLayer(DeviceObject& deviceObj, TransportLayer& layer) : + _deviceObj(deviceObj), + _transportLayer(layer) { - // Application Layer Services on System Broadcast communication mode - case SystemNetworkParameterRead: - case SystemNetworkParameterResponse: - case SystemNetworkParameterWrite: - - // Open media specific Application Layer Services on System Broadcast communication mode - case DomainAddressSerialNumberRead: - case DomainAddressSerialNumberResponse: - case DomainAddressSerialNumberWrite: - case DomainAddressRead: - case DomainAddressSelectiveRead: - case DomainAddressResponse: - case DomainAddressWrite: - return true; + _hopCount = _deviceObj.defaultHopCount(); + } - default: - return false; + uint8_t NetworkLayer::hopCount() const + { + return _hopCount; } - return false; + bool NetworkLayer::isApciSystemBroadcast(APDU& apdu) + { + switch (apdu.type()) + { + // Application Layer Services on System Broadcast communication mode + case SystemNetworkParameterRead: + case SystemNetworkParameterResponse: + case SystemNetworkParameterWrite: + + // Open media specific Application Layer Services on System Broadcast communication mode + case DomainAddressSerialNumberRead: + case DomainAddressSerialNumberResponse: + case DomainAddressSerialNumberWrite: + case DomainAddressRead: + case DomainAddressSelectiveRead: + case DomainAddressResponse: + case DomainAddressWrite: + return true; + + default: + return false; + } + + return false; + } } - diff --git a/src/knx/network_layer/network_layer.h b/src/knx/network_layer/network_layer.h index b3cfa830..e2d0d3e4 100644 --- a/src/knx/network_layer/network_layer.h +++ b/src/knx/network_layer/network_layer.h @@ -7,41 +7,44 @@ #include -class DeviceObject; -class APDU; - -class NetworkLayer +namespace Knx { - friend class NetworkLayerEntity; - - public: - NetworkLayer(DeviceObject& deviceObj, TransportLayer& layer); - - uint8_t hopCount() const; - bool isApciSystemBroadcast(APDU& apdu); - - // from transport layer - virtual void dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) = 0; - virtual void dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) = 0; - virtual void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) = 0; - virtual void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) = 0; - - protected: - DeviceObject& _deviceObj; - TransportLayer& _transportLayer; - - // from entities - virtual void dataIndication(AckType ack, AddressType addType, uint16_t destination, FrameFormat format, NPDU& npdu, - Priority priority, uint16_t source, uint8_t srcIfIdx) = 0; - virtual void dataConfirm(AckType ack, AddressType addressType, uint16_t destination, FrameFormat format, Priority priority, - uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) = 0; - virtual void broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, - Priority priority, uint16_t source, uint8_t srcIfIdx) = 0; - virtual void broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) = 0; - virtual void systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, - Priority priority, uint16_t source, uint8_t srcIfIdx) = 0; - virtual void systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) = 0; - - private: - uint8_t _hopCount; // Network Layer Parameter hop_count for the device's own outgoing frames (default value from PID_ROUTING_COUNT) -}; + class DeviceObject; + class APDU; + + class NetworkLayer + { + friend class NetworkLayerEntity; + + public: + NetworkLayer(DeviceObject& deviceObj, TransportLayer& layer); + + uint8_t hopCount() const; + bool isApciSystemBroadcast(APDU& apdu); + + // from transport layer + virtual void dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) = 0; + virtual void dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) = 0; + virtual void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) = 0; + virtual void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) = 0; + + protected: + DeviceObject& _deviceObj; + TransportLayer& _transportLayer; + + // from entities + virtual void dataIndication(AckType ack, AddressType addType, uint16_t destination, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source, uint8_t srcIfIdx) = 0; + virtual void dataConfirm(AckType ack, AddressType addressType, uint16_t destination, FrameFormat format, Priority priority, + uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) = 0; + virtual void broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source, uint8_t srcIfIdx) = 0; + virtual void broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) = 0; + virtual void systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source, uint8_t srcIfIdx) = 0; + virtual void systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) = 0; + + private: + uint8_t _hopCount; // Network Layer Parameter hop_count for the device's own outgoing frames (default value from PID_ROUTING_COUNT) + }; +} \ No newline at end of file diff --git a/src/knx/network_layer/network_layer_device.cpp b/src/knx/network_layer/network_layer_device.cpp index b38a1ee6..6652034b 100644 --- a/src/knx/network_layer/network_layer_device.cpp +++ b/src/knx/network_layer/network_layer_device.cpp @@ -8,157 +8,160 @@ #define LOGGER Logger::logger("NetworkLayerDevice") -NetworkLayerDevice::NetworkLayerDevice(DeviceObject& deviceObj, TransportLayer& layer) : - NetworkLayer(deviceObj, layer), - _netLayerEntities { {*this, kInterfaceIndex} } +namespace Knx { -} + NetworkLayerDevice::NetworkLayerDevice(DeviceObject& deviceObj, TransportLayer& layer) : + NetworkLayer(deviceObj, layer), + _netLayerEntities { {*this, kInterfaceIndex} } + { + } -NetworkLayerEntity& NetworkLayerDevice::getInterface() -{ - return _netLayerEntities[kInterfaceIndex]; -} + NetworkLayerEntity& NetworkLayerDevice::getInterface() + { + return _netLayerEntities[kInterfaceIndex]; + } -void NetworkLayerDevice::dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) -{ - NPDU& npdu = tpdu.frame().npdu(); - - if (hopType == UnlimitedRouting) - npdu.hopCount(7); - else - npdu.hopCount(hopCount()); - - //if (tpdu.apdu().length() > 0) - //{ - // print.print("-> NL "); - // tpdu.apdu().printPDU(); - //} - LOGGER.info("dataIndividualRequest ", npdu); - _netLayerEntities[kInterfaceIndex].sendDataRequest(npdu, ack, destination, _deviceObj.individualAddress(), priority, IndividualAddress, Broadcast); -} - -void NetworkLayerDevice::dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) -{ - NPDU& npdu = tpdu.frame().npdu(); + void NetworkLayerDevice::dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) + { + NPDU& npdu = tpdu.frame().npdu(); + + if (hopType == UnlimitedRouting) + npdu.hopCount(7); + else + npdu.hopCount(hopCount()); + + //if (tpdu.apdu().length() > 0) + //{ + // print.print("-> NL "); + // tpdu.apdu().printPDU(); + //} + LOGGER.info("dataIndividualRequest ", npdu); + _netLayerEntities[kInterfaceIndex].sendDataRequest(npdu, ack, destination, _deviceObj.individualAddress(), priority, IndividualAddress, Broadcast); + } - if (hopType == UnlimitedRouting) - npdu.hopCount(7); - else - npdu.hopCount(hopCount()); + void NetworkLayerDevice::dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) + { + NPDU& npdu = tpdu.frame().npdu(); - LOGGER.info("dataGroupRequest ", npdu); - _netLayerEntities[kInterfaceIndex].sendDataRequest(npdu, ack, destination, _deviceObj.individualAddress(), priority, GroupAddress, Broadcast); -} + if (hopType == UnlimitedRouting) + npdu.hopCount(7); + else + npdu.hopCount(hopCount()); -void NetworkLayerDevice::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) -{ - NPDU& npdu = tpdu.frame().npdu(); + LOGGER.info("dataGroupRequest ", npdu); + _netLayerEntities[kInterfaceIndex].sendDataRequest(npdu, ack, destination, _deviceObj.individualAddress(), priority, GroupAddress, Broadcast); + } - if (hopType == UnlimitedRouting) - npdu.hopCount(7); - else - npdu.hopCount(hopCount()); + void NetworkLayerDevice::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) + { + NPDU& npdu = tpdu.frame().npdu(); - LOGGER.info("dataBroadcastRequest ", npdu); - _netLayerEntities[kInterfaceIndex].sendDataRequest(npdu, ack, 0, _deviceObj.individualAddress(), priority, GroupAddress, Broadcast); -} + if (hopType == UnlimitedRouting) + npdu.hopCount(7); + else + npdu.hopCount(hopCount()); -void NetworkLayerDevice::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) -{ - // for closed media like TP1 and IP - bool isClosedMedium = (_netLayerEntities[kInterfaceIndex].mediumType() == DptMedium::KNX_TP1) || (_netLayerEntities[kInterfaceIndex].mediumType() == DptMedium::KNX_IP); - SystemBroadcast broadcastType = (isClosedMedium && isApciSystemBroadcast(tpdu.apdu()) ? Broadcast : SysBroadcast); + LOGGER.info("dataBroadcastRequest ", npdu); + _netLayerEntities[kInterfaceIndex].sendDataRequest(npdu, ack, 0, _deviceObj.individualAddress(), priority, GroupAddress, Broadcast); + } - NPDU& npdu = tpdu.frame().npdu(); + void NetworkLayerDevice::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) + { + // for closed media like TP1 and IP + bool isClosedMedium = (_netLayerEntities[kInterfaceIndex].mediumType() == DptMedium::KNX_TP1) || (_netLayerEntities[kInterfaceIndex].mediumType() == DptMedium::KNX_IP); + SystemBroadcast broadcastType = (isClosedMedium && isApciSystemBroadcast(tpdu.apdu()) ? Broadcast : SysBroadcast); - if (hopType == UnlimitedRouting) - npdu.hopCount(7); - else - npdu.hopCount(hopCount()); + NPDU& npdu = tpdu.frame().npdu(); - LOGGER.info("dataSystemBroadcastRequest ", npdu); - _netLayerEntities[kInterfaceIndex].sendDataRequest(npdu, ack, 0, _deviceObj.individualAddress(), priority, GroupAddress, broadcastType); -} + if (hopType == UnlimitedRouting) + npdu.hopCount(7); + else + npdu.hopCount(hopCount()); -void NetworkLayerDevice::dataIndication(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) -{ - LOGGER.info("dataIndication ", npdu); - HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + LOGGER.info("dataSystemBroadcastRequest ", npdu); + _netLayerEntities[kInterfaceIndex].sendDataRequest(npdu, ack, 0, _deviceObj.individualAddress(), priority, GroupAddress, broadcastType); + } - if (addrType == IndividualAddress) + void NetworkLayerDevice::dataIndication(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) { - if (destination != _deviceObj.individualAddress()) + LOGGER.info("dataIndication ", npdu); + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + + if (addrType == IndividualAddress) + { + if (destination != _deviceObj.individualAddress()) + return; + + _transportLayer.dataIndividualIndication(destination, hopType, priority, source, npdu.tpdu()); return; + } - _transportLayer.dataIndividualIndication(destination, hopType, priority, source, npdu.tpdu()); - return; + // group-address type + if (destination != 0) + { + _transportLayer.dataGroupIndication(destination, hopType, priority, source, npdu.tpdu()); + return; + } } - // group-address type - if (destination != 0) + void NetworkLayerDevice::dataConfirm(AckType ack, AddressType addressType, uint16_t destination, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) { - _transportLayer.dataGroupIndication(destination, hopType, priority, source, npdu.tpdu()); - return; - } -} + LOGGER.info("dataConfirm ", npdu); + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; -void NetworkLayerDevice::dataConfirm(AckType ack, AddressType addressType, uint16_t destination, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) -{ - LOGGER.info("dataConfirm ", npdu); - HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + if (addressType == IndividualAddress) + { + _transportLayer.dataIndividualConfirm(ack, destination, hopType, priority, npdu.tpdu(), status); + return; + } - if (addressType == IndividualAddress) + // group-address type + if (destination != 0) + { + _transportLayer.dataGroupConfirm(ack, source, destination, hopType, priority, npdu.tpdu(), status); + return; + } + } + + void NetworkLayerDevice::broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) { - _transportLayer.dataIndividualConfirm(ack, destination, hopType, priority, npdu.tpdu(), status); - return; + LOGGER.info("broadcastIndication ", npdu); + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + DptMedium mediumType = _netLayerEntities[srcIfIdx].mediumType(); + + // for closed media like TP1 and IP there is no system broadcast + // however we must be able to access those APCI via broadcast mode + // so we "translate" it to system broadcast like a coupler does when routing + // between closed and open media + if ( ((mediumType == DptMedium::KNX_TP1) || (mediumType == DptMedium::KNX_IP)) && + isApciSystemBroadcast(npdu.tpdu().apdu())) + { + npdu.frame().systemBroadcast(SysBroadcast); + _transportLayer.dataSystemBroadcastIndication(hopType, priority, source, npdu.tpdu()); + return; + } + + _transportLayer.dataBroadcastIndication(hopType, priority, source, npdu.tpdu()); } - // group-address type - if (destination != 0) + void NetworkLayerDevice::broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) { - _transportLayer.dataGroupConfirm(ack, source, destination, hopType, priority, npdu.tpdu(), status); - return; + LOGGER.info("broadcastConfirm ", npdu); + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + _transportLayer.dataBroadcastConfirm(ack, hopType, priority, npdu.tpdu(), status); } -} -void NetworkLayerDevice::broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) -{ - LOGGER.info("broadcastIndication ", npdu); - HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; - DptMedium mediumType = _netLayerEntities[srcIfIdx].mediumType(); - - // for closed media like TP1 and IP there is no system broadcast - // however we must be able to access those APCI via broadcast mode - // so we "translate" it to system broadcast like a coupler does when routing - // between closed and open media - if ( ((mediumType == DptMedium::KNX_TP1) || (mediumType == DptMedium::KNX_IP)) && - isApciSystemBroadcast(npdu.tpdu().apdu())) + void NetworkLayerDevice::systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) { - npdu.frame().systemBroadcast(SysBroadcast); + LOGGER.info("systemBroadcastIndication ", npdu); + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; _transportLayer.dataSystemBroadcastIndication(hopType, priority, source, npdu.tpdu()); - return; } - _transportLayer.dataBroadcastIndication(hopType, priority, source, npdu.tpdu()); -} - -void NetworkLayerDevice::broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) -{ - LOGGER.info("broadcastConfirm ", npdu); - HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; - _transportLayer.dataBroadcastConfirm(ack, hopType, priority, npdu.tpdu(), status); -} - -void NetworkLayerDevice::systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) -{ - LOGGER.info("systemBroadcastIndication ", npdu); - HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; - _transportLayer.dataSystemBroadcastIndication(hopType, priority, source, npdu.tpdu()); -} - -void NetworkLayerDevice::systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) -{ - LOGGER.info("systemBroadcastConfirm ", npdu); - HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; - _transportLayer.dataSystemBroadcastConfirm(ack, hopType, npdu.tpdu(), priority, status); -} + void NetworkLayerDevice::systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) + { + LOGGER.info("systemBroadcastConfirm ", npdu); + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + _transportLayer.dataSystemBroadcastConfirm(ack, hopType, npdu.tpdu(), priority, status); + } +} \ No newline at end of file diff --git a/src/knx/network_layer/network_layer_device.h b/src/knx/network_layer/network_layer_device.h index b452a76b..9e1743a3 100644 --- a/src/knx/network_layer/network_layer_device.h +++ b/src/knx/network_layer/network_layer_device.h @@ -7,38 +7,41 @@ #include -class DeviceObject; - -class NetworkLayerDevice : public NetworkLayer +namespace Knx { - friend class NetworkLayerEntity; - - public: - NetworkLayerDevice(DeviceObject& deviceObj, TransportLayer& layer); - - NetworkLayerEntity& getInterface(); - - // from transport layer - void dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override; - void dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override; - void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override; - void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override; - - private: - // from entities - void dataIndication(AckType ack, AddressType addType, uint16_t destination, FrameFormat format, NPDU& npdu, - Priority priority, uint16_t source, uint8_t srcIfIdx) override; - void dataConfirm(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, Priority priority, - uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override; - void broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, - Priority priority, uint16_t source, uint8_t srcIfIdx) override; - void broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override; - void systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, - Priority priority, uint16_t source, uint8_t srcIfIdx) override; - void systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override; - - // Support only a single physical interface for normal devices - NetworkLayerEntity _netLayerEntities[1]; - - static constexpr uint8_t kInterfaceIndex = 0; -}; + class DeviceObject; + + class NetworkLayerDevice : public NetworkLayer + { + friend class NetworkLayerEntity; + + public: + NetworkLayerDevice(DeviceObject& deviceObj, TransportLayer& layer); + + NetworkLayerEntity& getInterface(); + + // from transport layer + void dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override; + void dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override; + void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override; + void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override; + + private: + // from entities + void dataIndication(AckType ack, AddressType addType, uint16_t destination, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source, uint8_t srcIfIdx) override; + void dataConfirm(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, Priority priority, + uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override; + void broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source, uint8_t srcIfIdx) override; + void broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override; + void systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source, uint8_t srcIfIdx) override; + void systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override; + + // Support only a single physical interface for normal devices + NetworkLayerEntity _netLayerEntities[1]; + + static constexpr uint8_t kInterfaceIndex = 0; + }; +} \ No newline at end of file diff --git a/src/knx/network_layer/network_layer_entity.cpp b/src/knx/network_layer/network_layer_entity.cpp index a0ccebec..00415dbe 100644 --- a/src/knx/network_layer/network_layer_entity.cpp +++ b/src/knx/network_layer/network_layer_entity.cpp @@ -5,71 +5,74 @@ #include "../datalink_layer/data_link_layer.h" #include "../bits.h" -NetworkLayerEntity::NetworkLayerEntity(NetworkLayer& netLayer, uint8_t entityIndex) : _netLayer(netLayer), _entityIndex(entityIndex) +namespace Knx { -} + NetworkLayerEntity::NetworkLayerEntity(NetworkLayer& netLayer, uint8_t entityIndex) : _netLayer(netLayer), _entityIndex(entityIndex) + { + } -void NetworkLayerEntity::dataLinkLayer(DataLinkLayer& layer) -{ - _dataLinkLayer = &layer; -} + void NetworkLayerEntity::dataLinkLayer(DataLinkLayer& layer) + { + _dataLinkLayer = &layer; + } -DataLinkLayer& NetworkLayerEntity::dataLinkLayer() -{ - return *_dataLinkLayer; -} + DataLinkLayer& NetworkLayerEntity::dataLinkLayer() + { + return *_dataLinkLayer; + } -NetworkLayer& NetworkLayerEntity::networkLayer() -{ - return _netLayer; -} + NetworkLayer& NetworkLayerEntity::networkLayer() + { + return _netLayer; + } -DptMedium NetworkLayerEntity::mediumType() const -{ - return _dataLinkLayer->mediumType(); -} + DptMedium NetworkLayerEntity::mediumType() const + { + return _dataLinkLayer->mediumType(); + } -uint8_t NetworkLayerEntity::getEntityIndex() -{ - return _entityIndex; -} + uint8_t NetworkLayerEntity::getEntityIndex() + { + return _entityIndex; + } -void NetworkLayerEntity::dataIndication(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source) -{ - _netLayer.dataIndication(ack, addrType, destination, format, npdu, priority, source, _entityIndex); -} + void NetworkLayerEntity::dataIndication(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source) + { + _netLayer.dataIndication(ack, addrType, destination, format, npdu, priority, source, _entityIndex); + } -void NetworkLayerEntity::dataConfirm(AckType ack, AddressType addressType, uint16_t destination, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status) -{ - _netLayer.dataConfirm(ack, addressType, destination, format, priority, source, npdu, status, _entityIndex); -} + void NetworkLayerEntity::dataConfirm(AckType ack, AddressType addressType, uint16_t destination, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status) + { + _netLayer.dataConfirm(ack, addressType, destination, format, priority, source, npdu, status, _entityIndex); + } -void NetworkLayerEntity::broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source) -{ - _netLayer.broadcastIndication(ack, format, npdu, priority, source, _entityIndex); -} + void NetworkLayerEntity::broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source) + { + _netLayer.broadcastIndication(ack, format, npdu, priority, source, _entityIndex); + } -void NetworkLayerEntity::broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status) -{ - _netLayer.broadcastConfirm(ack, format, priority, source, npdu, status, _entityIndex); -} + void NetworkLayerEntity::broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status) + { + _netLayer.broadcastConfirm(ack, format, priority, source, npdu, status, _entityIndex); + } -void NetworkLayerEntity::systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source) -{ - _netLayer.systemBroadcastIndication(ack, format, npdu, priority, source, _entityIndex); -} + void NetworkLayerEntity::systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source) + { + _netLayer.systemBroadcastIndication(ack, format, npdu, priority, source, _entityIndex); + } -void NetworkLayerEntity::systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status) -{ - _netLayer.systemBroadcastConfirm(ack, format, priority, source, npdu, status, _entityIndex); -} + void NetworkLayerEntity::systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status) + { + _netLayer.systemBroadcastConfirm(ack, format, priority, source, npdu, status, _entityIndex); + } -void NetworkLayerEntity::sendDataRequest(NPDU& npdu, AckType ack, uint16_t destination, uint16_t source, Priority priority, AddressType addrType, SystemBroadcast systemBroadcast, bool doNotRepeat) -{ - FrameFormat frameFormat = npdu.octetCount() > 15 ? ExtendedFrame : StandardFrame; + void NetworkLayerEntity::sendDataRequest(NPDU& npdu, AckType ack, uint16_t destination, uint16_t source, Priority priority, AddressType addrType, SystemBroadcast systemBroadcast, bool doNotRepeat) + { + FrameFormat frameFormat = npdu.octetCount() > 15 ? ExtendedFrame : StandardFrame; - if (systemBroadcast == Broadcast) - _dataLinkLayer->dataRequest(ack, addrType, destination, source, frameFormat, priority, npdu); - else - _dataLinkLayer->systemBroadcastRequest(ack, frameFormat, priority, npdu, source); -} + if (systemBroadcast == Broadcast) + _dataLinkLayer->dataRequest(ack, addrType, destination, source, frameFormat, priority, npdu); + else + _dataLinkLayer->systemBroadcastRequest(ack, frameFormat, priority, npdu, source); + } +} \ No newline at end of file diff --git a/src/knx/network_layer/network_layer_entity.h b/src/knx/network_layer/network_layer_entity.h index 5444a11e..3cad54b2 100644 --- a/src/knx/network_layer/network_layer_entity.h +++ b/src/knx/network_layer/network_layer_entity.h @@ -5,41 +5,44 @@ #include -class DataLinkLayer; -class NetworkLayer; - -class NetworkLayerEntity +namespace Knx { - friend class NetworkLayerCoupler; - friend class NetworkLayerDevice; - - public: - NetworkLayerEntity(NetworkLayer& netLayer, uint8_t entityIndex); - - void dataLinkLayer(DataLinkLayer& layer); - DataLinkLayer& dataLinkLayer(); - NetworkLayer& networkLayer(); - - DptMedium mediumType() const; - uint8_t getEntityIndex(); - - // from data link layer - void dataIndication(AckType ack, AddressType addType, uint16_t destination, FrameFormat format, NPDU& npdu, - Priority priority, uint16_t source); - void dataConfirm(AckType ack, AddressType addressType, uint16_t destination, FrameFormat format, Priority priority, - uint16_t source, NPDU& npdu, bool status); - void broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, - Priority priority, uint16_t source); - void broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status); - void systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, - Priority priority, uint16_t source); - void systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status); - - private: - // From network layer - void sendDataRequest(NPDU& npdu, AckType ack, uint16_t destination, uint16_t source, Priority priority, AddressType addrType, SystemBroadcast systemBroadcast, bool doNotRepeat = false); - - DataLinkLayer* _dataLinkLayer = 0; - NetworkLayer& _netLayer; - uint8_t _entityIndex; -}; + class DataLinkLayer; + class NetworkLayer; + + class NetworkLayerEntity + { + friend class NetworkLayerCoupler; + friend class NetworkLayerDevice; + + public: + NetworkLayerEntity(NetworkLayer& netLayer, uint8_t entityIndex); + + void dataLinkLayer(DataLinkLayer& layer); + DataLinkLayer& dataLinkLayer(); + NetworkLayer& networkLayer(); + + DptMedium mediumType() const; + uint8_t getEntityIndex(); + + // from data link layer + void dataIndication(AckType ack, AddressType addType, uint16_t destination, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source); + void dataConfirm(AckType ack, AddressType addressType, uint16_t destination, FrameFormat format, Priority priority, + uint16_t source, NPDU& npdu, bool status); + void broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source); + void broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status); + void systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source); + void systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status); + + private: + // From network layer + void sendDataRequest(NPDU& npdu, AckType ack, uint16_t destination, uint16_t source, Priority priority, AddressType addrType, SystemBroadcast systemBroadcast, bool doNotRepeat = false); + + DataLinkLayer* _dataLinkLayer = 0; + NetworkLayer& _netLayer; + uint8_t _entityIndex; + }; +} \ No newline at end of file diff --git a/src/knx/network_layer/npdu.cpp b/src/knx/network_layer/npdu.cpp index a99d1f32..cce3b3d0 100644 --- a/src/knx/network_layer/npdu.cpp +++ b/src/knx/network_layer/npdu.cpp @@ -5,52 +5,55 @@ #include -NPDU::NPDU(uint8_t* data, CemiFrame& frame): _data(data), _frame(frame) -{ -} - - -uint8_t NPDU::octetCount() const -{ - return _data[0]; -} - -void NPDU::octetCount(uint8_t value) -{ - _data[0] = value; -} - -uint8_t NPDU::length() const -{ - return _data[0] + 2; // +1 for length field, +1 for TCPI -} - -uint8_t NPDU::hopCount() const -{ - return _frame.hopCount(); -} - -void NPDU::hopCount(uint8_t value) -{ - _frame.hopCount(value); -} - -CemiFrame& NPDU::frame() -{ - return _frame; -} - -TPDU& NPDU::tpdu() -{ - return _frame.tpdu(); -} - -void NPDU::printIt() const -{ +namespace Knx +{ + NPDU::NPDU(uint8_t* data, CemiFrame& frame): _data(data), _frame(frame) + { + } + + + uint8_t NPDU::octetCount() const + { + return _data[0]; + } + + void NPDU::octetCount(uint8_t value) + { + _data[0] = value; + } + + uint8_t NPDU::length() const + { + return _data[0] + 2; // +1 for length field, +1 for TCPI + } + + uint8_t NPDU::hopCount() const + { + return _frame.hopCount(); + } + + void NPDU::hopCount(uint8_t value) + { + _frame.hopCount(value); + } + + CemiFrame& NPDU::frame() + { + return _frame; + } + + TPDU& NPDU::tpdu() + { + return _frame.tpdu(); + } + + void NPDU::printIt() const + { #ifndef KNX_NO_PRINT - print("NPDU: Octetcount: "); - print(octetCount()); - print(" hopCount "); - print(hopCount()); + print("NPDU: Octetcount: "); + print(octetCount()); + print(" hopCount "); + print(hopCount()); #endif + } } \ No newline at end of file diff --git a/src/knx/network_layer/npdu.h b/src/knx/network_layer/npdu.h index 75ee8774..39ee800f 100644 --- a/src/knx/network_layer/npdu.h +++ b/src/knx/network_layer/npdu.h @@ -4,27 +4,30 @@ #include -class CemiFrame; -class TPDU; - -class NPDU : public IPrintable +namespace Knx { - friend class CemiFrame; + class CemiFrame; + class TPDU; + + class NPDU : public IPrintable + { + friend class CemiFrame; - public: - uint8_t octetCount() const; - void octetCount(uint8_t value); - uint8_t length() const; - uint8_t hopCount() const; - void hopCount(uint8_t value); - CemiFrame& frame(); - TPDU& tpdu(); - void printIt() const; + public: + uint8_t octetCount() const; + void octetCount(uint8_t value); + uint8_t length() const; + uint8_t hopCount() const; + void hopCount(uint8_t value); + CemiFrame& frame(); + TPDU& tpdu(); + void printIt() const; - protected: - NPDU(uint8_t* data, CemiFrame& frame); + protected: + NPDU(uint8_t* data, CemiFrame& frame); - private: - uint8_t* _data = 0; - CemiFrame& _frame; -}; \ No newline at end of file + private: + uint8_t* _data = 0; + CemiFrame& _frame; + }; +} \ No newline at end of file diff --git a/src/knx/platform/arduino_platform.cpp b/src/knx/platform/arduino_platform.cpp index 25cc725a..cbc816ff 100644 --- a/src/knx/platform/arduino_platform.cpp +++ b/src/knx/platform/arduino_platform.cpp @@ -6,306 +6,309 @@ #include #endif +namespace Knx +{ #ifndef KNX_NO_PRINT Stream* ArduinoPlatform::SerialDebug = &KNX_DEBUG_SERIAL; #endif -ArduinoPlatform::ArduinoPlatform() : _knxSerial(nullptr) -{ -} + ArduinoPlatform::ArduinoPlatform() : _knxSerial(nullptr) + { + } -ArduinoPlatform::ArduinoPlatform(HardwareSerial* knxSerial) : _knxSerial(knxSerial) -{ -} + ArduinoPlatform::ArduinoPlatform(HardwareSerial* knxSerial) : _knxSerial(knxSerial) + { + } -void ArduinoPlatform::fatalError() -{ - while (true) + void ArduinoPlatform::fatalError() { + while (true) + { #ifdef KNX_LED - static const long LED_BLINK_PERIOD = 200; + static const long LED_BLINK_PERIOD = 200; - if ((millis() % LED_BLINK_PERIOD) > (LED_BLINK_PERIOD / 2)) - digitalWrite(KNX_LED, HIGH); - else - digitalWrite(KNX_LED, LOW); + if ((millis() % LED_BLINK_PERIOD) > (LED_BLINK_PERIOD / 2)) + digitalWrite(KNX_LED, HIGH); + else + digitalWrite(KNX_LED, LOW); #endif + } } -} - -void ArduinoPlatform::knxUart( HardwareSerial* serial ) -{ - if (_knxSerial) - closeUart(); - _knxSerial = serial; - setupUart(); -} + void ArduinoPlatform::knxUart( HardwareSerial* serial ) + { + if (_knxSerial) + closeUart(); -HardwareSerial* ArduinoPlatform::knxUart() -{ - return _knxSerial; -} + _knxSerial = serial; + setupUart(); + } -void ArduinoPlatform::setupUart() -{ - _knxSerial->begin(19200, SERIAL_8E1); + HardwareSerial* ArduinoPlatform::knxUart() + { + return _knxSerial; + } - while (!_knxSerial) - ; -} + void ArduinoPlatform::setupUart() + { + _knxSerial->begin(19200, SERIAL_8E1); + while (!_knxSerial) + ; + } -void ArduinoPlatform::closeUart() -{ - _knxSerial->end(); -} + void ArduinoPlatform::closeUart() + { + _knxSerial->end(); + } -int ArduinoPlatform::uartAvailable() -{ - return _knxSerial->available(); -} + int ArduinoPlatform::uartAvailable() + { + return _knxSerial->available(); + } -size_t ArduinoPlatform::writeUart(const uint8_t data) -{ - //printHex("write(data); -} + size_t ArduinoPlatform::writeUart(const uint8_t data) + { + //printHex("write(data); + } -size_t ArduinoPlatform::writeUart(const uint8_t* buffer, size_t size) -{ - //printHex("write(buffer, size); -} + size_t ArduinoPlatform::writeUart(const uint8_t* buffer, size_t size) + { + //printHex("write(buffer, size); + } -int ArduinoPlatform::readUart() -{ - int val = _knxSerial->read(); - //if(val > 0) - // printHex("p>", (uint8_t*)&val, 1); - return val; -} + int ArduinoPlatform::readUart() + { + int val = _knxSerial->read(); + //if(val > 0) + // printHex("p>", (uint8_t*)&val, 1); + return val; + } -size_t ArduinoPlatform::readBytesUart(uint8_t* buffer, size_t length) -{ - size_t toRead = length; - uint8_t* pos = buffer; - while (toRead > 0) + size_t ArduinoPlatform::readBytesUart(uint8_t* buffer, size_t length) { - size_t val = _knxSerial->readBytes(pos, toRead); - pos += val; - toRead -= val; + size_t toRead = length; + uint8_t* pos = buffer; + + while (toRead > 0) + { + size_t val = _knxSerial->readBytes(pos, toRead); + pos += val; + toRead -= val; + } + + //printHex("p>", buffer, length); + return length; } - //printHex("p>", buffer, length); - return length; -} - -void ArduinoPlatform::flushUart() -{ - return _knxSerial->flush(); -} + void ArduinoPlatform::flushUart() + { + return _knxSerial->flush(); + } #ifndef KNX_NO_SPI -void ArduinoPlatform::setupSpi() -{ - SPI.begin(); - SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); -} + void ArduinoPlatform::setupSpi() + { + SPI.begin(); + SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); + } -void ArduinoPlatform::closeSpi() -{ - SPI.endTransaction(); - SPI.end(); -} + void ArduinoPlatform::closeSpi() + { + SPI.endTransaction(); + SPI.end(); + } -int ArduinoPlatform::readWriteSpi(uint8_t* data, size_t len) -{ - SPI.transfer(data, len); - return 0; -} + int ArduinoPlatform::readWriteSpi(uint8_t* data, size_t len) + { + SPI.transfer(data, len); + return 0; + } #endif #ifndef KNX_NO_PRINT -void printUint64(uint64_t value, int base = DEC) -{ - char buf[8 * sizeof(uint64_t) + 1]; - char* str = &buf[sizeof(buf) - 1]; - *str = '\0'; + void printUint64(uint64_t value, int base = DEC) + { + char buf[8 * sizeof(uint64_t) + 1]; + char* str = &buf[sizeof(buf) - 1]; + *str = '\0'; - uint64_t n = value; + uint64_t n = value; - do - { - char c = n % base; - n /= base; + do + { + char c = n % base; + n /= base; - *--str = c < 10 ? c + '0' : c + 'A' - 10; - } while (n > 0); + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while (n > 0); - print(str); -} + print(str); + } -void print(const char* s) -{ - ArduinoPlatform::SerialDebug->print(s); -} -void print(char c) -{ - ArduinoPlatform::SerialDebug->print(c); -} + void print(const char* s) + { + ArduinoPlatform::SerialDebug->print(s); + } + void print(char c) + { + ArduinoPlatform::SerialDebug->print(c); + } -void print(unsigned char num) -{ - ArduinoPlatform::SerialDebug->print(num); -} + void print(unsigned char num) + { + ArduinoPlatform::SerialDebug->print(num); + } -void print(unsigned char num, int base) -{ - ArduinoPlatform::SerialDebug->print(num, base); -} + void print(unsigned char num, int base) + { + ArduinoPlatform::SerialDebug->print(num, base); + } -void print(int num) -{ - ArduinoPlatform::SerialDebug->print(num); -} + void print(int num) + { + ArduinoPlatform::SerialDebug->print(num); + } -void print(int num, int base) -{ - ArduinoPlatform::SerialDebug->print(num, base); -} + void print(int num, int base) + { + ArduinoPlatform::SerialDebug->print(num, base); + } -void print(unsigned int num) -{ - ArduinoPlatform::SerialDebug->print(num); -} + void print(unsigned int num) + { + ArduinoPlatform::SerialDebug->print(num); + } -void print(unsigned int num, int base) -{ - ArduinoPlatform::SerialDebug->print(num, base); -} + void print(unsigned int num, int base) + { + ArduinoPlatform::SerialDebug->print(num, base); + } -void print(long num) -{ - ArduinoPlatform::SerialDebug->print(num); -} + void print(long num) + { + ArduinoPlatform::SerialDebug->print(num); + } -void print(long num, int base) -{ - ArduinoPlatform::SerialDebug->print(num, base); -} + void print(long num, int base) + { + ArduinoPlatform::SerialDebug->print(num, base); + } -void print(unsigned long num) -{ - ArduinoPlatform::SerialDebug->print(num); -} + void print(unsigned long num) + { + ArduinoPlatform::SerialDebug->print(num); + } -void print(unsigned long num, int base) -{ - ArduinoPlatform::SerialDebug->print(num, base); -} + void print(unsigned long num, int base) + { + ArduinoPlatform::SerialDebug->print(num, base); + } -void print(unsigned long long num) -{ - printUint64(num); -} + void print(unsigned long long num) + { + printUint64(num); + } -void print(unsigned long long num, int base) -{ - printUint64(num, base); -} + void print(unsigned long long num, int base) + { + printUint64(num, base); + } -void print(double num) -{ - ArduinoPlatform::SerialDebug->print(num); -} + void print(double num) + { + ArduinoPlatform::SerialDebug->print(num); + } -void println(const char* s) -{ - ArduinoPlatform::SerialDebug->println(s); -} + void println(const char* s) + { + ArduinoPlatform::SerialDebug->println(s); + } -void println(char c) -{ - ArduinoPlatform::SerialDebug->println(c); -} + void println(char c) + { + ArduinoPlatform::SerialDebug->println(c); + } -void println(unsigned char num) -{ - ArduinoPlatform::SerialDebug->println(num); -} + void println(unsigned char num) + { + ArduinoPlatform::SerialDebug->println(num); + } -void println(unsigned char num, int base) -{ - ArduinoPlatform::SerialDebug->println(num, base); -} + void println(unsigned char num, int base) + { + ArduinoPlatform::SerialDebug->println(num, base); + } -void println(int num) -{ - ArduinoPlatform::SerialDebug->println(num); -} + void println(int num) + { + ArduinoPlatform::SerialDebug->println(num); + } -void println(int num, int base) -{ - ArduinoPlatform::SerialDebug->println(num, base); -} + void println(int num, int base) + { + ArduinoPlatform::SerialDebug->println(num, base); + } -void println(unsigned int num) -{ - ArduinoPlatform::SerialDebug->println(num); -} + void println(unsigned int num) + { + ArduinoPlatform::SerialDebug->println(num); + } -void println(unsigned int num, int base) -{ - ArduinoPlatform::SerialDebug->println(num, base); -} + void println(unsigned int num, int base) + { + ArduinoPlatform::SerialDebug->println(num, base); + } -void println(long num) -{ - ArduinoPlatform::SerialDebug->println(num); -} + void println(long num) + { + ArduinoPlatform::SerialDebug->println(num); + } -void println(long num, int base) -{ - ArduinoPlatform::SerialDebug->println(num, base); -} + void println(long num, int base) + { + ArduinoPlatform::SerialDebug->println(num, base); + } -void println(unsigned long num) -{ - ArduinoPlatform::SerialDebug->println(num); -} + void println(unsigned long num) + { + ArduinoPlatform::SerialDebug->println(num); + } -void println(unsigned long num, int base) -{ - ArduinoPlatform::SerialDebug->println(num, base); -} + void println(unsigned long num, int base) + { + ArduinoPlatform::SerialDebug->println(num, base); + } -void println(unsigned long long num) -{ - printUint64(num); - println(""); -} + void println(unsigned long long num) + { + printUint64(num); + println(""); + } -void println(unsigned long long num, int base) -{ - printUint64(num, base); - println(""); -} + void println(unsigned long long num, int base) + { + printUint64(num, base); + println(""); + } -void println(double num) -{ - ArduinoPlatform::SerialDebug->println(num); -} + void println(double num) + { + ArduinoPlatform::SerialDebug->println(num); + } -void println(void) -{ - ArduinoPlatform::SerialDebug->println(); -} + void println(void) + { + ArduinoPlatform::SerialDebug->println(); + } #endif // KNX_NO_PRINT +} \ No newline at end of file diff --git a/src/knx/platform/arduino_platform.h b/src/knx/platform/arduino_platform.h index 9e2e9933..c9d98662 100644 --- a/src/knx/platform/arduino_platform.h +++ b/src/knx/platform/arduino_platform.h @@ -6,37 +6,40 @@ #define KNX_DEBUG_SERIAL Serial #endif -class ArduinoPlatform : public Platform +namespace Knx { - public: - ArduinoPlatform(); - ArduinoPlatform(HardwareSerial* knxSerial); + class ArduinoPlatform : public Platform + { + public: + ArduinoPlatform(); + ArduinoPlatform(HardwareSerial* knxSerial); - // basic stuff - void fatalError(); + // basic stuff + void fatalError(); - //uart - virtual void knxUart( HardwareSerial* serial); - virtual HardwareSerial* knxUart(); - virtual void setupUart(); - virtual void closeUart(); - virtual int uartAvailable(); - virtual size_t writeUart(const uint8_t data); - virtual size_t writeUart(const uint8_t* buffer, size_t size); - virtual int readUart(); - virtual size_t readBytesUart(uint8_t* buffer, size_t length); - virtual void flushUart(); + //uart + virtual void knxUart( HardwareSerial* serial); + virtual HardwareSerial* knxUart(); + virtual void setupUart(); + virtual void closeUart(); + virtual int uartAvailable(); + virtual size_t writeUart(const uint8_t data); + virtual size_t writeUart(const uint8_t* buffer, size_t size); + virtual int readUart(); + virtual size_t readBytesUart(uint8_t* buffer, size_t length); + virtual void flushUart(); - //spi + //spi #ifndef KNX_NO_SPI - void setupSpi() override; - void closeSpi() override; - int readWriteSpi (uint8_t* data, size_t len) override; + void setupSpi() override; + void closeSpi() override; + int readWriteSpi (uint8_t* data, size_t len) override; #endif #ifndef KNX_NO_PRINT - static Stream* SerialDebug; + static Stream* SerialDebug; #endif - protected: - HardwareSerial* _knxSerial; -}; + protected: + HardwareSerial* _knxSerial; + }; +} \ No newline at end of file diff --git a/src/knx/platform/cc1310_platform.cpp b/src/knx/platform/cc1310_platform.cpp index 17fda5a4..f2950fcd 100644 --- a/src/knx/platform/cc1310_platform.cpp +++ b/src/knx/platform/cc1310_platform.cpp @@ -16,577 +16,579 @@ #include "knx/bits.h" #include "cc1310_platform.h" -//#define printf(args...) (SEGGER_RTT_printf(0, args)) -//#define PRINT_RTT +namespace Knx +{ + //#define printf(args...) (SEGGER_RTT_printf(0, args)) + //#define PRINT_RTT #define PRINT_UART -static uint8_t serialNumber[6]; -// KNX_FLASH_SIZE shall be defined in CMakeLists.txt for example. It is also used in class Memory in memory.cpp -static uint8_t NVS_buffer[KNX_FLASH_SIZE]; - -static UART_Handle uart; - -static NVS_Handle nvsHandle; + static uint8_t serialNumber[6]; + // KNX_FLASH_SIZE shall be defined in CMakeLists.txt for example. It is also used in class Memory in memory.cpp + static uint8_t NVS_buffer[KNX_FLASH_SIZE]; -static ClockP_Handle clk0Handle; -static ClockP_Struct clk0Struct; -static volatile uint32_t msCounter = 0; - -static void clk0Fxn(uintptr_t arg0) -{ - msCounter++; -} - -static void setupClock() -{ - ClockP_Params clkParams; - ClockP_Params_init(&clkParams); - clkParams.period = 1000 / ClockP_tickPeriod; - clkParams.startFlag = true; - ClockP_construct(&clk0Struct, (ClockP_Fxn)clk0Fxn, 1000 / ClockP_tickPeriod, &clkParams); - clk0Handle = ClockP_handle(&clk0Struct); -} + static UART_Handle uart; -static void setupGPIO() -{ - /* Configure the LED and button pins */ - GPIO_setConfig(Board_GPIO_LED0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW); - GPIO_setConfig(Board_GPIO_LED1, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW); - GPIO_setConfig(Board_GPIO_BUTTON0, GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING); - GPIO_setConfig(Board_GPIO_BUTTON1, GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING); -} + static NVS_Handle nvsHandle; -static void setupUART() -{ - UART_Params uartParams; - UART_Params_init(&uartParams); - uartParams.writeDataMode = UART_DATA_BINARY; - uartParams.readDataMode = UART_DATA_BINARY; - uartParams.readReturnMode = UART_RETURN_FULL; - uartParams.readEcho = UART_ECHO_OFF; - uartParams.baudRate = 115200; - uart = UART_open(Board_UART0, &uartParams); + static ClockP_Handle clk0Handle; + static ClockP_Struct clk0Struct; + static volatile uint32_t msCounter = 0; - if (uart == NULL) + static void clk0Fxn(uintptr_t arg0) { - while (true) - {} + msCounter++; } -} -static void setupNVS() -{ - NVS_Params nvsParams; - NVS_Params_init(&nvsParams); - nvsHandle = NVS_open(Board_NVSINTERNAL, &nvsParams); + static void setupClock() + { + ClockP_Params clkParams; + ClockP_Params_init(&clkParams); + clkParams.period = 1000 / ClockP_tickPeriod; + clkParams.startFlag = true; + ClockP_construct(&clk0Struct, (ClockP_Fxn)clk0Fxn, 1000 / ClockP_tickPeriod, &clkParams); + clk0Handle = ClockP_handle(&clk0Struct); + } - if (nvsHandle == NULL) + static void setupGPIO() { - println("NVS_open() failed."); - return; + /* Configure the LED and button pins */ + GPIO_setConfig(Board_GPIO_LED0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW); + GPIO_setConfig(Board_GPIO_LED1, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW); + GPIO_setConfig(Board_GPIO_BUTTON0, GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING); + GPIO_setConfig(Board_GPIO_BUTTON1, GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING); } - NVS_Attrs attrs; - NVS_getAttrs(nvsHandle, &attrs); - print("NVS flash size: "); - println((int)attrs.regionSize); - print("NVS flash sector size: "); - println((int)attrs.sectorSize); + static void setupUART() + { + UART_Params uartParams; + UART_Params_init(&uartParams); + uartParams.writeDataMode = UART_DATA_BINARY; + uartParams.readDataMode = UART_DATA_BINARY; + uartParams.readReturnMode = UART_RETURN_FULL; + uartParams.readEcho = UART_ECHO_OFF; + uartParams.baudRate = 115200; + uart = UART_open(Board_UART0, &uartParams); + + if (uart == NULL) + { + while (true) + {} + } + } - if (GPIO_read(Board_GPIO_BUTTON1) == 0) + static void setupNVS() { - println("Button1 is pressed. Erasing flash..."); - int_fast16_t result = NVS_erase(nvsHandle, 0, attrs.regionSize); + NVS_Params nvsParams; + NVS_Params_init(&nvsParams); + nvsHandle = NVS_open(Board_NVSINTERNAL, &nvsParams); - if (result != NVS_STATUS_SUCCESS) + if (nvsHandle == NULL) { - print("Error erasing NVS, result: "); - println(result); + println("NVS_open() failed."); + return; } - else + + NVS_Attrs attrs; + NVS_getAttrs(nvsHandle, &attrs); + print("NVS flash size: "); + println((int)attrs.regionSize); + print("NVS flash sector size: "); + println((int)attrs.sectorSize); + + if (GPIO_read(Board_GPIO_BUTTON1) == 0) { - println("NVS successfully erased."); + println("Button1 is pressed. Erasing flash..."); + int_fast16_t result = NVS_erase(nvsHandle, 0, attrs.regionSize); + + if (result != NVS_STATUS_SUCCESS) + { + print("Error erasing NVS, result: "); + println(result); + } + else + { + println("NVS successfully erased."); + } } } -} -void sleep(uint32_t sec) -{ - ClockP_sleep(sec); -} + void sleep(uint32_t sec) + { + ClockP_sleep(sec); + } -void usleep(uint32_t usec) -{ - ClockP_usleep(usec); -} + void usleep(uint32_t usec) + { + ClockP_usleep(usec); + } -uint32_t millis() -{ - // we use our own ms clock because the Os tick counter has counts 10us ticks and following calculation would not wrap correctly at 32bit boundary - //return Clock_getTicks() * (uint64_t) Clock_tickPeriod / 1000; // rtos - //return ClockP_getTicks( * (uint64_t) Clock_tickPeriod / 1000); //nortos - return msCounter; -} + uint32_t millis() + { + // we use our own ms clock because the Os tick counter has counts 10us ticks and following calculation would not wrap correctly at 32bit boundary + //return Clock_getTicks() * (uint64_t) Clock_tickPeriod / 1000; // rtos + //return ClockP_getTicks( * (uint64_t) Clock_tickPeriod / 1000); //nortos + return msCounter; + } -void delay(uint32_t ms) -{ - ClockP_usleep(ms * 1000); - //sleep(ms * (1000 / ClockP_tickPeriod)); //rtos - //sleepTicks(millis * 1000ULL / ClockP_tickPeriod); //nortos -} + void delay(uint32_t ms) + { + ClockP_usleep(ms * 1000); + //sleep(ms * (1000 / ClockP_tickPeriod)); //rtos + //sleepTicks(millis * 1000ULL / ClockP_tickPeriod); //nortos + } -void delayMicroseconds (unsigned int howLong) -{ - ClockP_usleep(howLong); -} + void delayMicroseconds (unsigned int howLong) + { + ClockP_usleep(howLong); + } #ifndef KNX_NO_PRINT -size_t write(uint8_t c) -{ + size_t write(uint8_t c) + { #if defined(PRINT_UART) - uint8_t buffer[1] = {c}; - return UART_write(uart, buffer, sizeof(buffer)); + uint8_t buffer[1] = {c}; + return UART_write(uart, buffer, sizeof(buffer)); #elif defined (PRINT_RTT) - return SEGGER_RTT_PutChar(0, (char)c); + return SEGGER_RTT_PutChar(0, (char)c); #else - return 1; + return 1; #endif -} + } #if 0 -size_t write(const uint8_t* buffer, size_t size) -{ - size_t n = 0; - - while (size--) + size_t write(const uint8_t* buffer, size_t size) { - if (write(*buffer++)) - { - n++; - } - else + size_t n = 0; + + while (size--) { - break; + if (write(*buffer++)) + { + n++; + } + else + { + break; + } } - } - return n; -} + return n; + } #else -size_t write(const uint8_t* buffer, size_t size) -{ + size_t write(const uint8_t* buffer, size_t size) + { #if defined(PRINT_UART) - return UART_write(uart, buffer, size); + return UART_write(uart, buffer, size); #elif defined (PRINT_RTT) - return SEGGER_RTT_Write(0, buffer, size); + return SEGGER_RTT_Write(0, buffer, size); #else - return size; + return size; #endif -} + } #endif -size_t write(const char* buffer, size_t size) -{ - return write((const uint8_t*)buffer, size); -} - -void print(const char* s) -{ - if (s == NULL) + size_t write(const char* buffer, size_t size) { - return; + return write((const uint8_t*)buffer, size); } - write(s, strlen(s)); -} -void print(char c) -{ - write(c); -} - -void printUint64(uint64_t value, int base = DEC) -{ - char buf[8 * sizeof(uint64_t) + 1]; - char* str = &buf[sizeof(buf) - 1]; - *str = '\0'; + void print(const char* s) + { + if (s == NULL) + { + return; + } - uint64_t n = value; + write(s, strlen(s)); + } + void print(char c) + { + write(c); + } - do + void printUint64(uint64_t value, int base = DEC) { - char c = n % base; - n /= base; + char buf[8 * sizeof(uint64_t) + 1]; + char* str = &buf[sizeof(buf) - 1]; + *str = '\0'; - *--str = c < 10 ? c + '0' : c + 'A' - 10; - } while (n > 0); + uint64_t n = value; - print(str); -} + do + { + char c = n % base; + n /= base; -void print(long long num, int base) -{ - if (base == 0) - { - write(num); - return; + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while (n > 0); + + print(str); } - else if (base == 10) + + void print(long long num, int base) { - if (num < 0) + if (base == 0) { - print('-'); - num = -num; - printUint64(num, 10); + write(num); return; } + else if (base == 10) + { + if (num < 0) + { + print('-'); + num = -num; + printUint64(num, 10); + return; + } - printUint64(num, 10); - return; - } - else - { - printUint64(num, base); - return; + printUint64(num, 10); + return; + } + else + { + printUint64(num, base); + return; + } } -} -void print(unsigned long long num, int base) -{ - if (base == 0) + void print(unsigned long long num, int base) { - write(num); - return; + if (base == 0) + { + write(num); + return; + } + else + { + printUint64(num, base); + return; + } } - else + + void print(unsigned char num, int base) { - printUint64(num, base); - return; + print((unsigned long long)num, base); } -} - -void print(unsigned char num, int base) -{ - print((unsigned long long)num, base); -} - -void print(int num, int base) -{ - print((long long)num, base); -} -void print(unsigned int num, int base) -{ - print((unsigned long long)num, base); -} - -void print(long num, int base) -{ - print((long long)num, base); -} - -void print(unsigned long num, int base) -{ - print((unsigned long long)num, base); -} - -void printFloat(double number, uint8_t digits) -{ - if (std::isnan(number)) + void print(int num, int base) { - print("nan"); - return; + print((long long)num, base); } - if (std::isinf(number)) + void print(unsigned int num, int base) { - print("inf"); - return; + print((unsigned long long)num, base); } - if (number > 4294967040.0) + void print(long num, int base) { - print("ovf"); // constant determined empirically - return; + print((long long)num, base); } - if (number < -4294967040.0) + void print(unsigned long num, int base) { - print("ovf"); // constant determined empirically - return; + print((unsigned long long)num, base); } - // Handle negative numbers - if (number < 0.0) + void printFloat(double number, uint8_t digits) { - print('-'); - number = -number; - } + if (std::isnan(number)) + { + print("nan"); + return; + } - // Round correctly so that print(1.999, 2) prints as "2.00" - double rounding = 0.5; + if (std::isinf(number)) + { + print("inf"); + return; + } - for (uint8_t i = 0; i < digits; ++i) - rounding /= 10.0; + if (number > 4294967040.0) + { + print("ovf"); // constant determined empirically + return; + } - number += rounding; + if (number < -4294967040.0) + { + print("ovf"); // constant determined empirically + return; + } - // Extract the integer part of the number and print it - unsigned long int_part = (unsigned long)number; - double remainder = number - (double)int_part; - printUint64(int_part); + // Handle negative numbers + if (number < 0.0) + { + print('-'); + number = -number; + } - // Print the decimal point, but only if there are digits beyond - if (digits > 0) - { - print('.'); + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + + for (uint8_t i = 0; i < digits; ++i) + rounding /= 10.0; + + number += rounding; + + // Extract the integer part of the number and print it + unsigned long int_part = (unsigned long)number; + double remainder = number - (double)int_part; + printUint64(int_part); + + // Print the decimal point, but only if there are digits beyond + if (digits > 0) + { + print('.'); + } + + // Extract digits from the remainder one at a time + while (digits-- > 0) + { + remainder *= 10.0; + unsigned int toPrint = (unsigned int)(remainder); + printUint64(toPrint); + remainder -= toPrint; + } } - // Extract digits from the remainder one at a time - while (digits-- > 0) + void print(double num, int digits = 2) { - remainder *= 10.0; - unsigned int toPrint = (unsigned int)(remainder); - printUint64(toPrint); - remainder -= toPrint; + printFloat(num, digits); } -} -void print(double num, int digits = 2) -{ - printFloat(num, digits); -} - -void println(void) -{ - print("\r\n"); -} + void println(void) + { + print("\r\n"); + } -void println(const char* s) -{ - print(s); - println(); -} -void println(char c) -{ - print(c); - println(); -} + void println(const char* s) + { + print(s); + println(); + } + void println(char c) + { + print(c); + println(); + } -void println(unsigned char num, int base) -{ - print(num, base); - println(); -} + void println(unsigned char num, int base) + { + print(num, base); + println(); + } -void println(int num, int base) -{ - print(num, base); - println(); -} + void println(int num, int base) + { + print(num, base); + println(); + } -void println(unsigned int num, int base) -{ - print(num, base); - println(); -} + void println(unsigned int num, int base) + { + print(num, base); + println(); + } -void print(double num) -{ - printf("%f", num); -} + void print(double num) + { + printf("%f", num); + } -void println(long num, int base) -{ - print(num, base); - println(); -} + void println(long num, int base) + { + print(num, base); + println(); + } -void println(unsigned long num, int base) -{ - print(num, base); - println(); -} + void println(unsigned long num, int base) + { + print(num, base); + println(); + } -void println(unsigned long long num, int base) -{ - printUint64(num, base); - println(); -} + void println(unsigned long long num, int base) + { + printUint64(num, base); + println(); + } -void println(double num, int digits = 2) -{ - print(num, digits); - println(); -} + void println(double num, int digits = 2) + { + print(num, digits); + println(); + } -void println(double num) -{ - // default: print 10 digits - println(num, 10); -} + void println(double num) + { + // default: print 10 digits + println(num, 10); + } #endif // KNX_NO_PRINT -uint32_t digitalRead(uint32_t dwPin) -{ - print("ignoring digitalRead: pin: "); - print(dwPin); - println(", returning 0"); - return 0; -} + uint32_t digitalRead(uint32_t dwPin) + { + print("ignoring digitalRead: pin: "); + print(dwPin); + println(", returning 0"); + return 0; + } -void digitalWrite(unsigned long pin, unsigned long value) -{ - if (pin == Board_GPIO_LED0) + void digitalWrite(unsigned long pin, unsigned long value) { - if (value > 0) + if (pin == Board_GPIO_LED0) { - GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON); + if (value > 0) + { + GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON); + } + else + { + GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF); + } } else { - GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF); + print("dummy digitalWrite: pin: "); + print(pin); + print(", value: "); + println(value, HEX); } } - else + + void pinMode(unsigned long pin, unsigned long mode) { - print("dummy digitalWrite: pin: "); + print("ignoring pinMode: pin: "); print(pin); - print(", value: "); - println(value, HEX); + print(", mode: "); + println(mode, HEX); } -} -void pinMode(unsigned long pin, unsigned long mode) -{ - print("ignoring pinMode: pin: "); - print(pin); - print(", mode: "); - println(mode, HEX); -} - -typedef void (*IsrFuncPtr)(); -static IsrFuncPtr gpioCallback; -static void gpioButtonFxn0(uint_least8_t index) -{ - gpioCallback(); -} + typedef void (*IsrFuncPtr)(); + static IsrFuncPtr gpioCallback; + static void gpioButtonFxn0(uint_least8_t index) + { + gpioCallback(); + } -void attachInterrupt(uint32_t pin, IsrFuncPtr callback, uint32_t mode) -{ - if (pin == Board_GPIO_BUTTON0) + void attachInterrupt(uint32_t pin, IsrFuncPtr callback, uint32_t mode) { - gpioCallback = callback; - /* install Button callback */ - GPIO_setCallback(Board_GPIO_BUTTON0, gpioButtonFxn0); + if (pin == Board_GPIO_BUTTON0) + { + gpioCallback = callback; + /* install Button callback */ + GPIO_setCallback(Board_GPIO_BUTTON0, gpioButtonFxn0); - /* Enable interrupts */ - GPIO_enableInt(Board_GPIO_BUTTON0); + /* Enable interrupts */ + GPIO_enableInt(Board_GPIO_BUTTON0); + } + else + { + print("dummy attachInterrupt: pin: "); + print(pin); + print(", mode: "); + println(mode, HEX); + } } - else + + CC1310Platform::CC1310Platform() { - print("dummy attachInterrupt: pin: "); - print(pin); - print(", mode: "); - println(mode, HEX); + // build serialNumber from IEEE MAC Address (MAC is 8 bytes, serialNumber 6 bytes only) + *(uint32_t*)(serialNumber + 2) = HWREG(FCFG1_BASE + FCFG1_O_MAC_15_4_0) ^ HWREG(FCFG1_BASE + FCFG1_O_MAC_15_4_1); // make a 6 byte hash from 8 bytes } -} - -CC1310Platform::CC1310Platform() -{ - // build serialNumber from IEEE MAC Address (MAC is 8 bytes, serialNumber 6 bytes only) - *(uint32_t*)(serialNumber + 2) = HWREG(FCFG1_BASE + FCFG1_O_MAC_15_4_0) ^ HWREG(FCFG1_BASE + FCFG1_O_MAC_15_4_1); // make a 6 byte hash from 8 bytes -} - -CC1310Platform::~CC1310Platform() -{ -} -void CC1310Platform::init() -{ - // TI Drivers init - // According to SDK docs it is safe to call them AFTER NoRTOS_Start() - // If RTOS is used and multiple thread use the same driver, then the init shall be performed before BIOS_Start() - GPIO_init(); - UART_init(); - NVS_init(); + CC1310Platform::~CC1310Platform() + { + } - // Init GPIO - setupGPIO(); + void CC1310Platform::init() + { + // TI Drivers init + // According to SDK docs it is safe to call them AFTER NoRTOS_Start() + // If RTOS is used and multiple thread use the same driver, then the init shall be performed before BIOS_Start() + GPIO_init(); + UART_init(); + NVS_init(); - // Init UART - setupUART(); + // Init GPIO + setupGPIO(); - // tick Period on this controller 10us so we use our own millisecond clock - setupClock(); + // Init UART + setupUART(); - // Init flash - setupNVS(); -} + // tick Period on this controller 10us so we use our own millisecond clock + setupClock(); -uint8_t* CC1310Platform::getEepromBuffer(uint32_t size) -{ - if (size > KNX_FLASH_SIZE) - { - fatalError(); + // Init flash + setupNVS(); } - NVS_read(nvsHandle, 0, (void*) NVS_buffer, size); - - for (uint32_t i = 0; i < size; i++) + uint8_t* CC1310Platform::getEepromBuffer(uint32_t size) { - if (NVS_buffer[i] != 0) + if (size > KNX_FLASH_SIZE) { - return NVS_buffer; + fatalError(); } - } - memset(NVS_buffer, 0xff, size); + NVS_read(nvsHandle, 0, (void*) NVS_buffer, size); - return NVS_buffer; -} - -void CC1310Platform::commitToEeprom() -{ - println("CC1310Platform::commitToEeprom() ..."); + for (uint32_t i = 0; i < size; i++) + { + if (NVS_buffer[i] != 0) + { + return NVS_buffer; + } + } - int_fast16_t result = NVS_write(nvsHandle, 0, (void*)NVS_buffer, KNX_FLASH_SIZE, NVS_WRITE_ERASE | NVS_WRITE_POST_VERIFY); + memset(NVS_buffer, 0xff, size); - if (result != NVS_STATUS_SUCCESS) - { - print("Error writing to NVS, result: "); - println(result); + return NVS_buffer; } - else + + void CC1310Platform::commitToEeprom() { - println("NVS successfully written"); - } + println("CC1310Platform::commitToEeprom() ..."); - delay(500); -} + int_fast16_t result = NVS_write(nvsHandle, 0, (void*)NVS_buffer, KNX_FLASH_SIZE, NVS_WRITE_ERASE | NVS_WRITE_POST_VERIFY); -void CC1310Platform::restart() -{ - println("System restart in 500ms."); - delay(500); - SysCtrlSystemReset(); - // Should neber be reached! - fatalError(); -} + if (result != NVS_STATUS_SUCCESS) + { + print("Error writing to NVS, result: "); + println(result); + } + else + { + println("NVS successfully written"); + } -void CC1310Platform::fatalError() -{ - println("A fatal error occured. Stopped."); + delay(500); + } - while (true) + void CC1310Platform::restart() { - /* Turn on user LED */ - GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF); - GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_ON); - delay(500); - GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON); - GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_OFF); + println("System restart in 500ms."); delay(500); + SysCtrlSystemReset(); + // Should neber be reached! + fatalError(); } -} -#endif // DeviceFamily_CC13X0 + void CC1310Platform::fatalError() + { + println("A fatal error occured. Stopped."); + + while (true) + { + /* Turn on user LED */ + GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF); + GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_ON); + delay(500); + GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON); + GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_OFF); + delay(500); + } + } +} +#endif // DeviceFamily_CC13X0 \ No newline at end of file diff --git a/src/knx/platform/cc1310_platform.h b/src/knx/platform/cc1310_platform.h index 05f23d56..ee232124 100644 --- a/src/knx/platform/cc1310_platform.h +++ b/src/knx/platform/cc1310_platform.h @@ -8,20 +8,22 @@ #include ".platform.h" -class CC1310Platform : public Platform +namespace Knx { - public: - CC1310Platform(); - virtual ~CC1310Platform(); - - void init(); - - // basic stuff - void restart() final; - void fatalError() final; - - uint8_t* getEepromBuffer(uint32_t size) final; - void commitToEeprom() final; -}; - + class CC1310Platform : public Platform + { + public: + CC1310Platform(); + virtual ~CC1310Platform(); + + void init(); + + // basic stuff + void restart() final; + void fatalError() final; + + uint8_t* getEepromBuffer(uint32_t size) final; + void commitToEeprom() final; + }; +} #endif //DeviceFamily_CC13X0 diff --git a/src/knx/platform/esp32_platform.cpp b/src/knx/platform/esp32_platform.cpp index 63be3a75..1552ffcb 100644 --- a/src/knx/platform/esp32_platform.cpp +++ b/src/knx/platform/esp32_platform.cpp @@ -10,166 +10,168 @@ #define KNX_SERIAL Serial1 #endif -Esp32Platform::Esp32Platform() +namespace Knx +{ + Esp32Platform::Esp32Platform() #ifndef KNX_NO_DEFAULT_UART - : ArduinoPlatform(&KNX_SERIAL) + : ArduinoPlatform(&KNX_SERIAL) #endif -{ + { #ifdef KNX_UART_RX_PIN - _rxPin = KNX_UART_RX_PIN; + _rxPin = KNX_UART_RX_PIN; #endif #ifdef KNX_UART_TX_PIN - _txPin = KNX_UART_TX_PIN; + _txPin = KNX_UART_TX_PIN; #endif -} + } -Esp32Platform::Esp32Platform(HardwareSerial* s) : ArduinoPlatform(s) -{ -} + Esp32Platform::Esp32Platform(HardwareSerial* s) : ArduinoPlatform(s) + { + } -void Esp32Platform::knxUartPins(int8_t rxPin, int8_t txPin) -{ - _rxPin = rxPin; - _txPin = txPin; -} + void Esp32Platform::knxUartPins(int8_t rxPin, int8_t txPin) + { + _rxPin = rxPin; + _txPin = txPin; + } -// ESP specific uart handling with pins -void Esp32Platform::setupUart() -{ - _knxSerial->begin(19200, SERIAL_8E1, _rxPin, _txPin); + // ESP specific uart handling with pins + void Esp32Platform::setupUart() + { + _knxSerial->begin(19200, SERIAL_8E1, _rxPin, _txPin); - while (!_knxSerial) - ; -} + while (!_knxSerial) + ; + } -uint32_t Esp32Platform::currentIpAddress() -{ - return WiFi.localIP(); -} + uint32_t Esp32Platform::currentIpAddress() + { + return WiFi.localIP(); + } -uint32_t Esp32Platform::currentSubnetMask() -{ - return WiFi.subnetMask(); -} + uint32_t Esp32Platform::currentSubnetMask() + { + return WiFi.subnetMask(); + } -uint32_t Esp32Platform::currentDefaultGateway() -{ - return WiFi.gatewayIP(); -} + uint32_t Esp32Platform::currentDefaultGateway() + { + return WiFi.gatewayIP(); + } -void Esp32Platform::macAddress(uint8_t* addr) -{ - esp_wifi_get_mac(WIFI_IF_STA, addr); -} + void Esp32Platform::macAddress(uint8_t* addr) + { + esp_wifi_get_mac(WIFI_IF_STA, addr); + } -uint32_t Esp32Platform::uniqueSerialNumber() -{ - uint64_t chipid = ESP.getEfuseMac(); - uint32_t upperId = (chipid >> 32) & 0xFFFFFFFF; - uint32_t lowerId = (chipid & 0xFFFFFFFF); - return (upperId ^ lowerId); -} + uint32_t Esp32Platform::uniqueSerialNumber() + { + uint64_t chipid = ESP.getEfuseMac(); + uint32_t upperId = (chipid >> 32) & 0xFFFFFFFF; + uint32_t lowerId = (chipid & 0xFFFFFFFF); + return (upperId ^ lowerId); + } -void Esp32Platform::restart() -{ - println("restart"); - ESP.restart(); -} + void Esp32Platform::restart() + { + println("restart"); + ESP.restart(); + } -void Esp32Platform::setupMultiCast(uint32_t addr, uint16_t port) -{ - IPAddress mcastaddr(htonl(addr)); + void Esp32Platform::setupMultiCast(uint32_t addr, uint16_t port) + { + IPAddress mcastaddr(htonl(addr)); - KNX_DEBUG_SERIAL.printf("setup multicast addr: %s port: %d ip: %s\n", mcastaddr.toString().c_str(), port, - WiFi.localIP().toString().c_str()); - uint8_t result = _udp.beginMulticast(mcastaddr, port); - KNX_DEBUG_SERIAL.printf("result %d\n", result); -} + KNX_DEBUG_SERIAL.printf("setup multicast addr: %s port: %d ip: %s\n", mcastaddr.toString().c_str(), port, + WiFi.localIP().toString().c_str()); + uint8_t result = _udp.beginMulticast(mcastaddr, port); + KNX_DEBUG_SERIAL.printf("result %d\n", result); + } -void Esp32Platform::closeMultiCast() -{ - _udp.stop(); -} + void Esp32Platform::closeMultiCast() + { + _udp.stop(); + } -bool Esp32Platform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) -{ - //printHex("<- ",buffer, len); - _udp.beginMulticastPacket(); - _udp.write(buffer, len); - _udp.endPacket(); - return true; -} + bool Esp32Platform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) + { + //printHex("<- ",buffer, len); + _udp.beginMulticastPacket(); + _udp.write(buffer, len); + _udp.endPacket(); + return true; + } -int Esp32Platform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port) -{ - int len = _udp.parsePacket(); + int Esp32Platform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port) + { + int len = _udp.parsePacket(); - if (len == 0) - return 0; + if (len == 0) + return 0; - if (len > maxLen) - { - println("Unexpected UDP data packet length - drop packet"); + if (len > maxLen) + { + println("Unexpected UDP data packet length - drop packet"); - for (size_t i = 0; i < len; i++) - _udp.read(); + for (size_t i = 0; i < len; i++) + _udp.read(); - return 0; - } + return 0; + } - _udp.read(buffer, len); - _remoteIP = _udp.remoteIP(); - _remotePort = _udp.remotePort(); - src_addr = htonl(_remoteIP); - src_port = _remotePort; + _udp.read(buffer, len); + _remoteIP = _udp.remoteIP(); + _remotePort = _udp.remotePort(); + src_addr = htonl(_remoteIP); + src_port = _remotePort; - // print("Remote IP: "); - // print(_udp.remoteIP().toString().c_str()); - // printHex("-> ", buffer, len); + // print("Remote IP: "); + // print(_udp.remoteIP().toString().c_str()); + // printHex("-> ", buffer, len); - return len; -} + return len; + } -bool Esp32Platform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) -{ - IPAddress ucastaddr(htonl(addr)); + bool Esp32Platform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) + { + IPAddress ucastaddr(htonl(addr)); - if (!addr) - ucastaddr = _remoteIP; + if (!addr) + ucastaddr = _remoteIP; - if (!port) - port = _remotePort; + if (!port) + port = _remotePort; - if (_udp.beginPacket(ucastaddr, port) == 1) - { - _udp.write(buffer, len); + if (_udp.beginPacket(ucastaddr, port) == 1) + { + _udp.write(buffer, len); + + if (_udp.endPacket() == 0) + println("sendBytesUniCast endPacket fail"); + } + else + println("sendBytesUniCast beginPacket fail"); - if (_udp.endPacket() == 0) - println("sendBytesUniCast endPacket fail"); + return true; } - else - println("sendBytesUniCast beginPacket fail"); - return true; -} + uint8_t* Esp32Platform::getEepromBuffer(uint32_t size) + { + uint8_t* eepromptr = EEPROM.getDataPtr(); -uint8_t* Esp32Platform::getEepromBuffer(uint32_t size) -{ - uint8_t* eepromptr = EEPROM.getDataPtr(); + if (eepromptr == nullptr) + { + EEPROM.begin(size); + eepromptr = EEPROM.getDataPtr(); + } - if (eepromptr == nullptr) - { - EEPROM.begin(size); - eepromptr = EEPROM.getDataPtr(); + return eepromptr; } - return eepromptr; -} - -void Esp32Platform::commitToEeprom() -{ - EEPROM.getDataPtr(); // trigger dirty flag in EEPROM lib to make sure data will be written to flash - EEPROM.commit(); + void Esp32Platform::commitToEeprom() + { + EEPROM.getDataPtr(); // trigger dirty flag in EEPROM lib to make sure data will be written to flash + EEPROM.commit(); + } } - -#endif +#endif \ No newline at end of file diff --git a/src/knx/platform/esp32_platform.h b/src/knx/platform/esp32_platform.h index 4f8fb8f6..660afd46 100644 --- a/src/knx/platform/esp32_platform.h +++ b/src/knx/platform/esp32_platform.h @@ -4,50 +4,52 @@ #include -class Esp32Platform : public ArduinoPlatform +namespace Knx { - public: - Esp32Platform(); - Esp32Platform(HardwareSerial* s); - - // uart - void knxUartPins(int8_t rxPin, int8_t txPin); - void setupUart() override; - - // ip stuff - uint32_t currentIpAddress() override; - uint32_t currentSubnetMask() override; - uint32_t currentDefaultGateway() override; - void macAddress(uint8_t* addr) override; - - // unique serial number - uint32_t uniqueSerialNumber() override; - - // basic stuff - void restart(); - - //multicast - void setupMultiCast(uint32_t addr, uint16_t port) override; - void closeMultiCast() override; - bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override; - int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port) override; - - //unicast - bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override; - - //memory - uint8_t* getEepromBuffer(uint32_t size); - void commitToEeprom(); - - protected: - IPAddress _remoteIP; - protected: - uint16_t _remotePort; - - private: - WiFiUDP _udp; - int8_t _rxPin = -1; - int8_t _txPin = -1; -}; - -#endif + class Esp32Platform : public ArduinoPlatform + { + public: + Esp32Platform(); + Esp32Platform(HardwareSerial* s); + + // uart + void knxUartPins(int8_t rxPin, int8_t txPin); + void setupUart() override; + + // ip stuff + uint32_t currentIpAddress() override; + uint32_t currentSubnetMask() override; + uint32_t currentDefaultGateway() override; + void macAddress(uint8_t* addr) override; + + // unique serial number + uint32_t uniqueSerialNumber() override; + + // basic stuff + void restart(); + + //multicast + void setupMultiCast(uint32_t addr, uint16_t port) override; + void closeMultiCast() override; + bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override; + int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port) override; + + //unicast + bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override; + + //memory + uint8_t* getEepromBuffer(uint32_t size); + void commitToEeprom(); + + protected: + IPAddress _remoteIP; + protected: + uint16_t _remotePort; + + private: + WiFiUDP _udp; + int8_t _rxPin = -1; + int8_t _txPin = -1; + }; +} +#endif \ No newline at end of file diff --git a/src/knx/platform/esp_platform.cpp b/src/knx/platform/esp_platform.cpp index 83a35864..5eb705b6 100644 --- a/src/knx/platform/esp_platform.cpp +++ b/src/knx/platform/esp_platform.cpp @@ -12,125 +12,128 @@ #define KNX_SERIAL Serial #endif -EspPlatform::EspPlatform() +namespace Knx +{ + EspPlatform::EspPlatform() #ifndef KNX_NO_DEFAULT_UART - : ArduinoPlatform(&KNX_SERIAL) + : ArduinoPlatform(&KNX_SERIAL) #endif -{ -} + { + } -EspPlatform::EspPlatform( HardwareSerial* s) : ArduinoPlatform(s) -{ -} + EspPlatform::EspPlatform( HardwareSerial* s) : ArduinoPlatform(s) + { + } -uint32_t EspPlatform::currentIpAddress() -{ - return WiFi.localIP(); -} + uint32_t EspPlatform::currentIpAddress() + { + return WiFi.localIP(); + } -uint32_t EspPlatform::currentSubnetMask() -{ - return WiFi.subnetMask(); -} + uint32_t EspPlatform::currentSubnetMask() + { + return WiFi.subnetMask(); + } -uint32_t EspPlatform::currentDefaultGateway() -{ - return WiFi.gatewayIP(); -} + uint32_t EspPlatform::currentDefaultGateway() + { + return WiFi.gatewayIP(); + } -void EspPlatform::macAddress(uint8_t* addr) -{ - wifi_get_macaddr(STATION_IF, addr); -} + void EspPlatform::macAddress(uint8_t* addr) + { + wifi_get_macaddr(STATION_IF, addr); + } -uint32_t EspPlatform::uniqueSerialNumber() -{ - return ESP.getChipId(); -} + uint32_t EspPlatform::uniqueSerialNumber() + { + return ESP.getChipId(); + } -void EspPlatform::restart() -{ - println("restart"); - ESP.reset(); -} + void EspPlatform::restart() + { + println("restart"); + ESP.reset(); + } -void EspPlatform::setupMultiCast(uint32_t addr, uint16_t port) -{ - _multicastAddr = htonl(addr); - _multicastPort = port; - IPAddress mcastaddr(_multicastAddr); - - KNX_DEBUG_SERIAL.printf("setup multicast addr: %s port: %d ip: %s\n", mcastaddr.toString().c_str(), port, - WiFi.localIP().toString().c_str()); - uint8 result = _udp.beginMulticast(WiFi.localIP(), mcastaddr, port); - KNX_DEBUG_SERIAL.printf("result %d\n", result); -} + void EspPlatform::setupMultiCast(uint32_t addr, uint16_t port) + { + _multicastAddr = htonl(addr); + _multicastPort = port; + IPAddress mcastaddr(_multicastAddr); + + KNX_DEBUG_SERIAL.printf("setup multicast addr: %s port: %d ip: %s\n", mcastaddr.toString().c_str(), port, + WiFi.localIP().toString().c_str()); + uint8 result = _udp.beginMulticast(WiFi.localIP(), mcastaddr, port); + KNX_DEBUG_SERIAL.printf("result %d\n", result); + } -void EspPlatform::closeMultiCast() -{ - _udp.stop(); -} + void EspPlatform::closeMultiCast() + { + _udp.stop(); + } -bool EspPlatform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) -{ - //printHex("<- ",buffer, len); - _udp.beginPacketMulticast(_multicastAddr, _multicastPort, WiFi.localIP()); - _udp.write(buffer, len); - _udp.endPacket(); - return true; -} + bool EspPlatform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) + { + //printHex("<- ",buffer, len); + _udp.beginPacketMulticast(_multicastAddr, _multicastPort, WiFi.localIP()); + _udp.write(buffer, len); + _udp.endPacket(); + return true; + } -int EspPlatform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) -{ - int len = _udp.parsePacket(); + int EspPlatform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) + { + int len = _udp.parsePacket(); - if (len == 0) - return 0; + if (len == 0) + return 0; - if (len > maxLen) - { - KNX_DEBUG_SERIAL.printf("udp buffer to small. was %d, needed %d\n", maxLen, len); - fatalError(); + if (len > maxLen) + { + KNX_DEBUG_SERIAL.printf("udp buffer to small. was %d, needed %d\n", maxLen, len); + fatalError(); + } + + _udp.read(buffer, len); + //printHex("-> ", buffer, len); + return len; } - _udp.read(buffer, len); - //printHex("-> ", buffer, len); - return len; -} + bool EspPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) + { + IPAddress ucastaddr(htonl(addr)); + println("sendBytesUniCast endPacket fail"); -bool EspPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) -{ - IPAddress ucastaddr(htonl(addr)); - println("sendBytesUniCast endPacket fail"); + if (_udp.beginPacket(ucastaddr, port) == 1) + { + _udp.write(buffer, len); - if (_udp.beginPacket(ucastaddr, port) == 1) - { - _udp.write(buffer, len); + if (_udp.endPacket() == 0) + println("sendBytesUniCast endPacket fail"); + } + else + println("sendBytesUniCast beginPacket fail"); - if (_udp.endPacket() == 0) - println("sendBytesUniCast endPacket fail"); + return true; } - else - println("sendBytesUniCast beginPacket fail"); - return true; -} + uint8_t* EspPlatform::getEepromBuffer(uint32_t size) + { + uint8_t* eepromptr = EEPROM.getDataPtr(); -uint8_t* EspPlatform::getEepromBuffer(uint32_t size) -{ - uint8_t* eepromptr = EEPROM.getDataPtr(); + if (eepromptr == nullptr) + { + EEPROM.begin(size); + eepromptr = EEPROM.getDataPtr(); + } - if (eepromptr == nullptr) - { - EEPROM.begin(size); - eepromptr = EEPROM.getDataPtr(); + return eepromptr; } - return eepromptr; -} - -void EspPlatform::commitToEeprom() -{ - EEPROM.commit(); + void EspPlatform::commitToEeprom() + { + EEPROM.commit(); + } } -#endif +#endif \ No newline at end of file diff --git a/src/knx/platform/esp_platform.h b/src/knx/platform/esp_platform.h index 1d4361ce..a6d665a9 100644 --- a/src/knx/platform/esp_platform.h +++ b/src/knx/platform/esp_platform.h @@ -3,41 +3,42 @@ #include #include - -class EspPlatform : public ArduinoPlatform +namespace Knx { - public: - EspPlatform(); - EspPlatform(HardwareSerial* s); - - // ip stuff - uint32_t currentIpAddress() override; - uint32_t currentSubnetMask() override; - uint32_t currentDefaultGateway() override; - void macAddress(uint8_t* addr) override; - - // unique serial number - uint32_t uniqueSerialNumber() override; - - // basic stuff - void restart(); - - //multicast - void setupMultiCast(uint32_t addr, uint16_t port) override; - void closeMultiCast() override; - bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override; - int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) override; - - //unicast - bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override; - - //memory - uint8_t* getEepromBuffer(uint32_t size); - void commitToEeprom(); - private: - WiFiUDP _udp; - uint32_t _multicastAddr; - uint16_t _multicastPort; -}; - -#endif + class EspPlatform : public ArduinoPlatform + { + public: + EspPlatform(); + EspPlatform(HardwareSerial* s); + + // ip stuff + uint32_t currentIpAddress() override; + uint32_t currentSubnetMask() override; + uint32_t currentDefaultGateway() override; + void macAddress(uint8_t* addr) override; + + // unique serial number + uint32_t uniqueSerialNumber() override; + + // basic stuff + void restart(); + + //multicast + void setupMultiCast(uint32_t addr, uint16_t port) override; + void closeMultiCast() override; + bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override; + int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) override; + + //unicast + bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override; + + //memory + uint8_t* getEepromBuffer(uint32_t size); + void commitToEeprom(); + private: + WiFiUDP _udp; + uint32_t _multicastAddr; + uint16_t _multicastPort; + }; +} +#endif \ No newline at end of file diff --git a/src/knx/platform/linux_platform.cpp b/src/knx/platform/linux_platform.cpp index 78969af1..4ff4ee96 100644 --- a/src/knx/platform/linux_platform.cpp +++ b/src/knx/platform/linux_platform.cpp @@ -42,1123 +42,1169 @@ #define MAX_MEM 4096 -LinuxPlatform::LinuxPlatform() +namespace Knx { - int socketMac = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); - - if (socketMac < 0) + LinuxPlatform::LinuxPlatform() { - LOGGER.critical("Lookup socket creation failed"); - return; - } + int socketMac = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); - struct ifreq ifr; + if (socketMac < 0) + { + LOGGER.critical("Lookup socket creation failed"); + return; + } - struct ifconf ifc; + struct ifreq ifr; - char buf[1024]; + struct ifconf ifc; - ifc.ifc_len = sizeof(buf); + char buf[1024]; - ifc.ifc_buf = buf; + ifc.ifc_len = sizeof(buf); - if (ioctl(socketMac, SIOCGIFCONF, &ifc) < 0) - return; + ifc.ifc_buf = buf; - struct ifreq* it = ifc.ifc_req; - const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq)); + if (ioctl(socketMac, SIOCGIFCONF, &ifc) < 0) + return; - for (; it != end; ++it) - { - strcpy(ifr.ifr_name, it->ifr_name); + struct ifreq* it = ifc.ifc_req; + const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq)); - if (ioctl(socketMac, SIOCGIFFLAGS, &ifr)) - continue; + for (; it != end; ++it) + { + strcpy(ifr.ifr_name, it->ifr_name); - if (ifr.ifr_flags & IFF_LOOPBACK) // don't count loopback - continue; + if (ioctl(socketMac, SIOCGIFFLAGS, &ifr)) + continue; - if (ioctl(socketMac, SIOCGIFHWADDR, &ifr)) - continue; + if (ifr.ifr_flags & IFF_LOOPBACK) // don't count loopback + continue; - if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) - continue; + if (ioctl(socketMac, SIOCGIFHWADDR, &ifr)) + continue; - memcpy(_macAddress, ifr.ifr_hwaddr.sa_data, IFHWADDRLEN); + if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) + continue; - ioctl(socketMac, SIOCGIFADDR, &ifr); + memcpy(_macAddress, ifr.ifr_hwaddr.sa_data, IFHWADDRLEN); - struct sockaddr_in* ipaddr = (struct sockaddr_in*)&ifr.ifr_addr; - _ipAddress = ntohl(ipaddr->sin_addr.s_addr); + ioctl(socketMac, SIOCGIFADDR, &ifr); - //printf("IP address: %s\n", inet_ntoa(ipaddr->sin_addr)); - ioctl(socketMac, SIOCGIFNETMASK, &ifr); - struct sockaddr_in* netmask = (struct sockaddr_in*)&ifr.ifr_netmask; - _netmask = ntohl(netmask->sin_addr.s_addr); - //printf("Netmask: %s\n", inet_ntoa(ipaddr->sin_addr)); - break; - } + struct sockaddr_in* ipaddr = (struct sockaddr_in*)&ifr.ifr_addr; + _ipAddress = ntohl(ipaddr->sin_addr.s_addr); - close(socketMac); + //printf("IP address: %s\n", inet_ntoa(ipaddr->sin_addr)); + ioctl(socketMac, SIOCGIFNETMASK, &ifr); + struct sockaddr_in* netmask = (struct sockaddr_in*)&ifr.ifr_netmask; + _netmask = ntohl(netmask->sin_addr.s_addr); + //printf("Netmask: %s\n", inet_ntoa(ipaddr->sin_addr)); + break; + } - // default GW - FILE* f; - char line[100], *p, *c, *g, *saveptr; + close(socketMac); - f = fopen("/proc/net/route", "r"); + // default GW + FILE* f; + char line[100], *p, *c, *g, *saveptr; - while (fgets(line, 100, f)) - { - p = strtok_r(line, " \t", &saveptr); - c = strtok_r(NULL, " \t", &saveptr); - g = strtok_r(NULL, " \t", &saveptr); + f = fopen("/proc/net/route", "r"); - if (p != NULL && c != NULL) + while (fgets(line, 100, f)) { - if (strcmp(c, "00000000") == 0) + p = strtok_r(line, " \t", &saveptr); + c = strtok_r(NULL, " \t", &saveptr); + g = strtok_r(NULL, " \t", &saveptr); + + if (p != NULL && c != NULL) { - //printf("Default interface is : %s \n" , p); - if (g) + if (strcmp(c, "00000000") == 0) { - char* pEnd; - _defaultGateway = ntohl(strtol(g, &pEnd, 16)); + //printf("Default interface is : %s \n" , p); + if (g) + { + char* pEnd; + _defaultGateway = ntohl(strtol(g, &pEnd, 16)); + } + + break; } - - break; } } + + fclose(f); } - fclose(f); -} + LinuxPlatform::~LinuxPlatform() + { + delete[] _args; + } -LinuxPlatform::~LinuxPlatform() -{ - delete[] _args; -} + void LinuxPlatform::restart() + { + execv(_args[0], _args); + } -uint32_t millis() -{ - struct timespec spec; + void LinuxPlatform::fatalError() + { + LOGGER.critical("A fatal error occured. Stopping.\n"); - clock_gettime(CLOCK_MONOTONIC, &spec); - return spec.tv_sec * 1000 + round(spec.tv_nsec / 1.0e6); -} + while (true) + sleep(1); + } -void delay(uint32_t millis) -{ - struct timespec ts; - ts.tv_sec = millis / 1000; - ts.tv_nsec = (millis % 1000) * 1000000; - nanosleep(&ts, NULL); -} + void LinuxPlatform::setupMultiCast(uint32_t addr, uint16_t port) + { + if (_multicastSocketFd >= 0) + closeMultiCast(); -void LinuxPlatform::restart() -{ - execv(_args[0], _args); -} + _multicastAddr = addr; + _multicastPort = port; -void LinuxPlatform::fatalError() -{ - LOGGER.critical("A fatal error occured. Stopping.\n"); + struct ip_mreq command; + uint32_t loop = 1; - while (true) - sleep(1); -} + struct sockaddr_in sin; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(INADDR_ANY); + sin.sin_port = htons(port); -void LinuxPlatform::setupMultiCast(uint32_t addr, uint16_t port) -{ - if (_multicastSocketFd >= 0) - closeMultiCast(); + _multicastSocketFd = socket(AF_INET, SOCK_DGRAM, 0); + + if (_multicastSocketFd == -1) + { + LOGGER.critical("socket() %s", strerror(errno)); + fatalError(); + } - _multicastAddr = addr; - _multicastPort = port; + /* Mehr Prozessen erlauben, denselben Port zu nutzen */ + loop = 1; - struct ip_mreq command; - uint32_t loop = 1; + if (setsockopt(_multicastSocketFd, SOL_SOCKET, SO_REUSEADDR, &loop, sizeof(loop)) < 0) + { + LOGGER.critical("setsockopt:SO_REUSEADDR %s", strerror(errno)); + fatalError(); + } - struct sockaddr_in sin; - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = htonl(INADDR_ANY); - sin.sin_port = htons(port); + if (bind(_multicastSocketFd, (struct sockaddr*)&sin, sizeof(sin)) < 0) + { + LOGGER.critical("bind %s", strerror(errno)); + fatalError(); + } - _multicastSocketFd = socket(AF_INET, SOCK_DGRAM, 0); + /* loopback */ + loop = 0; - if (_multicastSocketFd == -1) - { - LOGGER.critical("socket() %s", strerror(errno)); - fatalError(); - } + if (setsockopt(_multicastSocketFd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) + { + LOGGER.critical("setsockopt:IP_MULTICAST_LOOP %s", strerror(errno)); + fatalError(); + } - /* Mehr Prozessen erlauben, denselben Port zu nutzen */ - loop = 1; + /* Join the broadcast group: */ + command.imr_multiaddr.s_addr = htonl(addr); + command.imr_interface.s_addr = htonl(INADDR_ANY); - if (setsockopt(_multicastSocketFd, SOL_SOCKET, SO_REUSEADDR, &loop, sizeof(loop)) < 0) - { - LOGGER.critical("setsockopt:SO_REUSEADDR %s", strerror(errno)); - fatalError(); + if (setsockopt(_multicastSocketFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &command, sizeof(command)) < 0) + { + LOGGER.critical("setsockopt:IP_ADD_MEMBERSHIP %s", strerror(errno)); + fatalError(); + } + + uint32_t flags = fcntl(_multicastSocketFd, F_GETFL); + flags |= O_NONBLOCK; + fcntl(_multicastSocketFd, F_SETFL, flags); } - if (bind(_multicastSocketFd, (struct sockaddr*)&sin, sizeof(sin)) < 0) + void LinuxPlatform::closeMultiCast() { - LOGGER.critical("bind %s", strerror(errno)); - fatalError(); + struct ip_mreq command; + command.imr_multiaddr.s_addr = htonl(_multicastAddr); + command.imr_interface.s_addr = htonl(INADDR_ANY); + + if (setsockopt(_multicastSocketFd, + IPPROTO_IP, + IP_DROP_MEMBERSHIP, + &command, sizeof(command)) < 0) + { + LOGGER.error("setsockopt:IP_DROP_MEMBERSHIP %s", strerror(errno)); + } + + close(_multicastSocketFd); + _multicastSocketFd = -1; } - /* loopback */ - loop = 0; + bool LinuxPlatform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) + { + struct sockaddr_in address = {0}; + address.sin_family = AF_INET; + address.sin_addr.s_addr = htonl(_multicastAddr); + address.sin_port = htons(_multicastPort); + + ssize_t retVal = 0; + + do + { + retVal = sendto(_multicastSocketFd, buffer, len, 0, (struct sockaddr*)&address, sizeof(address)); + + if (retVal == -1) + { + if (errno != EAGAIN && errno != EWOULDBLOCK) + return false; + } + } while (retVal == -1); + + // printHex("<-", buffer, len); + return true; + } - if (setsockopt(_multicastSocketFd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) + int LinuxPlatform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) { - LOGGER.critical("setsockopt:IP_MULTICAST_LOOP %s", strerror(errno)); - fatalError(); + uint32_t sin_len; + struct sockaddr_in sin; + + sin_len = sizeof(sin); + ssize_t len = recvfrom(_multicastSocketFd, buffer, maxLen, 0, (struct sockaddr*)&sin, &sin_len); + // if (len > 0) + // printHex("->", buffer, len); + + return len; } - /* Join the broadcast group: */ - command.imr_multiaddr.s_addr = htonl(addr); - command.imr_interface.s_addr = htonl(INADDR_ANY); + uint8_t* LinuxPlatform::getEepromBuffer(uint32_t size) + { + if (_fd < 0) + doMemoryMapping(); + + return _mappedFile + 2; + } - if (setsockopt(_multicastSocketFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &command, sizeof(command)) < 0) + void LinuxPlatform::commitToEeprom() { - LOGGER.critical("setsockopt:IP_ADD_MEMBERSHIP %s", strerror(errno)); - fatalError(); + if (_fd < 0) + doMemoryMapping(); + + fsync(_fd); } - uint32_t flags = fcntl(_multicastSocketFd, F_GETFL); - flags |= O_NONBLOCK; - fcntl(_multicastSocketFd, F_SETFL, flags); -} +#define FLASHSIZE 0x10000 + void LinuxPlatform::doMemoryMapping() + { + _fd = open(_flashFilePath.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRGRP | S_IROTH); -void LinuxPlatform::closeMultiCast() -{ - struct ip_mreq command; - command.imr_multiaddr.s_addr = htonl(_multicastAddr); - command.imr_interface.s_addr = htonl(INADDR_ANY); + if (_fd < 0) + { + LOGGER.critical("Error in file opening"); + //exit(-1); + } + + struct stat st; + + uint32_t ret = fstat(_fd, &st); + + if (ret < 0) + { + LOGGER.critical("Error in fstat"); + //exit(-1); + } + + size_t len_file = st.st_size; + + if (len_file < FLASHSIZE) + { + if (ftruncate(_fd, FLASHSIZE) != 0) + { + LOGGER.critical("Error extending file"); + //exit(-1); + } + + len_file = FLASHSIZE; + } + + unsigned char* addr = (unsigned char*)mmap(NULL, len_file, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0); + + if (addr[0] != 0xAF || addr[1] != 0xFE) + { + memset(addr, 0, FLASHSIZE); + addr[0] = 0xAF; + addr[1] = 0xFE; + } - if (setsockopt(_multicastSocketFd, - IPPROTO_IP, - IP_DROP_MEMBERSHIP, - &command, sizeof(command)) < 0) + if (addr == MAP_FAILED) + { + LOGGER.critical("Error in mmap"); + //exit(-1); + } + + _mappedFile = addr; + } + + void LinuxPlatform::closeSpi() { - LOGGER.error("setsockopt:IP_DROP_MEMBERSHIP %s", strerror(errno)); + close(_spiFd); + LOGGER.info("SPI device closed."); } - close(_multicastSocketFd); - _multicastSocketFd = -1; -} + int LinuxPlatform::readWriteSpi(uint8_t* data, size_t len) + { + uint16_t spiDelay = 0; + uint32_t spiSpeed = 8000000; // 4 MHz SPI speed + uint8_t spiBPW = 8; // Bits per word -bool LinuxPlatform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) -{ - struct sockaddr_in address = {0}; - address.sin_family = AF_INET; - address.sin_addr.s_addr = htonl(_multicastAddr); - address.sin_port = htons(_multicastPort); + struct spi_ioc_transfer spi; - ssize_t retVal = 0; + // Mentioned in spidev.h but not used in the original kernel documentation + // test program )-: - do - { - retVal = sendto(_multicastSocketFd, buffer, len, 0, (struct sockaddr*)&address, sizeof(address)); + memset(&spi, 0, sizeof(spi)); + + spi.tx_buf = (uint64_t)data; + spi.rx_buf = (uint64_t)data; + spi.len = len; + spi.delay_usecs = spiDelay; + spi.speed_hz = spiSpeed; + spi.bits_per_word = spiBPW; - if (retVal == -1) + return ioctl(_spiFd, SPI_IOC_MESSAGE(1), &spi); + } + + void LinuxPlatform::setupSpi() + { + if ((_spiFd = open("/dev/spidev0.0", O_RDWR)) < 0) { - if (errno != EAGAIN && errno != EWOULDBLOCK) - return false; + LOGGER.error("ERROR: SPI setup failed! Could not open SPI device!"); + return; } - } while (retVal == -1); - // printHex("<-", buffer, len); - return true; -} + // Set SPI parameters. + int mode = 0; // Mode 0 + uint8_t spiBPW = 8; // Bits per word + int speed = 8000000; // 4 MHz SPI speed -int LinuxPlatform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) -{ - uint32_t sin_len; - struct sockaddr_in sin; + if (ioctl(_spiFd, SPI_IOC_WR_MODE, &mode) < 0) + { + LOGGER.error("ERROR: SPI Mode Change failure: %s", strerror(errno)); + close(_spiFd); + return; + } - sin_len = sizeof(sin); - ssize_t len = recvfrom(_multicastSocketFd, buffer, maxLen, 0, (struct sockaddr*)&sin, &sin_len); - // if (len > 0) - // printHex("->", buffer, len); + if (ioctl(_spiFd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0) + { + LOGGER.error("ERROR: SPI BPW Change failure: %s", strerror(errno)); + close(_spiFd); + return; + } - return len; -} + if (ioctl(_spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) + { + LOGGER.error("ERROR: SPI Speed Change failure: %s", strerror(errno)); + close(_spiFd); + return; + } -uint8_t* LinuxPlatform::getEepromBuffer(uint32_t size) -{ - if (_fd < 0) - doMemoryMapping(); + LOGGER.info("SPI device setup ok."); + } - return _mappedFile + 2; -} + void LinuxPlatform::flashFilePath(const std::string path) + { + _flashFilePath = path; + } -void LinuxPlatform::commitToEeprom() -{ - if (_fd < 0) - doMemoryMapping(); + std::string LinuxPlatform::flashFilePath() + { + return _flashFilePath; + } - fsync(_fd); -} -#define FLASHSIZE 0x10000 -void LinuxPlatform::doMemoryMapping() -{ - _fd = open(_flashFilePath.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRGRP | S_IROTH); - if (_fd < 0) + size_t LinuxPlatform::readBytesUart(uint8_t* buffer, size_t length) { - LOGGER.critical("Error in file opening"); - //exit(-1); + return read(_uartFd, buffer, length); } - struct stat st; + int LinuxPlatform::readUart() + { + uint8_t x ; + + if (read(_uartFd, &x, 1) != 1) + { + return -1; + } - uint32_t ret = fstat(_fd, &st); + return ((int)x) & 0xFF ; + } - if (ret < 0) + size_t LinuxPlatform::writeUart(const uint8_t* buffer, size_t size) { - LOGGER.critical("Error in fstat"); - //exit(-1); + return write(_uartFd, buffer, size) ; } - size_t len_file = st.st_size; + size_t LinuxPlatform::writeUart(const uint8_t data) + { + return write(_uartFd, &data, 1) ; + } - if (len_file < FLASHSIZE) + int LinuxPlatform::uartAvailable() { - if (ftruncate(_fd, FLASHSIZE) != 0) + int result ; + + if (ioctl(_uartFd, FIONREAD, &result) == -1) { - LOGGER.critical("Error extending file"); - //exit(-1); + return -1; } - len_file = FLASHSIZE; + return result ; } - unsigned char* addr = (unsigned char*)mmap(NULL, len_file, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0); - - if (addr[0] != 0xAF || addr[1] != 0xFE) + void LinuxPlatform::closeUart() { - memset(addr, 0, FLASHSIZE); - addr[0] = 0xAF; - addr[1] = 0xFE; + if (_uartFd >= 0) + { + close(_uartFd); + } } - if (addr == MAP_FAILED) + void LinuxPlatform::setupUart() { - LOGGER.critical("Error in mmap"); - //exit(-1); - } + /* + * 19200,8E1, no handshake + */ + struct termios options; /* Schnittstellenoptionen */ - _mappedFile = addr; -} + /* Port oeffnen - read/write, kein "controlling tty", Status von DCD ignorieren */ + _uartFd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY); -void LinuxPlatform::closeSpi() -{ - close(_spiFd); - LOGGER.info("SPI device closed."); -} + if (_uartFd >= 0) + { + /* get the current options */ + fcntl(_uartFd, F_SETFL, 0); -int LinuxPlatform::readWriteSpi(uint8_t* data, size_t len) -{ - uint16_t spiDelay = 0; - uint32_t spiSpeed = 8000000; // 4 MHz SPI speed - uint8_t spiBPW = 8; // Bits per word + if (tcgetattr(_uartFd, &options) != 0) + { + close(_uartFd); + _uartFd = -1; + return; + } - struct spi_ioc_transfer spi; + memset(&options, 0, sizeof(options)); /* Structur loeschen, ggf. vorher sichern + und bei Programmende wieder restaurieren */ + /* Baudrate setzen */ + cfsetispeed(&options, B19200); + cfsetospeed(&options, B19200); + + /* setze Optionen */ + options.c_cflag |= PARENB; /* Enable Paritybit */ + options.c_cflag &= ~PARODD; /* Even parity */ + options.c_cflag &= ~CSTOPB; /* 1 Stoppbit */ + options.c_cflag &= ~CSIZE; /* 8 Datenbits */ + options.c_cflag |= CS8; + + /* 19200 bps, 8 Datenbits, CD-Signal ignorieren, Lesen erlauben */ + options.c_cflag |= (CLOCAL | CREAD); + + /* Kein Echo, keine Steuerzeichen, keine Interrupts */ + options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + options.c_iflag = IGNPAR; /* Parity-Fehler ignorieren */ + options.c_oflag &= ~OPOST; /* setze "raw" Input */ + options.c_cc[VMIN] = 0; /* warten auf min. 0 Zeichen */ + options.c_cc[VTIME] = 10; /* Timeout 1 Sekunde */ + tcflush(_uartFd, TCIOFLUSH); /* Puffer leeren */ + + if (tcsetattr(_uartFd, TCSAFLUSH, &options) != 0) + { + close(_uartFd); + _uartFd = -1; + return; + } + } + } +#ifndef KNX_NO_PRINT + void printUint64(uint64_t value, int base = DEC) + { + char buf[8 * sizeof(uint64_t) + 1]; + char* str = &buf[sizeof(buf) - 1]; + *str = '\0'; - // Mentioned in spidev.h but not used in the original kernel documentation - // test program )-: + uint64_t n = value; - memset(&spi, 0, sizeof(spi)); + do + { + char c = n % base; + n /= base; - spi.tx_buf = (uint64_t)data; - spi.rx_buf = (uint64_t)data; - spi.len = len; - spi.delay_usecs = spiDelay; - spi.speed_hz = spiSpeed; - spi.bits_per_word = spiBPW; + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while (n > 0); - return ioctl(_spiFd, SPI_IOC_MESSAGE(1), &spi); -} + print(str); + } -void LinuxPlatform::setupSpi() -{ - if ((_spiFd = open("/dev/spidev0.0", O_RDWR)) < 0) + void print(const char* s) { - LOGGER.error("ERROR: SPI setup failed! Could not open SPI device!"); - return; + printf("%s", s); + } + void print(char c) + { + printf("%c", c); } - // Set SPI parameters. - int mode = 0; // Mode 0 - uint8_t spiBPW = 8; // Bits per word - int speed = 8000000; // 4 MHz SPI speed - - if (ioctl(_spiFd, SPI_IOC_WR_MODE, &mode) < 0) + void print(unsigned char num) { - LOGGER.error("ERROR: SPI Mode Change failure: %s", strerror(errno)); - close(_spiFd); - return; + print(num, DEC); } - if (ioctl(_spiFd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0) + void print(unsigned char num, int base) { - LOGGER.error("ERROR: SPI BPW Change failure: %s", strerror(errno)); - close(_spiFd); - return; + if (base == HEX) + printf("%X", num); + else + printf("%d", num); } - if (ioctl(_spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) + void print(int num) { - LOGGER.error("ERROR: SPI Speed Change failure: %s", strerror(errno)); - close(_spiFd); - return; + print(num, DEC); } - LOGGER.info("SPI device setup ok."); -} + void print(int num, int base) + { + if (base == HEX) + printf("%X", num); + else + printf("%d", num); + } -void LinuxPlatform::flashFilePath(const std::string path) -{ - _flashFilePath = path; -} + void print(unsigned int num) + { + print(num, DEC); + } -std::string LinuxPlatform::flashFilePath() -{ - return _flashFilePath; -} + void print(unsigned int num, int base) + { + if (base == HEX) + printf("%X", num); + else + printf("%d", num); + } + void print(long num) + { + print(num, DEC); + } + void print(long num, int base) + { + if (base == HEX) + printf("%lX", num); + else + printf("%ld", num); + } -size_t LinuxPlatform::readBytesUart(uint8_t* buffer, size_t length) -{ - return read(_uartFd, buffer, length); -} + void print(unsigned long num) + { + print(num, DEC); + } -int LinuxPlatform::readUart() -{ - uint8_t x ; + void print(unsigned long num, int base) + { + if (base == HEX) + printf("%lX", num); + else + printf("%ld", num); + } - if (read(_uartFd, &x, 1) != 1) + void print(unsigned long long num) { - return -1; + printUint64(num); } - return ((int)x) & 0xFF ; -} + void print(unsigned long long num, int base) + { + printUint64(num, base); + } -size_t LinuxPlatform::writeUart(const uint8_t* buffer, size_t size) -{ - return write(_uartFd, buffer, size) ; -} + void print(double num) + { + printf("%f", num); + } -size_t LinuxPlatform::writeUart(const uint8_t data) -{ - return write(_uartFd, &data, 1) ; -} + void println(const char* s) + { + printf("%s\n", s); + } + void println(char c) + { + printf("%c\n", c); + } -int LinuxPlatform::uartAvailable() -{ - int result ; + void println(unsigned char num) + { + println(num, DEC); + } - if (ioctl(_uartFd, FIONREAD, &result) == -1) + void println(unsigned char num, int base) { - return -1; + if (base == HEX) + printf("%X\n", num); + else + printf("%d\n", num); } - return result ; -} + void println(int num) + { + println(num, DEC); + } -void LinuxPlatform::closeUart() -{ - if (_uartFd >= 0) + void println(int num, int base) { - close(_uartFd); + if (base == HEX) + printf("%X\n", num); + else + printf("%d\n", num); } -} -void LinuxPlatform::setupUart() -{ - /* - * 19200,8E1, no handshake - */ - struct termios options; /* Schnittstellenoptionen */ + void println(unsigned int num) + { + println(num, DEC); + } - /* Port oeffnen - read/write, kein "controlling tty", Status von DCD ignorieren */ - _uartFd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY); + void println(unsigned int num, int base) + { + if (base == HEX) + printf("%X\n", num); + else + printf("%d\n", num); + } - if (_uartFd >= 0) + void println(long num) { - /* get the current options */ - fcntl(_uartFd, F_SETFL, 0); + println(num, DEC); + } - if (tcgetattr(_uartFd, &options) != 0) - { - close(_uartFd); - _uartFd = -1; - return; - } + void println(long num, int base) + { + if (base == HEX) + printf("%lX\n", num); + else + printf("%ld\n", num); + } - memset(&options, 0, sizeof(options)); /* Structur loeschen, ggf. vorher sichern - und bei Programmende wieder restaurieren */ - /* Baudrate setzen */ - cfsetispeed(&options, B19200); - cfsetospeed(&options, B19200); - - /* setze Optionen */ - options.c_cflag |= PARENB; /* Enable Paritybit */ - options.c_cflag &= ~PARODD; /* Even parity */ - options.c_cflag &= ~CSTOPB; /* 1 Stoppbit */ - options.c_cflag &= ~CSIZE; /* 8 Datenbits */ - options.c_cflag |= CS8; - - /* 19200 bps, 8 Datenbits, CD-Signal ignorieren, Lesen erlauben */ - options.c_cflag |= (CLOCAL | CREAD); - - /* Kein Echo, keine Steuerzeichen, keine Interrupts */ - options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); - options.c_iflag = IGNPAR; /* Parity-Fehler ignorieren */ - options.c_oflag &= ~OPOST; /* setze "raw" Input */ - options.c_cc[VMIN] = 0; /* warten auf min. 0 Zeichen */ - options.c_cc[VTIME] = 10; /* Timeout 1 Sekunde */ - tcflush(_uartFd, TCIOFLUSH); /* Puffer leeren */ - - if (tcsetattr(_uartFd, TCSAFLUSH, &options) != 0) - { - close(_uartFd); - _uartFd = -1; - return; - } + void println(unsigned long num) + { + println(num, DEC); } -} -#ifndef KNX_NO_PRINT -void printUint64(uint64_t value, int base = DEC) -{ - char buf[8 * sizeof(uint64_t) + 1]; - char* str = &buf[sizeof(buf) - 1]; - *str = '\0'; + void println(unsigned long num, int base) + { + if (base == HEX) + printf("%lX\n", num); + else + printf("%ld\n", num); + } - uint64_t n = value; + void println(unsigned long long num) + { + printUint64(num); + println(""); + } - do + void println(unsigned long long num, int base) { - char c = n % base; - n /= base; + printUint64(num, base); + println(""); + } - *--str = c < 10 ? c + '0' : c + 'A' - 10; - } while (n > 0); + void println(double num) + { + printf("%f\n", num); + } - print(str); -} - -void print(const char* s) -{ - printf("%s", s); -} -void print(char c) -{ - printf("%c", c); -} + void println(double num, int places) + { + printf("%f\n", num); + } -void print(unsigned char num) -{ - print(num, DEC); -} + void println(void) + { + printf("\n"); + } +#endif // KNX_NO_PRINT -void print(unsigned char num, int base) -{ - if (base == HEX) - printf("%X", num); - else - printf("%d", num); -} + void LinuxPlatform::cmdLineArgs(int argc, char** argv) + { + if (_args) + delete[] _args; -void print(int num) -{ - print(num, DEC); -} + _args = new char* [argc + 1]; + memcpy(_args, argv, argc * sizeof(char*)); + _args[argc] = 0; + } -void print(int num, int base) -{ - if (base == HEX) - printf("%X", num); - else - printf("%d", num); -} + /* Buffer size for string operations (e.g. snprintf())*/ +#define MAX_STRBUF_SIZE 100 +#define MAX_NUM_GPIO 64 -void print(unsigned int num) -{ - print(num, DEC); -} + static int gpioFds[MAX_NUM_GPIO] = + { + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + }; + + /* A ctivate GPIO-Pin + * Write GPIO pin number to /sys/class/gpio/export + * Result: 0 = success, -1 = error + */ + int gpio_export(int pin) + { + char buffer[MAX_STRBUF_SIZE]; /* Output Buffer */ + ssize_t bytes; /* Used Buffer length */ + int fd; /* Filedescriptor */ + int res; /* Result from write() */ -void print(unsigned int num, int base) -{ - if (base == HEX) - printf("%X", num); - else - printf("%d", num); -} + LOGGER.info("Export GPIO pin %d", pin); -void print(long num) -{ - print(num, DEC); -} + fd = open("/sys/class/gpio/export", O_WRONLY); -void print(long num, int base) -{ - if (base == HEX) - printf("%lX", num); - else - printf("%ld", num); -} + if (fd < 0) + { + LOGGER.error("Could not export GPIO pin(open)! %s", strerror(errno)); + return (-1); + } -void print(unsigned long num) -{ - print(num, DEC); -} + bytes = snprintf(buffer, MAX_STRBUF_SIZE, "%d", pin); + res = write(fd, buffer, bytes); -void print(unsigned long num, int base) -{ - if (base == HEX) - printf("%lX", num); - else - printf("%ld", num); -} + if (res < 0) + { + LOGGER.error("Could not export GPIO pin(write)! %s", strerror(errno)); + return (-1); + } -void print(unsigned long long num) -{ - printUint64(num); -} + close(fd); + delay(100); -void print(unsigned long long num, int base) -{ - printUint64(num, base); -} + return (0); + } -void print(double num) -{ - printf("%f", num); -} + /* Deactivate GPIO pin + * Write GPIO pin number to /sys/class/gpio/unexport + * Result: 0 = success, -1 = error + */ + int gpio_unexport(int pin) + { + char buffer[MAX_STRBUF_SIZE]; /* Output Buffer */ + ssize_t bytes; /* Used Buffer length */ + int fd; /* Filedescriptor */ + int res; /* Result from write() */ -void println(const char* s) -{ - printf("%s\n", s); -} -void println(char c) -{ - printf("%c\n", c); -} + LOGGER.info("Unexport GPIO pin %d", pin); -void println(unsigned char num) -{ - println(num, DEC); -} + close(gpioFds[pin]); -void println(unsigned char num, int base) -{ - if (base == HEX) - printf("%X\n", num); - else - printf("%d\n", num); -} + fd = open("/sys/class/gpio/unexport", O_WRONLY); -void println(int num) -{ - println(num, DEC); -} + if (fd < 0) + { + LOGGER.error("Could not unexport GPIO pin(open)! %s", strerror(errno)); + return (-1); + } -void println(int num, int base) -{ - if (base == HEX) - printf("%X\n", num); - else - printf("%d\n", num); -} + bytes = snprintf(buffer, MAX_STRBUF_SIZE, "%d", pin); + res = write(fd, buffer, bytes); -void println(unsigned int num) -{ - println(num, DEC); -} + if (res < 0) + { + LOGGER.error("Could not unexport GPIO pin(write)! %s", strerror(errno)); + return (-1); + } -void println(unsigned int num, int base) -{ - if (base == HEX) - printf("%X\n", num); - else - printf("%d\n", num); -} + close(fd); + return (0); + } -void println(long num) -{ - println(num, DEC); -} + /* Set GPIO pin mode (input/output) + * Write GPIO pin number to /sys/class/gpioXX/direction + * Direction: 0 = input, 1 = output + * Result: 0 = success, -1 = error + */ + int gpio_direction(int pin, int dir) + { + char path[MAX_STRBUF_SIZE]; /* Buffer for path */ + int fd; /* Filedescriptor */ + int res; /* Result from write() */ -void println(long num, int base) -{ - if (base == HEX) - printf("%lX\n", num); - else - printf("%ld\n", num); -} + LOGGER.info("Set GPIO direction for pin %d to %s", pin, (dir == INPUT) ? "INPUT" : "OUTPUT"); -void println(unsigned long num) -{ - println(num, DEC); -} + snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/direction", pin); + fd = open(path, O_WRONLY); -void println(unsigned long num, int base) -{ - if (base == HEX) - printf("%lX\n", num); - else - printf("%ld\n", num); -} + if (fd < 0) + { + LOGGER.error("Could not set mode for GPIO pin(open)! %s", strerror(errno)); + return (-1); + } -void println(unsigned long long num) -{ - printUint64(num); - println(""); -} + switch (dir) + { + case INPUT: + res = write(fd, "in", 2); + break; -void println(unsigned long long num, int base) -{ - printUint64(num, base); - println(""); -} + case OUTPUT: + res = write(fd, "out", 3); + break; -void println(double num) -{ - printf("%f\n", num); -} + default: + res = -1; + break; + } -void println(double num, int places) -{ - printf("%f\n", num); -} + if (res < 0) + { + LOGGER.error("Could not set mode for GPIO pin(write)! %s", strerror(errno)); + return (-1); + } -void println(void) -{ - printf("\n"); -} -#endif // KNX_NO_PRINT + close(fd); + return (0); + } -void pinMode(uint32_t dwPin, uint32_t dwMode) -{ - gpio_export(dwPin); - gpio_direction(dwPin, dwMode); -} + /* Read from GPIO pin + * Result: -1 = error, 0/1 = GPIO pin state + */ + int gpio_read(int pin) + { + char path[MAX_STRBUF_SIZE]; /* Buffer for path */ + char c; -void digitalWrite(uint32_t dwPin, uint32_t dwVal) -{ - gpio_write(dwPin, dwVal); -} + snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/value", pin); -uint32_t digitalRead(uint32_t dwPin) -{ - return gpio_read(dwPin); -} + if (gpioFds[pin] < 0) + gpioFds[pin] = open(path, O_RDWR); -typedef void (*voidFuncPtr)(void); -void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) -{ -} + if ( gpioFds[pin] < 0) + { + LOGGER.error("Could not read from GPIO(open)! %s", strerror(errno)); + return (-1); + } -void LinuxPlatform::cmdLineArgs(int argc, char** argv) -{ - if (_args) - delete[] _args; + lseek(gpioFds[pin], 0L, SEEK_SET); - _args = new char* [argc + 1]; - memcpy(_args, argv, argc * sizeof(char*)); - _args[argc] = 0; -} + if (read(gpioFds[pin], &c, 1) < 0) + { + LOGGER.error("Could not read from GPIO(read)! %s", strerror(errno)); + return (-1); + } -/* Buffer size for string operations (e.g. snprintf())*/ -#define MAX_STRBUF_SIZE 100 -#define MAX_NUM_GPIO 64 + return (c == '0') ? LOW : HIGH; + } -static int gpioFds[MAX_NUM_GPIO] = -{ - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - }; + /* Write to GPIO pin + * Result: -1 = error, 0 = success + */ + int gpio_write(int pin, int value) + { + if (pin < 0) + return -1; -/* Activate GPIO-Pin - * Write GPIO pin number to /sys/class/gpio/export - * Result: 0 = success, -1 = error - */ -int gpio_export(int pin) -{ - char buffer[MAX_STRBUF_SIZE]; /* Output Buffer */ - ssize_t bytes; /* Used Buffer length */ - int fd; /* Filedescriptor */ - int res; /* Result from write() */ + char path[MAX_STRBUF_SIZE]; /* Buffer for path */ + int res; /* Result from write()*/ - LOGGER.info("Export GPIO pin %d", pin); + snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/value", pin); - fd = open("/sys/class/gpio/export", O_WRONLY); + if (gpioFds[pin] < 0) + gpioFds[pin] = open(path, O_RDWR); - if (fd < 0) - { - LOGGER.error("Could not export GPIO pin(open)! %s", strerror(errno)); - return (-1); - } + if ( gpioFds[pin] < 0) + { + LOGGER.error("Could not write to GPIO(open)! %s", strerror(errno)); + return (-1); + } - bytes = snprintf(buffer, MAX_STRBUF_SIZE, "%d", pin); - res = write(fd, buffer, bytes); + switch (value) + { + case LOW: + res = write(gpioFds[pin], "0\n", 2); + break; - if (res < 0) - { - LOGGER.error("Could not export GPIO pin(write)! %s", strerror(errno)); - return (-1); - } + case HIGH: + res = write(gpioFds[pin], "1\n", 2); + break; - close(fd); - delay(100); + default: + res = -1; + break; + } - return (0); -} + if (res < 0) + { + LOGGER.error("Could not write to GPIO(write)! %s", strerror(errno)); + return (-1); + } -/* Deactivate GPIO pin - * Write GPIO pin number to /sys/class/gpio/unexport - * Result: 0 = success, -1 = error - */ -int gpio_unexport(int pin) -{ - char buffer[MAX_STRBUF_SIZE]; /* Output Buffer */ - ssize_t bytes; /* Used Buffer length */ - int fd; /* Filedescriptor */ - int res; /* Result from write() */ + return (0); + } - LOGGER.info("Unexport GPIO pin %d", pin); + /* Set GPIO pin edge detection + * 'r' (rising) + * 'f' (falling) + * 'b' (both) + */ + int gpio_edge(unsigned int pin, char edge) + { + char path[MAX_STRBUF_SIZE]; /* Buffer for path */ + int fd; /* Filedescriptor */ - close(gpioFds[pin]); + snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/edge", pin); - fd = open("/sys/class/gpio/unexport", O_WRONLY); + fd = open(path, O_WRONLY | O_NONBLOCK); - if (fd < 0) - { - LOGGER.error("Could not unexport GPIO pin(open)! %s", strerror(errno)); - return (-1); - } + if (fd < 0) + { + LOGGER.error("Could not set GPIO edge detection(open)! %s", strerror(errno)); + return (-1); + } - bytes = snprintf(buffer, MAX_STRBUF_SIZE, "%d", pin); - res = write(fd, buffer, bytes); + switch (edge) + { + case 'r': + strncpy(path, "rising", 8); + break; - if (res < 0) - { - LOGGER.error("Could not unexport GPIO pin(write)! %s", strerror(errno)); - return (-1); - } + case 'f': + strncpy(path, "falling", 8); + break; - close(fd); - return (0); -} + case 'b': + strncpy(path, "both", 8); + break; -/* Set GPIO pin mode (input/output) - * Write GPIO pin number to /sys/class/gpioXX/direction - * Direction: 0 = input, 1 = output - * Result: 0 = success, -1 = error - */ -int gpio_direction(int pin, int dir) -{ - char path[MAX_STRBUF_SIZE]; /* Buffer for path */ - int fd; /* Filedescriptor */ - int res; /* Result from write() */ + case 'n': + strncpy(path, "none", 8); + break; - LOGGER.info("Set GPIO direction for pin %d to %s", pin, (dir == INPUT) ? "INPUT" : "OUTPUT"); + default: + close(fd); + return (-2); + } - snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/direction", pin); - fd = open(path, O_WRONLY); + write(fd, path, strlen(path) + 1); - if (fd < 0) - { - LOGGER.error("Could not set mode for GPIO pin(open)! %s", strerror(errno)); - return (-1); + close(fd); + return 0; } - switch (dir) + /* Wait for edge on GPIO pin + * timeout in milliseconds + * Result: <0: error, 0: poll() Timeout, + * 1: edge detected, GPIO pin reads "0" + * 2: edge detected, GPIO pin reads "1" + */ + int gpio_wait(unsigned int pin, int timeout) { - case INPUT: - res = write(fd, "in", 2); - break; + char path[MAX_STRBUF_SIZE]; /* Buffer for path */ + int fd; /* Filedescriptor */ + struct pollfd polldat[1]; /* Variable for poll() */ + char buf[MAX_STRBUF_SIZE]; /* Read buffer */ + int rc; /* Result */ - case OUTPUT: - res = write(fd, "out", 3); - break; + /* Open GPIO pin */ + snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/value", pin); + fd = open(path, O_RDONLY | O_NONBLOCK); - default: - res = -1; - break; - } + if (fd < 0) + { + LOGGER.error("Could not wait for GPIO edge(open)! %s", strerror(errno)); + return (-1); + } - if (res < 0) - { - LOGGER.error("Could not set mode for GPIO pin(write)! %s", strerror(errno)); - return (-1); - } + /* prepare poll() */ + memset((void*)buf, 0, sizeof(buf)); + memset((void*)polldat, 0, sizeof(polldat)); + polldat[0].fd = fd; + polldat[0].events = POLLPRI; - close(fd); - return (0); -} + /* clear any existing detected edges before */ + lseek(fd, 0, SEEK_SET); + rc = read(fd, buf, MAX_STRBUF_SIZE - 1); -/* Read from GPIO pin - * Result: -1 = error, 0/1 = GPIO pin state - */ -int gpio_read(int pin) -{ - char path[MAX_STRBUF_SIZE]; /* Buffer for path */ - char c; + rc = poll(polldat, 1, timeout); - snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/value", pin); + if (rc < 0) + { + /* poll() failed! */ + LOGGER.error("Could not wait for GPIO edge(poll)! %s", strerror(errno)); + close(fd); + return (-1); + } - if (gpioFds[pin] < 0) - gpioFds[pin] = open(path, O_RDWR); + if (rc == 0) + { + /* poll() timeout! */ + close(fd); + return (0); + } - if (gpioFds[pin] < 0) - { - LOGGER.error("Could not read from GPIO(open)! %s", strerror(errno)); - return (-1); - } + if (polldat[0].revents & POLLPRI) + { + if (rc < 0) + { + /* read() failed! */ + LOGGER.error("Could not wait for GPIO edge(read)! %s", strerror(errno)); + close(fd); + return (-2); + } - lseek(gpioFds[pin], 0L, SEEK_SET); + /* printf("poll() GPIO %d interrupt occurred: %s\n", pin, buf); */ + close(fd); + return (1 + atoi(buf)); + } - if (read(gpioFds[pin], &c, 1) < 0) - { - LOGGER.error("Could not read from GPIO(read)! %s", strerror(errno)); + close(fd); return (-1); } - return (c == '0') ? LOW : HIGH; -} - -/* Write to GPIO pin - * Result: -1 = error, 0 = success - */ -int gpio_write(int pin, int value) -{ - if (pin < 0) - return -1; + bool LinuxPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) + { + struct sockaddr_in address = {0}; + address.sin_family = AF_INET; + address.sin_addr.s_addr = htonl(addr); + address.sin_port = htons(port); - char path[MAX_STRBUF_SIZE]; /* Buffer for path */ - int res; /* Result from write()*/ + ssize_t retVal = 0; - snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/value", pin); + do + { + retVal = sendto(_multicastSocketFd, buffer, len, 0, (struct sockaddr*)&address, sizeof(address)); - if (gpioFds[pin] < 0) - gpioFds[pin] = open(path, O_RDWR); + if (retVal == -1) + { + if (errno != EAGAIN && errno != EWOULDBLOCK) + return false; + } + } while (retVal == -1); - if (gpioFds[pin] < 0) - { - LOGGER.error("Could not write to GPIO(open)! %s", strerror(errno)); - return (-1); + // printHex("<-", buffer, len); + return true; } - switch (value) + void LinuxPlatform::macAddress(uint8_t* mac_address) { - case LOW: - res = write(gpioFds[pin], "0\n", 2); - break; - - case HIGH: - res = write(gpioFds[pin], "1\n", 2); - break; - - default: - res = -1; - break; + memcpy(mac_address, _macAddress, IFHWADDRLEN); } - if (res < 0) + uint32_t LinuxPlatform::currentIpAddress() { - LOGGER.error("Could not write to GPIO(write)! %s", strerror(errno)); - return (-1); + return _ipAddress; } - return (0); -} - -/* Set GPIO pin edge detection - * 'r' (rising) - * 'f' (falling) - * 'b' (both) - */ -int gpio_edge(unsigned int pin, char edge) -{ - char path[MAX_STRBUF_SIZE]; /* Buffer for path */ - int fd; /* Filedescriptor */ - - snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/edge", pin); - - fd = open(path, O_WRONLY | O_NONBLOCK); - - if (fd < 0) + uint32_t LinuxPlatform::currentSubnetMask() { - LOGGER.error("Could not set GPIO edge detection(open)! %s", strerror(errno)); - return (-1); + return _netmask; } - switch (edge) + uint32_t LinuxPlatform::currentDefaultGateway() { - case 'r': - strncpy(path, "rising", 8); - break; - - case 'f': - strncpy(path, "falling", 8); - break; - - case 'b': - strncpy(path, "both", 8); - break; - - case 'n': - strncpy(path, "none", 8); - break; - - default: - close(fd); - return (-2); + return _defaultGateway; } - - write(fd, path, strlen(path) + 1); - - close(fd); - return 0; } -/* Wait for edge on GPIO pin - * timeout in milliseconds - * Result: <0: error, 0: poll() Timeout, - * 1: edge detected, GPIO pin reads "0" - * 2: edge detected, GPIO pin reads "1" - */ -int gpio_wait(unsigned int pin, int timeout) +void pinMode(uint32_t dwPin, uint32_t dwMode) { - char path[MAX_STRBUF_SIZE]; /* Buffer for path */ - int fd; /* Filedescriptor */ - struct pollfd polldat[1]; /* Variable for poll() */ - char buf[MAX_STRBUF_SIZE]; /* Read buffer */ - int rc; /* Result */ - - /* Open GPIO pin */ - snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/value", pin); - fd = open(path, O_RDONLY | O_NONBLOCK); - - if (fd < 0) - { - LOGGER.error("Could not wait for GPIO edge(open)! %s", strerror(errno)); - return (-1); - } - - /* prepare poll() */ - memset((void*)buf, 0, sizeof(buf)); - memset((void*)polldat, 0, sizeof(polldat)); - polldat[0].fd = fd; - polldat[0].events = POLLPRI; - - /* clear any existing detected edges before */ - lseek(fd, 0, SEEK_SET); - rc = read(fd, buf, MAX_STRBUF_SIZE - 1); + Knx::gpio_export(dwPin); + Knx::gpio_direction(dwPin, dwMode); +} - rc = poll(polldat, 1, timeout); +void digitalWrite(uint32_t dwPin, uint32_t dwVal) +{ + Knx::gpio_write(dwPin, dwVal); +} - if (rc < 0) - { - /* poll() failed! */ - LOGGER.error("Could not wait for GPIO edge(poll)! %s", strerror(errno)); - close(fd); - return (-1); - } +uint32_t digitalRead(uint32_t dwPin) +{ + return Knx::gpio_read(dwPin); +} - if (rc == 0) - { - /* poll() timeout! */ - close(fd); - return (0); - } +typedef void (*voidFuncPtr)(void); +void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) +{ +} - if (polldat[0].revents & POLLPRI) - { - if (rc < 0) - { - /* read() failed! */ - LOGGER.error("Could not wait for GPIO edge(read)! %s", strerror(errno)); - close(fd); - return (-2); - } +uint32_t millis() +{ + struct timespec spec; - /* printf("poll() GPIO %d interrupt occurred: %s\n", pin, buf); */ - close(fd); - return (1 + atoi(buf)); - } + clock_gettime(CLOCK_MONOTONIC, &spec); + return spec.tv_sec * 1000 + round(spec.tv_nsec / 1.0e6); +} - close(fd); - return (-1); +void delay(uint32_t millis) +{ + struct timespec ts; + ts.tv_sec = millis / 1000; + ts.tv_nsec = (millis % 1000) * 1000000; + nanosleep(&ts, NULL); } void delayMicrosecondsHard(unsigned int howLong) @@ -1191,48 +1237,4 @@ void delayMicroseconds(unsigned int howLong) nanosleep(&sleeper, NULL); } } - -bool LinuxPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) -{ - struct sockaddr_in address = {0}; - address.sin_family = AF_INET; - address.sin_addr.s_addr = htonl(addr); - address.sin_port = htons(port); - - ssize_t retVal = 0; - - do - { - retVal = sendto(_multicastSocketFd, buffer, len, 0, (struct sockaddr*)&address, sizeof(address)); - - if (retVal == -1) - { - if (errno != EAGAIN && errno != EWOULDBLOCK) - return false; - } - } while (retVal == -1); - - // printHex("<-", buffer, len); - return true; -} - -void LinuxPlatform::macAddress(uint8_t* mac_address) -{ - memcpy(mac_address, _macAddress, IFHWADDRLEN); -} - -uint32_t LinuxPlatform::currentIpAddress() -{ - return _ipAddress; -} - -uint32_t LinuxPlatform::currentSubnetMask() -{ - return _netmask; -} - -uint32_t LinuxPlatform::currentDefaultGateway() -{ - return _defaultGateway; -} -#endif +#endif \ No newline at end of file diff --git a/src/knx/platform/linux_platform.h b/src/knx/platform/linux_platform.h index a9f05de8..c42d2c78 100644 --- a/src/knx/platform/linux_platform.h +++ b/src/knx/platform/linux_platform.h @@ -5,77 +5,79 @@ #include "platform.h" #include -extern int gpio_direction(int pin, int dir); -extern int gpio_read(int pin); -extern int gpio_write(int pin, int value); -extern int gpio_export(int pin); -extern int gpio_unexport(int pin); - -class LinuxPlatform: public Platform +namespace Knx { - public: - LinuxPlatform(); - virtual ~LinuxPlatform(); - - void cmdLineArgs(int argc, char** argv); - - std::string flashFilePath(); - void flashFilePath(const std::string path); - - // basic stuff - void restart() override; - void fatalError() override; - - // ip config - uint32_t currentIpAddress() override; - uint32_t currentSubnetMask() override; - uint32_t currentDefaultGateway() override; - void macAddress(uint8_t* data) override; - - - //multicast - void setupMultiCast(uint32_t addr, uint16_t port) override; - void closeMultiCast() override; - bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override; - int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) override; - bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override; - - //UART - void setupUart() override; - void closeUart() override; - int uartAvailable() override; - size_t writeUart(const uint8_t data) override; - size_t writeUart(const uint8_t* buffer, size_t size) override; - int readUart() override; - size_t readBytesUart(uint8_t* buffer, size_t length) override; - - //spi - void setupSpi() override; - void closeSpi() override; - int readWriteSpi (uint8_t* data, size_t len) override; - - //memory - uint8_t* getEepromBuffer(uint32_t size) override; - void commitToEeprom() override; - void cmdlineArgs(int argc, char** argv); - - private: - uint32_t _multicastAddr = -1; - uint16_t _multicastPort = -1; - int _multicastSocketFd = -1; - - void doMemoryMapping(); - uint8_t* _mappedFile = 0; - int _fd = -1; - int _spiFd = -1; - int _uartFd = -1; - std::string _flashFilePath = "flash.bin"; - char** _args = 0; - - uint8_t _macAddress[6] = {0, 0, 0, 0, 0, 0}; - uint32_t _ipAddress = 0; - uint32_t _netmask = 0; - uint32_t _defaultGateway = 0; -}; - -#endif + extern int gpio_direction(int pin, int dir); + extern int gpio_read(int pin); + extern int gpio_write(int pin, int value); + extern int gpio_export(int pin); + extern int gpio_unexport(int pin); + + class LinuxPlatform: public Platform + { + public: + LinuxPlatform(); + virtual ~LinuxPlatform(); + + void cmdLineArgs(int argc, char** argv); + + std::string flashFilePath(); + void flashFilePath(const std::string path); + + // basic stuff + void restart() override; + void fatalError() override; + + // ip config + uint32_t currentIpAddress() override; + uint32_t currentSubnetMask() override; + uint32_t currentDefaultGateway() override; + void macAddress(uint8_t* data) override; + + + //multicast + void setupMultiCast(uint32_t addr, uint16_t port) override; + void closeMultiCast() override; + bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override; + int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) override; + bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override; + + //UART + void setupUart() override; + void closeUart() override; + int uartAvailable() override; + size_t writeUart(const uint8_t data) override; + size_t writeUart(const uint8_t* buffer, size_t size) override; + int readUart() override; + size_t readBytesUart(uint8_t* buffer, size_t length) override; + + //spi + void setupSpi() override; + void closeSpi() override; + int readWriteSpi (uint8_t* data, size_t len) override; + + //memory + uint8_t* getEepromBuffer(uint32_t size) override; + void commitToEeprom() override; + void cmdlineArgs(int argc, char** argv); + + private: + uint32_t _multicastAddr = -1; + uint16_t _multicastPort = -1; + int _multicastSocketFd = -1; + + void doMemoryMapping(); + uint8_t* _mappedFile = 0; + int _fd = -1; + int _spiFd = -1; + int _uartFd = -1; + std::string _flashFilePath = "flash.bin"; + char** _args = 0; + + uint8_t _macAddress[6] = {0, 0, 0, 0, 0, 0}; + uint32_t _ipAddress = 0; + uint32_t _netmask = 0; + uint32_t _defaultGateway = 0; + }; +} +#endif \ No newline at end of file diff --git a/src/knx/platform/platform.cpp b/src/knx/platform/platform.cpp index 79dd90da..825b5d15 100644 --- a/src/knx/platform/platform.cpp +++ b/src/knx/platform/platform.cpp @@ -5,447 +5,450 @@ #include #include -NvMemoryType Platform::NonVolatileMemoryType() +namespace Knx { - return _memoryType; -} + NvMemoryType Platform::NonVolatileMemoryType() + { + return _memoryType; + } -void Platform::NonVolatileMemoryType(NvMemoryType type) -{ - _memoryType = type; -} + void Platform::NonVolatileMemoryType(NvMemoryType type) + { + _memoryType = type; + } -void Platform::setupSpi() -{} + void Platform::setupSpi() + {} -void Platform::closeSpi() -{} + void Platform::closeSpi() + {} -int Platform::readWriteSpi(uint8_t* data, size_t len) -{ - return 0; -} + int Platform::readWriteSpi(uint8_t* data, size_t len) + { + return 0; + } -size_t Platform::readBytesUart(uint8_t* buffer, size_t length) -{ - return 0; -} + size_t Platform::readBytesUart(uint8_t* buffer, size_t length) + { + return 0; + } -int Platform::readUart() -{ - return -1; -} + int Platform::readUart() + { + return -1; + } -size_t Platform::writeUart(const uint8_t* buffer, size_t size) -{ - return 0; -} + size_t Platform::writeUart(const uint8_t* buffer, size_t size) + { + return 0; + } -size_t Platform::writeUart(const uint8_t data) -{ - return 0; -} + size_t Platform::writeUart(const uint8_t data) + { + return 0; + } -int Platform::uartAvailable() -{ - return 0; -} + int Platform::uartAvailable() + { + return 0; + } -void Platform::closeUart() -{} + void Platform::closeUart() + {} -void Platform::setupUart() -{} + void Platform::setupUart() + {} -bool Platform::overflowUart() -{ - return false; -} + bool Platform::overflowUart() + { + return false; + } -void Platform::flushUart() -{} + void Platform::flushUart() + {} -uint32_t Platform::currentIpAddress() -{ - return 0x01020304; -} + uint32_t Platform::currentIpAddress() + { + return 0x01020304; + } -uint32_t Platform::currentSubnetMask() -{ - return 0; -} + uint32_t Platform::currentSubnetMask() + { + return 0; + } -uint32_t Platform::currentDefaultGateway() -{ - return 0; -} + uint32_t Platform::currentDefaultGateway() + { + return 0; + } -void Platform::macAddress(uint8_t* data) -{} + void Platform::macAddress(uint8_t* data) + {} -uint32_t Platform::uniqueSerialNumber() -{ - return 0x01020304; -} + uint32_t Platform::uniqueSerialNumber() + { + return 0x01020304; + } -void Platform::setupMultiCast(uint32_t addr, uint16_t port) -{} + void Platform::setupMultiCast(uint32_t addr, uint16_t port) + {} -void Platform::closeMultiCast() -{} + void Platform::closeMultiCast() + {} -bool Platform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) -{ - return false; -} + bool Platform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) + { + return false; + } -bool Platform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) -{ - return false; -} + bool Platform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) + { + return false; + } -int Platform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) -{ - return 0; -} + int Platform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) + { + return 0; + } -int Platform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port) -{ - return readBytesMultiCast(buffer, maxLen); -} + int Platform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port) + { + return readBytesMultiCast(buffer, maxLen); + } -size_t Platform::flashEraseBlockSize() -{ - return 0; -} + size_t Platform::flashEraseBlockSize() + { + return 0; + } -size_t Platform::flashPageSize() -{ - // align to 32bit as default for Eeprom Emulation plattforms - return 4; -} + size_t Platform::flashPageSize() + { + // align to 32bit as default for Eeprom Emulation plattforms + return 4; + } -uint8_t* Platform::userFlashStart() -{ - return nullptr; -} + uint8_t* Platform::userFlashStart() + { + return nullptr; + } -size_t Platform::userFlashSizeEraseBlocks() -{ - return 0; -} + size_t Platform::userFlashSizeEraseBlocks() + { + return 0; + } -void Platform::flashErase(uint16_t eraseBlockNum) -{} + void Platform::flashErase(uint16_t eraseBlockNum) + {} -void Platform::flashWritePage(uint16_t pageNumber, uint8_t* data) -{} + void Platform::flashWritePage(uint16_t pageNumber, uint8_t* data) + {} -uint8_t* Platform::getEepromBuffer(uint32_t size) -{ - return nullptr; -} + uint8_t* Platform::getEepromBuffer(uint32_t size) + { + return nullptr; + } -void Platform::commitToEeprom() -{} + void Platform::commitToEeprom() + {} -uint8_t* Platform::getNonVolatileMemoryStart() -{ - if (_memoryType == Flash) - return userFlashStart(); + uint8_t* Platform::getNonVolatileMemoryStart() + { + if (_memoryType == Flash) + return userFlashStart(); #ifdef KNX_FLASH_CALLBACK - else if (_memoryType == Callback) - return _callbackFlashRead(); + else if (_memoryType == Callback) + return _callbackFlashRead(); #endif - else - return getEepromBuffer(KNX_FLASH_SIZE); -} + else + return getEepromBuffer(KNX_FLASH_SIZE); + } -size_t Platform::getNonVolatileMemorySize() -{ - if (_memoryType == Flash) - return userFlashSizeEraseBlocks() * flashEraseBlockSize() * flashPageSize(); + size_t Platform::getNonVolatileMemorySize() + { + if (_memoryType == Flash) + return userFlashSizeEraseBlocks() * flashEraseBlockSize() * flashPageSize(); #ifdef KNX_FLASH_CALLBACK - else if (_memoryType == Callback) - return _callbackFlashSize(); + else if (_memoryType == Callback) + return _callbackFlashSize(); #endif - else - return KNX_FLASH_SIZE; -} + else + return KNX_FLASH_SIZE; + } -void Platform::commitNonVolatileMemory() -{ - if (_memoryType == Flash) + void Platform::commitNonVolatileMemory() { - if (_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) + if (_memoryType == Flash) { - writeBufferedEraseBlock(); + if (_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) + { + writeBufferedEraseBlock(); - free(_eraseblockBuffer); - _eraseblockBuffer = nullptr; - _bufferedEraseblockNumber = -1; // does that make sense? + free(_eraseblockBuffer); + _eraseblockBuffer = nullptr; + _bufferedEraseblockNumber = -1; // does that make sense? + } } - } #ifdef KNX_FLASH_CALLBACK - else if (_memoryType == Callback) - return _callbackFlashCommit(); + else if (_memoryType == Callback) + return _callbackFlashCommit(); #endif - else - { - commitToEeprom(); + else + { + commitToEeprom(); + } } -} -uint32_t Platform::writeNonVolatileMemory(uint32_t relativeAddress, uint8_t* buffer, size_t size) -{ + uint32_t Platform::writeNonVolatileMemory(uint32_t relativeAddress, uint8_t* buffer, size_t size) + { #ifdef KNX_LOG_MEM - print("Platform::writeNonVolatileMemory relativeAddress "); - print(relativeAddress); - print(" size "); - println(size); + print("Platform::writeNonVolatileMemory relativeAddress "); + print(relativeAddress); + print(" size "); + println(size); #endif - if (_memoryType == Flash) - { - while (size > 0) + if (_memoryType == Flash) { - loadEraseblockContaining(relativeAddress); - uint32_t start = _bufferedEraseblockNumber * (flashEraseBlockSize() * flashPageSize()); - uint32_t end = start + (flashEraseBlockSize() * flashPageSize()); + while (size > 0) + { + loadEraseblockContaining(relativeAddress); + uint32_t start = _bufferedEraseblockNumber * (flashEraseBlockSize() * flashPageSize()); + uint32_t end = start + (flashEraseBlockSize() * flashPageSize()); - uint32_t offset = relativeAddress - start; - uint32_t length = end - relativeAddress; + uint32_t offset = relativeAddress - start; + uint32_t length = end - relativeAddress; - if (length > size) - length = size; + if (length > size) + length = size; - memcpy(_eraseblockBuffer + offset, buffer, length); - _bufferedEraseblockDirty = true; + memcpy(_eraseblockBuffer + offset, buffer, length); + _bufferedEraseblockDirty = true; - relativeAddress += length; - buffer += length; - size -= length; - } + relativeAddress += length; + buffer += length; + size -= length; + } - return relativeAddress; - } + return relativeAddress; + } #ifdef KNX_FLASH_CALLBACK - else if (_memoryType == Callback) - return _callbackFlashWrite(relativeAddress, buffer, size); + else if (_memoryType == Callback) + return _callbackFlashWrite(relativeAddress, buffer, size); #endif - else - { - memcpy(getEepromBuffer(KNX_FLASH_SIZE) + relativeAddress, buffer, size); - return relativeAddress + size; + else + { + memcpy(getEepromBuffer(KNX_FLASH_SIZE) + relativeAddress, buffer, size); + return relativeAddress + size; + } } -} -uint32_t Platform::readNonVolatileMemory(uint32_t relativeAddress, uint8_t* buffer, size_t size) -{ + uint32_t Platform::readNonVolatileMemory(uint32_t relativeAddress, uint8_t* buffer, size_t size) + { #ifdef KNX_LOG_MEM - print("Platform::readNonVolatileMemory relativeAddress "); - print(relativeAddress); - print(" size "); - println(size); + print("Platform::readNonVolatileMemory relativeAddress "); + print(relativeAddress); + print(" size "); + println(size); #endif - if (_memoryType == Flash) - { - uint32_t offset = 0; - - while (size > 0) + if (_memoryType == Flash) { - // bufferd block is "left" of requested memory, read until the end and return - if (_bufferedEraseblockNumber < getEraseBlockNumberOf(relativeAddress)) - { - memcpy(buffer + offset, userFlashStart() + relativeAddress, size); - return relativeAddress + size; - } - // bufferd block is "right" of requested memory, and may interfere - else if (_bufferedEraseblockNumber > getEraseBlockNumberOf(relativeAddress)) - { - // if the end of the requested memory is before the buffered block, read until the end and return - int32_t eraseblockNumberEnd = getEraseBlockNumberOf(relativeAddress + size - 1); + uint32_t offset = 0; - if (_bufferedEraseblockNumber > eraseblockNumberEnd) + while (size > 0) + { + // bufferd block is "left" of requested memory, read until the end and return + if (_bufferedEraseblockNumber < getEraseBlockNumberOf(relativeAddress)) { memcpy(buffer + offset, userFlashStart() + relativeAddress, size); return relativeAddress + size; } - // if not, read until the buffered block starts and loop through while again - else - { - uint32_t sizeToRead = (eraseblockNumberEnd * flashEraseBlockSize()) - relativeAddress; - memcpy(buffer + offset, userFlashStart() + relativeAddress, sizeToRead); - relativeAddress += sizeToRead; - size -= sizeToRead; - offset += sizeToRead; - } - } - // start of requested memory is within the buffered erase block - else - { - // if the end of the requested memory is also in the buffered block, read until the end and return - int32_t eraseblockNumberEnd = getEraseBlockNumberOf(relativeAddress + size - 1); - - if (_bufferedEraseblockNumber == eraseblockNumberEnd) + // bufferd block is "right" of requested memory, and may interfere + else if (_bufferedEraseblockNumber > getEraseBlockNumberOf(relativeAddress)) { - uint8_t* start = _eraseblockBuffer + (relativeAddress - _bufferedEraseblockNumber * flashEraseBlockSize()); - memcpy(buffer + offset, start, size); - return relativeAddress + size; + // if the end of the requested memory is before the buffered block, read until the end and return + int32_t eraseblockNumberEnd = getEraseBlockNumberOf(relativeAddress + size - 1); + + if (_bufferedEraseblockNumber > eraseblockNumberEnd) + { + memcpy(buffer + offset, userFlashStart() + relativeAddress, size); + return relativeAddress + size; + } + // if not, read until the buffered block starts and loop through while again + else + { + uint32_t sizeToRead = (eraseblockNumberEnd * flashEraseBlockSize()) - relativeAddress; + memcpy(buffer + offset, userFlashStart() + relativeAddress, sizeToRead); + relativeAddress += sizeToRead; + size -= sizeToRead; + offset += sizeToRead; + } } - // if not, read until the end of the buffered block and loop through while again + // start of requested memory is within the buffered erase block else { - uint32_t offsetInBufferedBlock = relativeAddress - _bufferedEraseblockNumber * flashEraseBlockSize(); - uint8_t* start = _eraseblockBuffer + offsetInBufferedBlock; - uint32_t sizeToRead = flashEraseBlockSize() - offsetInBufferedBlock; - memcpy(buffer + offset, start, sizeToRead); - relativeAddress += sizeToRead; - size -= sizeToRead; - offset += sizeToRead; + // if the end of the requested memory is also in the buffered block, read until the end and return + int32_t eraseblockNumberEnd = getEraseBlockNumberOf(relativeAddress + size - 1); + + if (_bufferedEraseblockNumber == eraseblockNumberEnd) + { + uint8_t* start = _eraseblockBuffer + (relativeAddress - _bufferedEraseblockNumber * flashEraseBlockSize()); + memcpy(buffer + offset, start, size); + return relativeAddress + size; + } + // if not, read until the end of the buffered block and loop through while again + else + { + uint32_t offsetInBufferedBlock = relativeAddress - _bufferedEraseblockNumber * flashEraseBlockSize(); + uint8_t* start = _eraseblockBuffer + offsetInBufferedBlock; + uint32_t sizeToRead = flashEraseBlockSize() - offsetInBufferedBlock; + memcpy(buffer + offset, start, sizeToRead); + relativeAddress += sizeToRead; + size -= sizeToRead; + offset += sizeToRead; + } } } - } - return relativeAddress; - } - else - { - memcpy(buffer, getEepromBuffer(KNX_FLASH_SIZE) + relativeAddress, size); - return relativeAddress + size; + return relativeAddress; + } + else + { + memcpy(buffer, getEepromBuffer(KNX_FLASH_SIZE) + relativeAddress, size); + return relativeAddress + size; + } } -} -// writes value repeat times into flash starting at relativeAddress -// returns next free relativeAddress -uint32_t Platform::writeNonVolatileMemory(uint32_t relativeAddress, uint8_t value, size_t repeat) -{ - if (_memoryType == Flash) + // writes value repeat times into flash starting at relativeAddress + // returns next free relativeAddress + uint32_t Platform::writeNonVolatileMemory(uint32_t relativeAddress, uint8_t value, size_t repeat) { - while (repeat > 0) + if (_memoryType == Flash) { - loadEraseblockContaining(relativeAddress); - uint32_t start = _bufferedEraseblockNumber * (flashEraseBlockSize() * flashPageSize()); - uint32_t end = start + (flashEraseBlockSize() * flashPageSize()); + while (repeat > 0) + { + loadEraseblockContaining(relativeAddress); + uint32_t start = _bufferedEraseblockNumber * (flashEraseBlockSize() * flashPageSize()); + uint32_t end = start + (flashEraseBlockSize() * flashPageSize()); - uint32_t offset = relativeAddress - start; - uint32_t length = end - relativeAddress; + uint32_t offset = relativeAddress - start; + uint32_t length = end - relativeAddress; - if (length > repeat) - length = repeat; + if (length > repeat) + length = repeat; - memset(_eraseblockBuffer + offset, value, length); - _bufferedEraseblockDirty = true; + memset(_eraseblockBuffer + offset, value, length); + _bufferedEraseblockDirty = true; - relativeAddress += length; - repeat -= length; - } + relativeAddress += length; + repeat -= length; + } - return relativeAddress; + return relativeAddress; + } + else + { + memset(getEepromBuffer(KNX_FLASH_SIZE) + relativeAddress, value, repeat); + return relativeAddress + repeat; + } } - else + + void Platform::loadEraseblockContaining(uint32_t relativeAddress) { - memset(getEepromBuffer(KNX_FLASH_SIZE) + relativeAddress, value, repeat); - return relativeAddress + repeat; - } -} + int32_t blockNum = getEraseBlockNumberOf(relativeAddress); -void Platform::loadEraseblockContaining(uint32_t relativeAddress) -{ - int32_t blockNum = getEraseBlockNumberOf(relativeAddress); + if (blockNum < 0) + { + println("loadEraseblockContaining could not get valid eraseblock number"); + fatalError(); + } + + if (blockNum != _bufferedEraseblockNumber && _bufferedEraseblockNumber >= 0) + writeBufferedEraseBlock(); + + bufferEraseBlock(blockNum); + } - if (blockNum < 0) + int32_t Platform::getEraseBlockNumberOf(uint32_t relativeAddress) { - println("loadEraseblockContaining could not get valid eraseblock number"); - fatalError(); + return relativeAddress / (flashEraseBlockSize() * flashPageSize()); } - if (blockNum != _bufferedEraseblockNumber && _bufferedEraseblockNumber >= 0) - writeBufferedEraseBlock(); - bufferEraseBlock(blockNum); -} + void Platform::writeBufferedEraseBlock() + { + if (_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) + { + flashErase(_bufferedEraseblockNumber); + + for (uint32_t i = 0; i < flashEraseBlockSize(); i++) + { + int32_t pageNumber = _bufferedEraseblockNumber * flashEraseBlockSize() + i; + uint8_t* data = _eraseblockBuffer + flashPageSize() * i; + flashWritePage(pageNumber, data); + } -int32_t Platform::getEraseBlockNumberOf(uint32_t relativeAddress) -{ - return relativeAddress / (flashEraseBlockSize() * flashPageSize()); -} + _bufferedEraseblockDirty = false; + } + } -void Platform::writeBufferedEraseBlock() -{ - if (_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) + void Platform::bufferEraseBlock(int32_t eraseBlockNumber) { - flashErase(_bufferedEraseblockNumber); + if (_bufferedEraseblockNumber == eraseBlockNumber) + return; - for (uint32_t i = 0; i < flashEraseBlockSize(); i++) + if (_eraseblockBuffer == nullptr) { - int32_t pageNumber = _bufferedEraseblockNumber * flashEraseBlockSize() + i; - uint8_t* data = _eraseblockBuffer + flashPageSize() * i; - flashWritePage(pageNumber, data); + _eraseblockBuffer = (uint8_t*)malloc(flashEraseBlockSize() * flashPageSize()); } + memcpy(_eraseblockBuffer, userFlashStart() + eraseBlockNumber * flashEraseBlockSize() * flashPageSize(), flashEraseBlockSize() * flashPageSize()); + + _bufferedEraseblockNumber = eraseBlockNumber; _bufferedEraseblockDirty = false; } -} -void Platform::bufferEraseBlock(int32_t eraseBlockNumber) -{ - if (_bufferedEraseblockNumber == eraseBlockNumber) - return; - - if (_eraseblockBuffer == nullptr) +#ifdef KNX_FLASH_CALLBACK + void Platform::registerFlashCallbacks( + FlashCallbackSize callbackFlashSize, + FlashCallbackRead callbackFlashRead, + FlashCallbackWrite callbackFlashWrite, + FlashCallbackCommit callbackFlashCommit) { - _eraseblockBuffer = (uint8_t*)malloc(flashEraseBlockSize() * flashPageSize()); + println("Set Callback"); + _memoryType = Callback; + _callbackFlashSize = callbackFlashSize; + _callbackFlashRead = callbackFlashRead; + _callbackFlashWrite = callbackFlashWrite; + _callbackFlashCommit = callbackFlashCommit; + _callbackFlashSize(); } - memcpy(_eraseblockBuffer, userFlashStart() + eraseBlockNumber * flashEraseBlockSize() * flashPageSize(), flashEraseBlockSize() * flashPageSize()); - - _bufferedEraseblockNumber = eraseBlockNumber; - _bufferedEraseblockDirty = false; -} - - -#ifdef KNX_FLASH_CALLBACK -void Platform::registerFlashCallbacks( - FlashCallbackSize callbackFlashSize, - FlashCallbackRead callbackFlashRead, - FlashCallbackWrite callbackFlashWrite, - FlashCallbackCommit callbackFlashCommit) -{ - println("Set Callback"); - _memoryType = Callback; - _callbackFlashSize = callbackFlashSize; - _callbackFlashRead = callbackFlashRead; - _callbackFlashWrite = callbackFlashWrite; - _callbackFlashCommit = callbackFlashCommit; - _callbackFlashSize(); -} - -FlashCallbackSize Platform::callbackFlashSize() -{ - return _callbackFlashSize; -} -FlashCallbackRead Platform::callbackFlashRead() -{ - return _callbackFlashRead; -} -FlashCallbackWrite Platform::callbackFlashWrite() -{ - return _callbackFlashWrite; -} -FlashCallbackCommit Platform::callbackFlashCommit() -{ - return _callbackFlashCommit; -} + FlashCallbackSize Platform::callbackFlashSize() + { + return _callbackFlashSize; + } + FlashCallbackRead Platform::callbackFlashRead() + { + return _callbackFlashRead; + } + FlashCallbackWrite Platform::callbackFlashWrite() + { + return _callbackFlashWrite; + } + FlashCallbackCommit Platform::callbackFlashCommit() + { + return _callbackFlashCommit; + } #endif +} \ No newline at end of file diff --git a/src/knx/platform/platform.h b/src/knx/platform/platform.h index b4666b06..135920e8 100644 --- a/src/knx/platform/platform.h +++ b/src/knx/platform/platform.h @@ -4,6 +4,9 @@ #include #include "../util/save_restore.h" + +namespace Knx +{ #ifndef KNX_FLASH_CALLBACK #ifndef KNX_FLASH_SIZE #define KNX_FLASH_SIZE 1024 @@ -21,132 +24,133 @@ typedef void (*FlashCallbackCommit)(); #endif -enum NvMemoryType -{ - Eeprom, - Flash, - Callback -}; - -class Platform -{ - public: - virtual ~Platform() {} - // ip config - virtual uint32_t currentIpAddress(); - virtual uint32_t currentSubnetMask(); - virtual uint32_t currentDefaultGateway(); - virtual void macAddress(uint8_t* data); - - // unique serial number - virtual uint32_t uniqueSerialNumber(); - - // basic stuff - virtual void restart() = 0; - virtual void fatalError() = 0; - - //multicast socket - virtual void setupMultiCast(uint32_t addr, uint16_t port); - virtual void closeMultiCast(); - virtual bool sendBytesMultiCast(uint8_t* buffer, uint16_t len); - virtual int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen); - virtual int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port); - - //unicast socket - virtual bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len); - - //UART - virtual void setupUart(); - virtual void closeUart(); - virtual int uartAvailable(); - virtual size_t writeUart(const uint8_t data); - virtual size_t writeUart(const uint8_t* buffer, size_t size); - virtual int readUart(); - virtual size_t readBytesUart(uint8_t* buffer, size_t length); - virtual bool overflowUart(); - virtual void flushUart(); - - // SPI - virtual void setupSpi(); - virtual void closeSpi(); - virtual int readWriteSpi(uint8_t* data, size_t len); - - //Memory - - // --- Overwrite these methods in the device-plattform to use the EEPROM Emulation API for UserMemory ---- - // - // --- changes to the UserMemory are written directly into the address space starting at getEepromBuffer - // --- commitToEeprom must save this to a non-volatile area if neccessary - virtual uint8_t* getEepromBuffer(uint32_t size); - virtual void commitToEeprom(); - // ------------------------------------------------------------------------------------------------------- - - virtual uint8_t* getNonVolatileMemoryStart(); - virtual size_t getNonVolatileMemorySize(); - virtual void commitNonVolatileMemory(); - // address is relative to start of nonvolatile memory - virtual uint32_t writeNonVolatileMemory(uint32_t relativeAddress, uint8_t* buffer, size_t size); - virtual uint32_t readNonVolatileMemory(uint32_t relativeAddress, uint8_t* buffer, size_t size); - virtual uint32_t writeNonVolatileMemory(uint32_t relativeAddress, uint8_t value, size_t repeat); - - NvMemoryType NonVolatileMemoryType(); - void NonVolatileMemoryType(NvMemoryType type); - - // --- Overwrite these methods in the device-plattform to use flash memory handling by the knx stack --- - // --- also set _memoryType = Flash in the device-plattform's contructor - // --- optional: overwrite writeBufferedEraseBlock() in the device-plattform to reduce overhead when flashing multiple pages - - // size of one flash page in bytes - virtual size_t flashPageSize(); + enum NvMemoryType + { + Eeprom, + Flash, + Callback + }; + + class Platform + { + public: + virtual ~Platform() {} + // ip config + virtual uint32_t currentIpAddress(); + virtual uint32_t currentSubnetMask(); + virtual uint32_t currentDefaultGateway(); + virtual void macAddress(uint8_t* data); + + // unique serial number + virtual uint32_t uniqueSerialNumber(); + + // basic stuff + virtual void restart() = 0; + virtual void fatalError() = 0; + + //multicast socket + virtual void setupMultiCast(uint32_t addr, uint16_t port); + virtual void closeMultiCast(); + virtual bool sendBytesMultiCast(uint8_t* buffer, uint16_t len); + virtual int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen); + virtual int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port); + + //unicast socket + virtual bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len); + + //UART + virtual void setupUart(); + virtual void closeUart(); + virtual int uartAvailable(); + virtual size_t writeUart(const uint8_t data); + virtual size_t writeUart(const uint8_t* buffer, size_t size); + virtual int readUart(); + virtual size_t readBytesUart(uint8_t* buffer, size_t length); + virtual bool overflowUart(); + virtual void flushUart(); + + // SPI + virtual void setupSpi(); + virtual void closeSpi(); + virtual int readWriteSpi(uint8_t* data, size_t len); + + //Memory + + // --- Overwrite these methods in the device-plattform to use the EEPROM Emulation API for UserMemory ---- + // + // --- changes to the UserMemory are written directly into the address space starting at getEepromBuffer + // --- commitToEeprom must save this to a non-volatile area if neccessary + virtual uint8_t* getEepromBuffer(uint32_t size); + virtual void commitToEeprom(); + // ------------------------------------------------------------------------------------------------------- + + virtual uint8_t* getNonVolatileMemoryStart(); + virtual size_t getNonVolatileMemorySize(); + virtual void commitNonVolatileMemory(); + // address is relative to start of nonvolatile memory + virtual uint32_t writeNonVolatileMemory(uint32_t relativeAddress, uint8_t* buffer, size_t size); + virtual uint32_t readNonVolatileMemory(uint32_t relativeAddress, uint8_t* buffer, size_t size); + virtual uint32_t writeNonVolatileMemory(uint32_t relativeAddress, uint8_t value, size_t repeat); + + NvMemoryType NonVolatileMemoryType(); + void NonVolatileMemoryType(NvMemoryType type); + + // --- Overwrite these methods in the device-plattform to use flash memory handling by the knx stack --- + // --- also set _memoryType = Flash in the device-plattform's contructor + // --- optional: overwrite writeBufferedEraseBlock() in the device-plattform to reduce overhead when flashing multiple pages + + // size of one flash page in bytes + virtual size_t flashPageSize(); #ifdef KNX_FLASH_CALLBACK - void registerFlashCallbacks( - FlashCallbackSize callbackFlashSize, - FlashCallbackRead callbackFlashRead, - FlashCallbackWrite callbackFlashWrite, - FlashCallbackCommit callbackFlashCommit); - - FlashCallbackSize callbackFlashSize(); - FlashCallbackRead callbackFlashRead(); - FlashCallbackWrite callbackFlashWrite(); - FlashCallbackCommit callbackFlashCommit(); + void registerFlashCallbacks( + FlashCallbackSize callbackFlashSize, + FlashCallbackRead callbackFlashRead, + FlashCallbackWrite callbackFlashWrite, + FlashCallbackCommit callbackFlashCommit); + + FlashCallbackSize callbackFlashSize(); + FlashCallbackRead callbackFlashRead(); + FlashCallbackWrite callbackFlashWrite(); + FlashCallbackCommit callbackFlashCommit(); #endif - protected: - // size of one EraseBlock in pages - virtual size_t flashEraseBlockSize(); - // start of user flash aligned to start of an erase block - virtual uint8_t* userFlashStart(); - // size of the user flash in EraseBlocks - virtual size_t userFlashSizeEraseBlocks(); - //relativ to userFlashStart - virtual void flashErase(uint16_t eraseBlockNum); - //write a single page to flash (pageNumber relative to userFashStart - virtual void flashWritePage(uint16_t pageNumber, uint8_t* data); - - - // ------------------------------------------------------------------------------------------------------- - - NvMemoryType _memoryType = Eeprom; - - void loadEraseblockContaining(uint32_t relativeAddress); - int32_t getEraseBlockNumberOf(uint32_t relativeAddress); - // writes _eraseblockBuffer to flash - virtual void writeBufferedEraseBlock(); - // copies a EraseBlock into the _eraseblockBuffer - void bufferEraseBlock(int32_t eraseBlockNumber); - - // in theory we would have to use this buffer for memory reads too, - // but because ets always restarts the device after programming it - // we can ignore this issue - uint8_t* _eraseblockBuffer = nullptr; - int32_t _bufferedEraseblockNumber = -1; - bool _bufferedEraseblockDirty = false; + protected: + // size of one EraseBlock in pages + virtual size_t flashEraseBlockSize(); + // start of user flash aligned to start of an erase block + virtual uint8_t* userFlashStart(); + // size of the user flash in EraseBlocks + virtual size_t userFlashSizeEraseBlocks(); + //relativ to userFlashStart + virtual void flashErase(uint16_t eraseBlockNum); + //write a single page to flash (pageNumber relative to userFashStart + virtual void flashWritePage(uint16_t pageNumber, uint8_t* data); + + + // ------------------------------------------------------------------------------------------------------- + + NvMemoryType _memoryType = Eeprom; + + void loadEraseblockContaining(uint32_t relativeAddress); + int32_t getEraseBlockNumberOf(uint32_t relativeAddress); + // writes _eraseblockBuffer to flash + virtual void writeBufferedEraseBlock(); + // copies a EraseBlock into the _eraseblockBuffer + void bufferEraseBlock(int32_t eraseBlockNumber); + + // in theory we would have to use this buffer for memory reads too, + // but because ets always restarts the device after programming it + // we can ignore this issue + uint8_t* _eraseblockBuffer = nullptr; + int32_t _bufferedEraseblockNumber = -1; + bool _bufferedEraseblockDirty = false; #ifdef KNX_FLASH_CALLBACK - FlashCallbackSize _callbackFlashSize = nullptr; - FlashCallbackRead _callbackFlashRead = nullptr; - FlashCallbackWrite _callbackFlashWrite = nullptr; - FlashCallbackCommit _callbackFlashCommit = nullptr; + FlashCallbackSize _callbackFlashSize = nullptr; + FlashCallbackRead _callbackFlashRead = nullptr; + FlashCallbackWrite _callbackFlashWrite = nullptr; + FlashCallbackCommit _callbackFlashCommit = nullptr; #endif -}; + }; +} \ No newline at end of file diff --git a/src/knx/platform/rp2040_arduino_platform.cpp b/src/knx/platform/rp2040_arduino_platform.cpp index 95016c20..ef2f7ec6 100644 --- a/src/knx/platform/rp2040_arduino_platform.cpp +++ b/src/knx/platform/rp2040_arduino_platform.cpp @@ -35,61 +35,63 @@ For usage of KNX-IP you have to define either #include // from Pico SDK #include // from Pico SDK +namespace Knx +{ #ifdef USE_KNX_DMA_UART #include -// constexpr uint32_t uartDmaTransferCount = 0b1111111111; -constexpr uint32_t uartDmaTransferCount = UINT32_MAX; -constexpr uint8_t uartDmaBufferExp = 8u; // 2**BufferExp -constexpr uint16_t uartDmaBufferSize = (1u << uartDmaBufferExp); -int8_t uartDmaChannel = -1; -volatile uint8_t __attribute__((aligned(uartDmaBufferSize))) uartDmaBuffer[uartDmaBufferSize] = {}; -volatile uint32_t uartDmaReadCount = 0; -volatile uint16_t uartDmaRestartCount = 0; -volatile uint32_t uartDmaWriteCount2 = 0; -volatile uint32_t uartDmaAvail = 0; - -// Returns the number of bytes read since the DMA transfer start -inline uint32_t uartDmaWriteCount() -{ - uartDmaWriteCount2 = uartDmaTransferCount - dma_channel_hw_addr(uartDmaChannel)->transfer_count; - return uartDmaWriteCount2; -} - -// Returns the current write position in the DMA buffer -inline uint16_t uartDmaWriteBufferPosition() -{ - return uartDmaWriteCount() % uartDmaBufferSize; -} - -// Returns the current read position in the DMA buffer -inline uint16_t uartDmaReadBufferPosition() -{ - return uartDmaReadCount % uartDmaBufferSize; -} + // constexpr uint32_t uartDmaTransferCount = 0b1111111111; + constexpr uint32_t uartDmaTransferCount = UINT32_MAX; + constexpr uint8_t uartDmaBufferExp = 8u; // 2**BufferExp + constexpr uint16_t uartDmaBufferSize = (1u << uartDmaBufferExp); + int8_t uartDmaChannel = -1; + volatile uint8_t __attribute__((aligned(uartDmaBufferSize))) uartDmaBuffer[uartDmaBufferSize] = {}; + volatile uint32_t uartDmaReadCount = 0; + volatile uint16_t uartDmaRestartCount = 0; + volatile uint32_t uartDmaWriteCount2 = 0; + volatile uint32_t uartDmaAvail = 0; + + // Returns the number of bytes read since the DMA transfer start + inline uint32_t uartDmaWriteCount() + { + uartDmaWriteCount2 = uartDmaTransferCount - dma_channel_hw_addr(uartDmaChannel)->transfer_count; + return uartDmaWriteCount2; + } -// Returns the current reading position as a pointer -inline uint8_t* uartDmaReadAddr() -{ - return ((uint8_t*)uartDmaBuffer + uartDmaReadBufferPosition()); -} + // Returns the current write position in the DMA buffer + inline uint16_t uartDmaWriteBufferPosition() + { + return uartDmaWriteCount() % uartDmaBufferSize; + } -// Restarts the transfer after completion. -void __time_critical_func(uartDmaRestart)() -{ - // println("Restart"); - uartDmaRestartCount = uartDmaWriteBufferPosition() - uartDmaReadBufferPosition(); + // Returns the current read position in the DMA buffer + inline uint16_t uartDmaReadBufferPosition() + { + return uartDmaReadCount % uartDmaBufferSize; + } - // if uartDmaRestartCount == 0, everything has been processed and the read count can be set to 0 again with the restart. - if (uartDmaRestartCount == 0) + // Returns the current reading position as a pointer + inline uint8_t* uartDmaReadAddr() { - uartDmaReadCount = 0; + return ((uint8_t*)uartDmaBuffer + uartDmaReadBufferPosition()); } - asm volatile("" ::: "memory"); - dma_hw->ints0 = 1u << uartDmaChannel; // clear DMA IRQ0 flag - asm volatile("" ::: "memory"); - dma_channel_set_write_addr(uartDmaChannel, uartDmaBuffer, true); -} + // Restarts the transfer after completion. + void __time_critical_func(uartDmaRestart)() + { + // println("Restart"); + uartDmaRestartCount = uartDmaWriteBufferPosition() - uartDmaReadBufferPosition(); + + // if uartDmaRestartCount == 0, everything has been processed and the read count can be set to 0 again with the restart. + if (uartDmaRestartCount == 0) + { + uartDmaReadCount = 0; + } + + asm volatile("" ::: "memory"); + dma_hw->ints0 = 1u << uartDmaChannel; // clear DMA IRQ0 flag + asm volatile("" ::: "memory"); + dma_channel_set_write_addr(uartDmaChannel, uartDmaBuffer, true); + } #endif #define FLASHPTR ((uint8_t*)XIP_BASE + KNX_FLASH_OFFSET) @@ -111,216 +113,216 @@ void __time_critical_func(uartDmaRestart)() #endif -RP2040ArduinoPlatform::RP2040ArduinoPlatform() + RP2040ArduinoPlatform::RP2040ArduinoPlatform() #if !defined(KNX_NO_DEFAULT_UART) && !defined(USE_KNX_DMA_UART) - : ArduinoPlatform(&KNX_SERIAL) + : ArduinoPlatform(&KNX_SERIAL) #endif -{ + { #ifdef KNX_UART_RX_PIN - _rxPin = KNX_UART_RX_PIN; + _rxPin = KNX_UART_RX_PIN; #endif #ifdef KNX_UART_TX_PIN - _txPin = KNX_UART_TX_PIN; + _txPin = KNX_UART_TX_PIN; #endif #ifndef USE_RP2040_EEPROM_EMULATION - _memoryType = Flash; + _memoryType = Flash; #endif -} + } -RP2040ArduinoPlatform::RP2040ArduinoPlatform(HardwareSerial* s) - : ArduinoPlatform(s) -{ + RP2040ArduinoPlatform::RP2040ArduinoPlatform(HardwareSerial* s) + : ArduinoPlatform(s) + { #ifndef USE_RP2040_EEPROM_EMULATION - _memoryType = Flash; + _memoryType = Flash; #endif -} + } -void RP2040ArduinoPlatform::knxUartPins(pin_size_t rxPin, pin_size_t txPin) -{ - _rxPin = rxPin; - _txPin = txPin; -} + void RP2040ArduinoPlatform::knxUartPins(pin_size_t rxPin, pin_size_t txPin) + { + _rxPin = rxPin; + _txPin = txPin; + } -bool RP2040ArduinoPlatform::overflowUart() -{ + bool RP2040ArduinoPlatform::overflowUart() + { #ifdef USE_KNX_DMA_UART - // during dma restart - bool ret; - const uint32_t writeCount = uartDmaWriteCount(); - - if (uartDmaRestartCount > 0) - ret = writeCount >= (uartDmaBufferSize - uartDmaRestartCount - 1); - else - ret = (writeCount - uartDmaReadCount) > uartDmaBufferSize; - - // if (ret) - // { - // println(uartDmaWriteBufferPosition()); - // println(uartDmaReadBufferPosition()); - // println(uartDmaWriteCount()); - // println(uartDmaReadCount); - // println(uartDmaRestartCount); - // printHex("BUF: ", (const uint8_t *)uartDmaBuffer, uartDmaBufferSize); - // println("OVERFLOW"); - // while (true) - // ; - // } - return ret; + // during dma restart + bool ret; + const uint32_t writeCount = uartDmaWriteCount(); + + if (uartDmaRestartCount > 0) + ret = writeCount >= (uartDmaBufferSize - uartDmaRestartCount - 1); + else + ret = (writeCount - uartDmaReadCount) > uartDmaBufferSize; + + // if (ret) + // { + // println(uartDmaWriteBufferPosition()); + // println(uartDmaReadBufferPosition()); + // println(uartDmaWriteCount()); + // println(uartDmaReadCount); + // println(uartDmaRestartCount); + // printHex("BUF: ", (const uint8_t *)uartDmaBuffer, uartDmaBufferSize); + // println("OVERFLOW"); + // while (true) + // ; + // } + return ret; #else - SerialUART* serial = dynamic_cast(_knxSerial); - return serial->overflow(); + SerialUART* serial = dynamic_cast(_knxSerial); + return serial->overflow(); #endif -} + } -void RP2040ArduinoPlatform::setupUart() -{ + void RP2040ArduinoPlatform::setupUart() + { #ifdef USE_KNX_DMA_UART - if (uartDmaChannel == -1) - { - // configure uart0 - gpio_set_function(_rxPin, GPIO_FUNC_UART); - gpio_set_function(_txPin, GPIO_FUNC_UART); - uart_init(KNX_DMA_UART, 19200); - uart_set_hw_flow(KNX_DMA_UART, false, false); - uart_set_format(KNX_DMA_UART, 8, 1, UART_PARITY_EVEN); - uart_set_fifo_enabled(KNX_DMA_UART, false); - - // configure uart0 - uartDmaChannel = dma_claim_unused_channel(true); // get free channel for dma - dma_channel_config dmaConfig = dma_channel_get_default_config(uartDmaChannel); - channel_config_set_transfer_data_size(&dmaConfig, DMA_SIZE_8); - channel_config_set_read_increment(&dmaConfig, false); - channel_config_set_write_increment(&dmaConfig, true); - channel_config_set_high_priority(&dmaConfig, true); - channel_config_set_ring(&dmaConfig, true, uartDmaBufferExp); - channel_config_set_dreq(&dmaConfig, KNX_DMA_UART_DREQ); - dma_channel_set_read_addr(uartDmaChannel, &uart_get_hw(uart0)->dr, false); - dma_channel_set_write_addr(uartDmaChannel, uartDmaBuffer, false); - dma_channel_set_trans_count(uartDmaChannel, uartDmaTransferCount, false); - dma_channel_set_config(uartDmaChannel, &dmaConfig, true); - dma_channel_set_irq1_enabled(uartDmaChannel, true); - // irq_add_shared_handler(KNX_DMA_IRQ, uartDmaRestart, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY); - irq_set_exclusive_handler(KNX_DMA_IRQ, uartDmaRestart); - irq_set_enabled(KNX_DMA_IRQ, true); - } + if (uartDmaChannel == -1) + { + // configure uart0 + gpio_set_function(_rxPin, GPIO_FUNC_UART); + gpio_set_function(_txPin, GPIO_FUNC_UART); + uart_init(KNX_DMA_UART, 19200); + uart_set_hw_flow(KNX_DMA_UART, false, false); + uart_set_format(KNX_DMA_UART, 8, 1, UART_PARITY_EVEN); + uart_set_fifo_enabled(KNX_DMA_UART, false); + + // configure uart0 + uartDmaChannel = dma_claim_unused_channel(true); // get free channel for dma + dma_channel_config dmaConfig = dma_channel_get_default_config(uartDmaChannel); + channel_config_set_transfer_data_size(&dmaConfig, DMA_SIZE_8); + channel_config_set_read_increment(&dmaConfig, false); + channel_config_set_write_increment(&dmaConfig, true); + channel_config_set_high_priority(&dmaConfig, true); + channel_config_set_ring(&dmaConfig, true, uartDmaBufferExp); + channel_config_set_dreq(&dmaConfig, KNX_DMA_UART_DREQ); + dma_channel_set_read_addr(uartDmaChannel, &uart_get_hw(uart0)->dr, false); + dma_channel_set_write_addr(uartDmaChannel, uartDmaBuffer, false); + dma_channel_set_trans_count(uartDmaChannel, uartDmaTransferCount, false); + dma_channel_set_config(uartDmaChannel, &dmaConfig, true); + dma_channel_set_irq1_enabled(uartDmaChannel, true); + // irq_add_shared_handler(KNX_DMA_IRQ, uartDmaRestart, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY); + irq_set_exclusive_handler(KNX_DMA_IRQ, uartDmaRestart); + irq_set_enabled(KNX_DMA_IRQ, true); + } #else - SerialUART* serial = dynamic_cast(_knxSerial); + SerialUART* serial = dynamic_cast(_knxSerial); - if (serial) - { - if (_rxPin != UART_PIN_NOT_DEFINED) - serial->setRX(_rxPin); + if (serial) + { + if (_rxPin != UART_PIN_NOT_DEFINED) + serial->setRX(_rxPin); - if (_txPin != UART_PIN_NOT_DEFINED) - serial->setTX(_txPin); + if (_txPin != UART_PIN_NOT_DEFINED) + serial->setTX(_txPin); - serial->setPollingMode(); - serial->setFIFOSize(64); - } + serial->setPollingMode(); + serial->setFIFOSize(64); + } - _knxSerial->begin(19200, SERIAL_8E1); + _knxSerial->begin(19200, SERIAL_8E1); - while (!_knxSerial) - ; + while (!_knxSerial) + ; #endif -} + } #ifdef USE_KNX_DMA_UART -int RP2040ArduinoPlatform::uartAvailable() -{ - if (uartDmaChannel == -1) - return 0; - - if (uartDmaRestartCount > 0) + int RP2040ArduinoPlatform::uartAvailable() { - return uartDmaRestartCount; + if (uartDmaChannel == -1) + return 0; + + if (uartDmaRestartCount > 0) + { + return uartDmaRestartCount; + } + else + { + uint32_t tc = dma_channel_hw_addr(uartDmaChannel)->transfer_count; + uartDmaAvail = tc; + int test = uartDmaTransferCount - tc - uartDmaReadCount; + return test; + } } - else + + int RP2040ArduinoPlatform::readUart() { - uint32_t tc = dma_channel_hw_addr(uartDmaChannel)->transfer_count; - uartDmaAvail = tc; - int test = uartDmaTransferCount - tc - uartDmaReadCount; - return test; - } -} + if (!uartAvailable()) + return -1; -int RP2040ArduinoPlatform::readUart() -{ - if (!uartAvailable()) - return -1; + int ret = uartDmaReadAddr()[0]; + // print("< "); + // println(ret, HEX); + uartDmaReadCount++; - int ret = uartDmaReadAddr()[0]; - // print("< "); - // println(ret, HEX); - uartDmaReadCount++; + if (uartDmaRestartCount > 0) + { + // process previouse buffer + uartDmaRestartCount--; - if (uartDmaRestartCount > 0) - { - // process previouse buffer - uartDmaRestartCount--; + // last char, then reset read count to start at new writer position + if (uartDmaRestartCount == 0) + uartDmaReadCount = 0; + } - // last char, then reset read count to start at new writer position - if (uartDmaRestartCount == 0) - uartDmaReadCount = 0; + return ret; } - return ret; -} - -size_t RP2040ArduinoPlatform::writeUart(const uint8_t data) -{ - if (uartDmaChannel == -1) - return 0; + size_t RP2040ArduinoPlatform::writeUart(const uint8_t data) + { + if (uartDmaChannel == -1) + return 0; - // print("> "); - // println(data, HEX); - while (!uart_is_writable(uart0)) - ; + // print("> "); + // println(data, HEX); + while (!uart_is_writable(uart0)) + ; - uart_putc_raw(uart0, data); - return 1; -} + uart_putc_raw(uart0, data); + return 1; + } -void RP2040ArduinoPlatform::closeUart() -{ - if (uartDmaChannel >= 0) + void RP2040ArduinoPlatform::closeUart() { - dma_channel_cleanup(uartDmaChannel); - irq_set_enabled(DMA_IRQ_0, false); - uart_deinit(uart0); - uartDmaChannel = -1; - uartDmaReadCount = 0; - uartDmaRestartCount = 0; + if (uartDmaChannel >= 0) + { + dma_channel_cleanup(uartDmaChannel); + irq_set_enabled(DMA_IRQ_0, false); + uart_deinit(uart0); + uartDmaChannel = -1; + uartDmaReadCount = 0; + uartDmaRestartCount = 0; + } } -} #endif -uint32_t RP2040ArduinoPlatform::uniqueSerialNumber() -{ - pico_unique_board_id_t id; // 64Bit unique serial number from the QSPI flash + uint32_t RP2040ArduinoPlatform::uniqueSerialNumber() + { + pico_unique_board_id_t id; // 64Bit unique serial number from the QSPI flash - noInterrupts(); - rp2040.idleOtherCore(); + noInterrupts(); + rp2040.idleOtherCore(); - flash_get_unique_id(id.id); // pico_get_unique_board_id(&id); + flash_get_unique_id(id.id); // pico_get_unique_board_id(&id); - rp2040.resumeOtherCore(); - interrupts(); + rp2040.resumeOtherCore(); + interrupts(); - // use lower 4 byte and convert to unit32_t - uint32_t uid = ((uint32_t)(id.id[4]) << 24) | ((uint32_t)(id.id[5]) << 16) | ((uint32_t)(id.id[6]) << 8) | (uint32_t)(id.id[7]); + // use lower 4 byte and convert to unit32_t + uint32_t uid = ((uint32_t)(id.id[4]) << 24) | ((uint32_t)(id.id[5]) << 16) | ((uint32_t)(id.id[6]) << 8) | (uint32_t)(id.id[7]); - return uid; -} + return uid; + } -void RP2040ArduinoPlatform::restart() -{ - println("restart"); - watchdog_reboot(0, 0, 0); -} + void RP2040ArduinoPlatform::restart() + { + println("restart"); + watchdog_reboot(0, 0, 0); + } #ifdef USE_RP2040_EEPROM_EMULATION @@ -328,255 +330,255 @@ void RP2040ArduinoPlatform::restart() #ifdef USE_RP2040_LARGE_EEPROM_EMULATION -uint8_t* RP2040ArduinoPlatform::getEepromBuffer(uint32_t size) -{ - if (size % 4096) + uint8_t* RP2040ArduinoPlatform::getEepromBuffer(uint32_t size) { - println("KNX_FLASH_SIZE must be a multiple of 4096"); - fatalError(); + if (size % 4096) + { + println("KNX_FLASH_SIZE must be a multiple of 4096"); + fatalError(); + } + + if (!_rambuff_initialized) + { + memcpy(_rambuff, FLASHPTR, KNX_FLASH_SIZE); + _rambuff_initialized = true; + } + + return _rambuff; } - if (!_rambuff_initialized) + void RP2040ArduinoPlatform::commitToEeprom() { - memcpy(_rambuff, FLASHPTR, KNX_FLASH_SIZE); - _rambuff_initialized = true; - } - - return _rambuff; -} + noInterrupts(); + rp2040.idleOtherCore(); -void RP2040ArduinoPlatform::commitToEeprom() -{ - noInterrupts(); - rp2040.idleOtherCore(); + // ToDo: write block-by-block to prevent writing of untouched blocks + if (memcmp(_rambuff, FLASHPTR, KNX_FLASH_SIZE)) + { + flash_range_erase(KNX_FLASH_OFFSET, KNX_FLASH_SIZE); + flash_range_program(KNX_FLASH_OFFSET, _rambuff, KNX_FLASH_SIZE); + } - // ToDo: write block-by-block to prevent writing of untouched blocks - if (memcmp(_rambuff, FLASHPTR, KNX_FLASH_SIZE)) - { - flash_range_erase(KNX_FLASH_OFFSET, KNX_FLASH_SIZE); - flash_range_program(KNX_FLASH_OFFSET, _rambuff, KNX_FLASH_SIZE); + rp2040.resumeOtherCore(); + interrupts(); } - rp2040.resumeOtherCore(); - interrupts(); -} - #else -uint8_t* RP2040ArduinoPlatform::getEepromBuffer(uint32_t size) -{ - if (size > 4096) + uint8_t* RP2040ArduinoPlatform::getEepromBuffer(uint32_t size) { - println("KNX_FLASH_SIZE to big for EEPROM emulation (max. 4kB)"); - fatalError(); - } + if (size > 4096) + { + println("KNX_FLASH_SIZE to big for EEPROM emulation (max. 4kB)"); + fatalError(); + } - uint8_t* eepromptr = EEPROM.getDataPtr(); + uint8_t* eepromptr = EEPROM.getDataPtr(); - if (eepromptr == nullptr) - { - EEPROM.begin(4096); - eepromptr = EEPROM.getDataPtr(); - } + if (eepromptr == nullptr) + { + EEPROM.begin(4096); + eepromptr = EEPROM.getDataPtr(); + } - return eepromptr; -} + return eepromptr; + } -void RP2040ArduinoPlatform::commitToEeprom() -{ - EEPROM.commit(); -} + void RP2040ArduinoPlatform::commitToEeprom() + { + EEPROM.commit(); + } #endif #else -size_t RP2040ArduinoPlatform::flashEraseBlockSize() -{ - return 16; // 16 pages x 256byte/page = 4096byte -} - -size_t RP2040ArduinoPlatform::flashPageSize() -{ - return 256; -} - -uint8_t* RP2040ArduinoPlatform::userFlashStart() -{ - return (uint8_t*)XIP_BASE + KNX_FLASH_OFFSET; -} - -size_t RP2040ArduinoPlatform::userFlashSizeEraseBlocks() -{ - if (KNX_FLASH_SIZE <= 0) - return 0; - else - return ((KNX_FLASH_SIZE - 1) / (flashPageSize() * flashEraseBlockSize())) + 1; -} + size_t RP2040ArduinoPlatform::flashEraseBlockSize() + { + return 16; // 16 pages x 256byte/page = 4096byte + } -void RP2040ArduinoPlatform::flashErase(uint16_t eraseBlockNum) -{ - noInterrupts(); - rp2040.idleOtherCore(); + size_t RP2040ArduinoPlatform::flashPageSize() + { + return 256; + } - flash_range_erase(KNX_FLASH_OFFSET + eraseBlockNum * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize()); + uint8_t* RP2040ArduinoPlatform::userFlashStart() + { + return (uint8_t*)XIP_BASE + KNX_FLASH_OFFSET; + } - rp2040.resumeOtherCore(); - interrupts(); -} + size_t RP2040ArduinoPlatform::userFlashSizeEraseBlocks() + { + if (KNX_FLASH_SIZE <= 0) + return 0; + else + return ((KNX_FLASH_SIZE - 1) / (flashPageSize() * flashEraseBlockSize())) + 1; + } -void RP2040ArduinoPlatform::flashWritePage(uint16_t pageNumber, uint8_t* data) -{ - noInterrupts(); - rp2040.idleOtherCore(); + void RP2040ArduinoPlatform::flashErase(uint16_t eraseBlockNum) + { + noInterrupts(); + rp2040.idleOtherCore(); - flash_range_program(KNX_FLASH_OFFSET + pageNumber * flashPageSize(), data, flashPageSize()); + flash_range_erase(KNX_FLASH_OFFSET + eraseBlockNum * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize()); - rp2040.resumeOtherCore(); - interrupts(); -} + rp2040.resumeOtherCore(); + interrupts(); + } -void RP2040ArduinoPlatform::writeBufferedEraseBlock() -{ - if (_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) + void RP2040ArduinoPlatform::flashWritePage(uint16_t pageNumber, uint8_t* data) { noInterrupts(); rp2040.idleOtherCore(); - flash_range_erase(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize()); - flash_range_program(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), _eraseblockBuffer, flashPageSize() * flashEraseBlockSize()); + flash_range_program(KNX_FLASH_OFFSET + pageNumber * flashPageSize(), data, flashPageSize()); rp2040.resumeOtherCore(); interrupts(); + } + + void RP2040ArduinoPlatform::writeBufferedEraseBlock() + { + if (_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) + { + noInterrupts(); + rp2040.idleOtherCore(); + + flash_range_erase(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize()); + flash_range_program(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), _eraseblockBuffer, flashPageSize() * flashEraseBlockSize()); + + rp2040.resumeOtherCore(); + interrupts(); - _bufferedEraseblockDirty = false; + _bufferedEraseblockDirty = false; + } } -} #endif #if defined(KNX_NETIF) -uint32_t RP2040ArduinoPlatform::currentIpAddress() -{ - return KNX_NETIF.localIP(); -} -uint32_t RP2040ArduinoPlatform::currentSubnetMask() -{ - return KNX_NETIF.subnetMask(); -} -uint32_t RP2040ArduinoPlatform::currentDefaultGateway() -{ - return KNX_NETIF.gatewayIP(); -} -void RP2040ArduinoPlatform::macAddress(uint8_t* addr) -{ + uint32_t RP2040ArduinoPlatform::currentIpAddress() + { + return KNX_NETIF.localIP(); + } + uint32_t RP2040ArduinoPlatform::currentSubnetMask() + { + return KNX_NETIF.subnetMask(); + } + uint32_t RP2040ArduinoPlatform::currentDefaultGateway() + { + return KNX_NETIF.gatewayIP(); + } + void RP2040ArduinoPlatform::macAddress(uint8_t* addr) + { #if defined(KNX_IP_LAN) - addr = KNX_NETIF.getNetIf()->hwaddr; + addr = KNX_NETIF.getNetIf()->hwaddr; #else - uint8_t macaddr[6] = {0, 0, 0, 0, 0, 0}; - addr = KNX_NETIF.macAddress(macaddr); + uint8_t macaddr[6] = {0, 0, 0, 0, 0, 0}; + addr = KNX_NETIF.macAddress(macaddr); #endif -} + } -// multicast -void RP2040ArduinoPlatform::setupMultiCast(uint32_t addr, uint16_t port) -{ - mcastaddr = IPAddress(htonl(addr)); - _port = port; - uint8_t result = _udp.beginMulticast(mcastaddr, port); - (void)result; + // multicast + void RP2040ArduinoPlatform::setupMultiCast(uint32_t addr, uint16_t port) + { + mcastaddr = IPAddress(htonl(addr)); + _port = port; + uint8_t result = _udp.beginMulticast(mcastaddr, port); + (void)result; #ifdef KNX_IP_GENERIC - // if(!_unicast_socket_setup) - // _unicast_socket_setup = UDP_UNICAST.begin(3671); + // if(!_unicast_socket_setup) + // _unicast_socket_setup = UDP_UNICAST.begin(3671); #endif - // print("Setup Mcast addr: "); - // print(mcastaddr.toString().c_str()); - // print(" on port: "); - // print(port); - // print(" result "); - // println(result); -} + // print("Setup Mcast addr: "); + // print(mcastaddr.toString().c_str()); + // print(" on port: "); + // print(port); + // print(" result "); + // println(result); + } -void RP2040ArduinoPlatform::closeMultiCast() -{ - _udp.stop(); -} + void RP2040ArduinoPlatform::closeMultiCast() + { + _udp.stop(); + } -bool RP2040ArduinoPlatform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) -{ - // printHex("<- ",buffer, len); + bool RP2040ArduinoPlatform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) + { + // printHex("<- ",buffer, len); - // ToDo: check if Ethernet is able to receive, return false if not - _udp.beginPacket(mcastaddr, _port); - _udp.write(buffer, len); - _udp.endPacket(); - return true; -} + // ToDo: check if Ethernet is able to receive, return false if not + _udp.beginPacket(mcastaddr, _port); + _udp.write(buffer, len); + _udp.endPacket(); + return true; + } -int RP2040ArduinoPlatform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port) -{ - int len = _udp.parsePacket(); + int RP2040ArduinoPlatform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port) + { + int len = _udp.parsePacket(); - if (len == 0) - return 0; + if (len == 0) + return 0; - if (len > maxLen) - { - println("Unexpected UDP data packet length - drop packet"); + if (len > maxLen) + { + println("Unexpected UDP data packet length - drop packet"); - for (size_t i = 0; i < len; i++) - _udp.read(); + for (size_t i = 0; i < len; i++) + _udp.read(); - return 0; - } + return 0; + } - _udp.read(buffer, len); - _remoteIP = _udp.remoteIP(); - _remotePort = _udp.remotePort(); - src_addr = htonl(_remoteIP); - src_port = _remotePort; + _udp.read(buffer, len); + _remoteIP = _udp.remoteIP(); + _remotePort = _udp.remotePort(); + src_addr = htonl(_remoteIP); + src_port = _remotePort; - // print("Remote IP: "); - // print(_udp.remoteIP().toString().c_str()); - // printHex("-> ", buffer, len); + // print("Remote IP: "); + // print(_udp.remoteIP().toString().c_str()); + // printHex("-> ", buffer, len); - return len; -} + return len; + } -// unicast -bool RP2040ArduinoPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) -{ - IPAddress ucastaddr(htonl(addr)); + // unicast + bool RP2040ArduinoPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) + { + IPAddress ucastaddr(htonl(addr)); - if (!addr) - ucastaddr = _remoteIP; + if (!addr) + ucastaddr = _remoteIP; - if (!port) - port = _remotePort; + if (!port) + port = _remotePort; - // print("sendBytesUniCast to:"); - // println(ucastaddr.toString().c_str()); + // print("sendBytesUniCast to:"); + // println(ucastaddr.toString().c_str()); #ifdef KNX_IP_GENERIC - if (!_unicast_socket_setup) - _unicast_socket_setup = UDP_UNICAST.begin(3671); + if (!_unicast_socket_setup) + _unicast_socket_setup = UDP_UNICAST.begin(3671); #endif - if (UDP_UNICAST.beginPacket(ucastaddr, port) == 1) - { - UDP_UNICAST.write(buffer, len); + if (UDP_UNICAST.beginPacket(ucastaddr, port) == 1) + { + UDP_UNICAST.write(buffer, len); - if (UDP_UNICAST.endPacket() == 0) - println("sendBytesUniCast endPacket fail"); - } - else - println("sendBytesUniCast beginPacket fail"); - - return true; -} -#endif + if (UDP_UNICAST.endPacket() == 0) + println("sendBytesUniCast endPacket fail"); + } + else + println("sendBytesUniCast beginPacket fail"); + return true; + } #endif +} +#endif \ No newline at end of file diff --git a/src/knx/platform/rp2040_arduino_platform.h b/src/knx/platform/rp2040_arduino_platform.h index 1a5d13be..7bcd5415 100644 --- a/src/knx/platform/rp2040_arduino_platform.h +++ b/src/knx/platform/rp2040_arduino_platform.h @@ -52,104 +52,105 @@ #define KNX_DMA_IRQ DMA_IRQ_0 #endif - -class RP2040ArduinoPlatform : public ArduinoPlatform +namespace Knx { - public: - RP2040ArduinoPlatform(); - RP2040ArduinoPlatform( HardwareSerial* s); - - // uart - void knxUartPins(pin_size_t rxPin, pin_size_t txPin); - void setupUart() override; - bool overflowUart() override; + class RP2040ArduinoPlatform : public ArduinoPlatform + { + public: + RP2040ArduinoPlatform(); + RP2040ArduinoPlatform( HardwareSerial* s); + + // uart + void knxUartPins(pin_size_t rxPin, pin_size_t txPin); + void setupUart() override; + bool overflowUart() override; #ifdef USE_KNX_DMA_UART - int uartAvailable() override; - void closeUart() override; - void knxUart( HardwareSerial* serial) override {}; - HardwareSerial* knxUart() override - { - return nullptr; - }; - size_t writeUart(const uint8_t data) override; - size_t writeUart(const uint8_t* buffer, size_t size) override - { - return 0; - }; - int readUart() override; - size_t readBytesUart(uint8_t* buffer, size_t length) override - { - return 0; - }; - void flushUart() override {}; + int uartAvailable() override; + void closeUart() override; + void knxUart( HardwareSerial* serial) override {}; + HardwareSerial* knxUart() override + { + return nullptr; + }; + size_t writeUart(const uint8_t data) override; + size_t writeUart(const uint8_t* buffer, size_t size) override + { + return 0; + }; + int readUart() override; + size_t readBytesUart(uint8_t* buffer, size_t length) override + { + return 0; + }; + void flushUart() override {}; #endif - // unique serial number - uint32_t uniqueSerialNumber() override; + // unique serial number + uint32_t uniqueSerialNumber() override; - void restart(); + void restart(); #ifdef USE_RP2040_EEPROM_EMULATION - uint8_t* getEepromBuffer(uint32_t size); - void commitToEeprom(); + uint8_t* getEepromBuffer(uint32_t size); + void commitToEeprom(); #ifdef USE_RP2040_LARGE_EEPROM_EMULATION - uint8_t _rambuff[KNX_FLASH_SIZE]; - bool _rambuff_initialized = false; + uint8_t _rambuff[KNX_FLASH_SIZE]; + bool _rambuff_initialized = false; #endif #else - // size of one EraseBlock in pages - virtual size_t flashEraseBlockSize(); - // size of one flash page in bytes - virtual size_t flashPageSize(); - // start of user flash aligned to start of an erase block - virtual uint8_t* userFlashStart(); - // size of the user flash in EraseBlocks - virtual size_t userFlashSizeEraseBlocks(); - //relativ to userFlashStart - virtual void flashErase(uint16_t eraseBlockNum); - //write a single page to flash (pageNumber relative to userFashStart - virtual void flashWritePage(uint16_t pageNumber, uint8_t* data); - - // writes _eraseblockBuffer to flash - overrides Plattform::writeBufferedEraseBlock() for performance optimization only - void writeBufferedEraseBlock(); + // size of one EraseBlock in pages + virtual size_t flashEraseBlockSize(); + // size of one flash page in bytes + virtual size_t flashPageSize(); + // start of user flash aligned to start of an erase block + virtual uint8_t* userFlashStart(); + // size of the user flash in EraseBlocks + virtual size_t userFlashSizeEraseBlocks(); + //relativ to userFlashStart + virtual void flashErase(uint16_t eraseBlockNum); + //write a single page to flash (pageNumber relative to userFashStart + virtual void flashWritePage(uint16_t pageNumber, uint8_t* data); + + // writes _eraseblockBuffer to flash - overrides Plattform::writeBufferedEraseBlock() for performance optimization only + void writeBufferedEraseBlock(); #endif #if defined(KNX_NETIF) - uint32_t currentIpAddress() override; - uint32_t currentSubnetMask() override; - uint32_t currentDefaultGateway() override; - void macAddress(uint8_t* addr) override; + uint32_t currentIpAddress() override; + uint32_t currentSubnetMask() override; + uint32_t currentDefaultGateway() override; + void macAddress(uint8_t* addr) override; - // multicast - void setupMultiCast(uint32_t addr, uint16_t port) override; - void closeMultiCast() override; - bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override; - int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port) override; + // multicast + void setupMultiCast(uint32_t addr, uint16_t port) override; + void closeMultiCast() override; + bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override; + int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port) override; - // unicast - bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override; + // unicast + bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override; #define UDP_UNICAST _udp - protected: - WiFiUDP _udp; - protected: - IPAddress mcastaddr; - protected: - uint16_t _port; -#endif - protected: - pin_size_t _rxPin = UART_PIN_NOT_DEFINED; - protected: - pin_size_t _txPin = UART_PIN_NOT_DEFINED; - - protected: - IPAddress _remoteIP = 0; - protected: - uint16_t _remotePort = 0; -}; - + protected: + WiFiUDP _udp; + protected: + IPAddress mcastaddr; + protected: + uint16_t _port; #endif + protected: + pin_size_t _rxPin = UART_PIN_NOT_DEFINED; + protected: + pin_size_t _txPin = UART_PIN_NOT_DEFINED; + + protected: + IPAddress _remoteIP = 0; + protected: + uint16_t _remotePort = 0; + }; +} +#endif \ No newline at end of file diff --git a/src/knx/platform/samd_platform.cpp b/src/knx/platform/samd_platform.cpp index 8223745f..4c2f7554 100644 --- a/src/knx/platform/samd_platform.cpp +++ b/src/knx/platform/samd_platform.cpp @@ -16,227 +16,230 @@ #define KNX_SERIAL Serial1 #endif -SamdPlatform::SamdPlatform() +namespace Knx +{ + SamdPlatform::SamdPlatform() #ifndef KNX_NO_DEFAULT_UART - : ArduinoPlatform(&KNX_SERIAL) + : ArduinoPlatform(&KNX_SERIAL) #endif -{ + { #ifndef USE_SAMD_EEPROM_EMULATION - init(); + init(); #endif -} + } -SamdPlatform::SamdPlatform( HardwareSerial* s) : ArduinoPlatform(s) -{ + SamdPlatform::SamdPlatform( HardwareSerial* s) : ArduinoPlatform(s) + { #ifndef USE_SAMD_EEPROM_EMULATION - init(); + init(); #endif -} + } -uint32_t SamdPlatform::uniqueSerialNumber() -{ + uint32_t SamdPlatform::uniqueSerialNumber() + { #if defined (__SAMD51__) - // SAMD51 from section 9.6 of the datasheet + // SAMD51 from section 9.6 of the datasheet #define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x008061FC) #define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x00806010) #define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x00806014) #define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x00806018) #else - //#elif defined (__SAMD21E17A__) || defined(__SAMD21G18A__) || defined(__SAMD21E18A__) || defined(__SAMD21J18A__) - // SAMD21 from section 9.3.3 of the datasheet + //#elif defined (__SAMD21E17A__) || defined(__SAMD21G18A__) || defined(__SAMD21E18A__) || defined(__SAMD21J18A__) + // SAMD21 from section 9.3.3 of the datasheet #define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x0080A00C) #define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x0080A040) #define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x0080A044) #define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x0080A048) #endif - return SERIAL_NUMBER_WORD_0 ^ SERIAL_NUMBER_WORD_1 ^ SERIAL_NUMBER_WORD_2 ^ SERIAL_NUMBER_WORD_3; -} + return SERIAL_NUMBER_WORD_0 ^ SERIAL_NUMBER_WORD_1 ^ SERIAL_NUMBER_WORD_2 ^ SERIAL_NUMBER_WORD_3; + } -void SamdPlatform::restart() -{ - println("restart"); - NVIC_SystemReset(); -} + void SamdPlatform::restart() + { + println("restart"); + NVIC_SystemReset(); + } #ifdef USE_SAMD_EEPROM_EMULATION #pragma warning "Using EEPROM Simulation" -uint8_t* SamdPlatform::getEepromBuffer(uint32_t size) -{ - //EEPROM.begin(size); - if (size > EEPROM_EMULATION_SIZE) - fatalError(); + uint8_t* SamdPlatform::getEepromBuffer(uint32_t size) + { + //EEPROM.begin(size); + if (size > EEPROM_EMULATION_SIZE) + fatalError(); - return EEPROM.getDataPtr(); -} + return EEPROM.getDataPtr(); + } -void SamdPlatform::commitToEeprom() -{ - EEPROM.commit(); -} + void SamdPlatform::commitToEeprom() + { + EEPROM.commit(); + } #else -extern uint32_t __etext; -extern uint32_t __data_start__; -extern uint32_t __data_end__; + extern uint32_t __etext; + extern uint32_t __data_start__; + extern uint32_t __data_end__; -static const uint32_t pageSizes[] = {8, 16, 32, 64, 128, 256, 512, 1024}; + static const uint32_t pageSizes[] = {8, 16, 32, 64, 128, 256, 512, 1024}; -void SamdPlatform::init() -{ - _memoryType = Flash; - _pageSize = pageSizes[NVMCTRL->PARAM.bit.PSZ]; - _pageCnt = NVMCTRL->PARAM.bit.NVMP; - _rowSize = PAGES_PER_ROW * _pageSize; + void SamdPlatform::init() + { + _memoryType = Flash; + _pageSize = pageSizes[NVMCTRL->PARAM.bit.PSZ]; + _pageCnt = NVMCTRL->PARAM.bit.NVMP; + _rowSize = PAGES_PER_ROW * _pageSize; - // find end of program flash and set limit to next row - uint32_t endEddr = (uint32_t)(&__etext + (&__data_end__ - &__data_start__)); // text + data MemoryBlock + // find end of program flash and set limit to next row + uint32_t endEddr = (uint32_t)(&__etext + (&__data_end__ - &__data_start__)); // text + data MemoryBlock #ifdef KNX_FLASH_OFFSET - _MemoryStart = KNX_FLASH_OFFSET; - _MemoryEnd = KNX_FLASH_OFFSET + KNX_FLASH_SIZE; + _MemoryStart = KNX_FLASH_OFFSET; + _MemoryEnd = KNX_FLASH_OFFSET + KNX_FLASH_SIZE; #else - _MemoryStart = getRowAddr(_pageSize * _pageCnt - KNX_FLASH_SIZE - 1); // 23295 - _MemoryEnd = getRowAddr(_pageSize * _pageCnt - 1); + _MemoryStart = getRowAddr(_pageSize * _pageCnt - KNX_FLASH_SIZE - 1); // 23295 + _MemoryEnd = getRowAddr(_pageSize * _pageCnt - 1); #endif - // chosen flash size is not available anymore - if (_MemoryStart < endEddr) - { - println("KNX_FLASH_SIZE is not available (possible too much flash use by firmware)"); - fatalError(); + // chosen flash size is not available anymore + if (_MemoryStart < endEddr) + { + println("KNX_FLASH_SIZE is not available (possible too much flash use by firmware)"); + fatalError(); + } } -} - -size_t SamdPlatform::flashEraseBlockSize() -{ - return PAGES_PER_ROW; -} -size_t SamdPlatform::flashPageSize() -{ - return _pageSize; -} - -uint8_t* SamdPlatform::userFlashStart() -{ - return (uint8_t*)_MemoryStart; -} - -size_t SamdPlatform::userFlashSizeEraseBlocks() -{ - if (KNX_FLASH_SIZE <= 0) - return 0; - else - return ((KNX_FLASH_SIZE - 1) / (flashPageSize() * flashEraseBlockSize())) + 1; -} + size_t SamdPlatform::flashEraseBlockSize() + { + return PAGES_PER_ROW; + } -void SamdPlatform::flashErase(uint16_t eraseBlockNum) -{ - noInterrupts(); + size_t SamdPlatform::flashPageSize() + { + return _pageSize; + } - eraseRow((void*)(_MemoryStart + eraseBlockNum * _rowSize)); - // flash_range_erase(KNX_FLASH_OFFSET + eraseBlockNum * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize()); + uint8_t* SamdPlatform::userFlashStart() + { + return (uint8_t*)_MemoryStart; + } - interrupts(); -} + size_t SamdPlatform::userFlashSizeEraseBlocks() + { + if (KNX_FLASH_SIZE <= 0) + return 0; + else + return ((KNX_FLASH_SIZE - 1) / (flashPageSize() * flashEraseBlockSize())) + 1; + } -void SamdPlatform::flashWritePage(uint16_t pageNumber, uint8_t* data) -{ - noInterrupts(); + void SamdPlatform::flashErase(uint16_t eraseBlockNum) + { + noInterrupts(); - write((void*)(_MemoryStart + pageNumber * _pageSize), data, _pageSize); - // flash_range_program(KNX_FLASH_OFFSET + pageNumber * flashPageSize(), data, flashPageSize()); + eraseRow((void*)(_MemoryStart + eraseBlockNum * _rowSize)); + // flash_range_erase(KNX_FLASH_OFFSET + eraseBlockNum * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize()); - interrupts(); -} + interrupts(); + } -void SamdPlatform::writeBufferedEraseBlock() -{ - if (_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) + void SamdPlatform::flashWritePage(uint16_t pageNumber, uint8_t* data) { noInterrupts(); - eraseRow((void*)(_MemoryStart + _bufferedEraseblockNumber * _rowSize)); - write((void*)(_MemoryStart + _bufferedEraseblockNumber * _rowSize), _eraseblockBuffer, _rowSize); - // flash_range_erase(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize()); - // flash_range_program(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), _eraseblockBuffer, flashPageSize() * flashEraseBlockSize()); + write((void*)(_MemoryStart + pageNumber * _pageSize), data, _pageSize); + // flash_range_program(KNX_FLASH_OFFSET + pageNumber * flashPageSize(), data, flashPageSize()); interrupts(); - - _bufferedEraseblockDirty = false; } -} -uint32_t SamdPlatform::getRowAddr(uint32_t flasAddr) -{ - return flasAddr & ~(_rowSize - 1); -} - -void SamdPlatform::write(const volatile void* flash_ptr, const void* data, uint32_t size) -{ - // Calculate data boundaries - size = (size + 3) / 4; - volatile uint32_t* src_addr = (volatile uint32_t*)data; - volatile uint32_t* dst_addr = (volatile uint32_t*)flash_ptr; - // volatile uint32_t *dst_addr = (volatile uint32_t *)flash_ptr; - // const uint8_t *src_addr = (uint8_t *)data; + void SamdPlatform::writeBufferedEraseBlock() + { + if (_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) + { + noInterrupts(); - // Disable automatic page write - NVMCTRL->CTRLB.bit.MANW = 1; + eraseRow((void*)(_MemoryStart + _bufferedEraseblockNumber * _rowSize)); + write((void*)(_MemoryStart + _bufferedEraseblockNumber * _rowSize), _eraseblockBuffer, _rowSize); + // flash_range_erase(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize()); + // flash_range_program(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), _eraseblockBuffer, flashPageSize() * flashEraseBlockSize()); - // Do writes in pages - while (size) - { - // Execute "PBC" Page Buffer Clear - NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC; + interrupts(); - while (NVMCTRL->INTFLAG.bit.READY == 0) - { + _bufferedEraseblockDirty = false; } + } - // Fill page buffer - uint32_t i; + uint32_t SamdPlatform::getRowAddr(uint32_t flasAddr) + { + return flasAddr & ~(_rowSize - 1); + } - for (i = 0; i < (_pageSize / 4) && size; i++) + void SamdPlatform::write(const volatile void* flash_ptr, const void* data, uint32_t size) + { + // Calculate data boundaries + size = (size + 3) / 4; + volatile uint32_t* src_addr = (volatile uint32_t*)data; + volatile uint32_t* dst_addr = (volatile uint32_t*)flash_ptr; + // volatile uint32_t *dst_addr = (volatile uint32_t *)flash_ptr; + // const uint8_t *src_addr = (uint8_t *)data; + + // Disable automatic page write + NVMCTRL->CTRLB.bit.MANW = 1; + + // Do writes in pages + while (size) { - *dst_addr = *src_addr; - src_addr++; - dst_addr++; - size--; + // Execute "PBC" Page Buffer Clear + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC; + + while (NVMCTRL->INTFLAG.bit.READY == 0) + { + } + + // Fill page buffer + uint32_t i; + + for (i = 0; i < (_pageSize / 4) && size; i++) + { + *dst_addr = *src_addr; + src_addr++; + dst_addr++; + size--; + } + + // Execute "WP" Write Page + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP; + + while (NVMCTRL->INTFLAG.bit.READY == 0) + { + } } + } - // Execute "WP" Write Page - NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP; + void SamdPlatform::erase(const volatile void* flash_ptr, uint32_t size) + { + const uint8_t* ptr = (const uint8_t*)flash_ptr; - while (NVMCTRL->INTFLAG.bit.READY == 0) + while (size > _rowSize) { + eraseRow(ptr); + ptr += _rowSize; + size -= _rowSize; } - } -} - -void SamdPlatform::erase(const volatile void* flash_ptr, uint32_t size) -{ - const uint8_t* ptr = (const uint8_t*)flash_ptr; - while (size > _rowSize) - { eraseRow(ptr); - ptr += _rowSize; - size -= _rowSize; } - eraseRow(ptr); -} - -void SamdPlatform::eraseRow(const volatile void* flash_ptr) -{ - NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr) / 2; - NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER; - - while (!NVMCTRL->INTFLAG.bit.READY) + void SamdPlatform::eraseRow(const volatile void* flash_ptr) { + NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr) / 2; + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER; + + while (!NVMCTRL->INTFLAG.bit.READY) + { + } } -} #endif -#endif +} +#endif \ No newline at end of file diff --git a/src/knx/platform/samd_platform.h b/src/knx/platform/samd_platform.h index 45399d1f..7b32f511 100644 --- a/src/knx/platform/samd_platform.h +++ b/src/knx/platform/samd_platform.h @@ -6,50 +6,52 @@ #define PAGES_PER_ROW 4 -class SamdPlatform : public ArduinoPlatform +namespace Knx { - public: - SamdPlatform(); - SamdPlatform( HardwareSerial* s); + class SamdPlatform : public ArduinoPlatform + { + public: + SamdPlatform(); + SamdPlatform( HardwareSerial* s); - // unique serial number - uint32_t uniqueSerialNumber() override; + // unique serial number + uint32_t uniqueSerialNumber() override; - void restart(); + void restart(); #ifdef USE_SAMD_EEPROM_EMULATION - uint8_t* getEepromBuffer(uint32_t size); - void commitToEeprom(); + uint8_t* getEepromBuffer(uint32_t size); + void commitToEeprom(); #else - // size of one EraseBlock in pages - virtual size_t flashEraseBlockSize(); - // size of one flash page in bytes - virtual size_t flashPageSize(); - // start of user flash aligned to start of an erase block - virtual uint8_t* userFlashStart(); - // size of the user flash in EraseBlocks - virtual size_t userFlashSizeEraseBlocks(); - // relativ to userFlashStart - virtual void flashErase(uint16_t eraseBlockNum); - // write a single page to flash (pageNumber relative to userFashStart - virtual void flashWritePage(uint16_t pageNumber, uint8_t* data); - - // writes _eraseblockBuffer to flash - overrides Plattform::writeBufferedEraseBlock() for performance optimization only - void writeBufferedEraseBlock(); - - private: - void init(); - uint32_t _MemoryEnd = 0; - uint32_t _MemoryStart = 0; - uint32_t _pageSize; - uint32_t _rowSize; - uint32_t _pageCnt; - - uint32_t getRowAddr(uint32_t flasAddr); - void write(const volatile void* flash_ptr, const void* data, uint32_t size); - void erase(const volatile void* flash_ptr, uint32_t size); - void eraseRow(const volatile void* flash_ptr); - -#endif -}; + // size of one EraseBlock in pages + virtual size_t flashEraseBlockSize(); + // size of one flash page in bytes + virtual size_t flashPageSize(); + // start of user flash aligned to start of an erase block + virtual uint8_t* userFlashStart(); + // size of the user flash in EraseBlocks + virtual size_t userFlashSizeEraseBlocks(); + // relativ to userFlashStart + virtual void flashErase(uint16_t eraseBlockNum); + // write a single page to flash (pageNumber relative to userFashStart + virtual void flashWritePage(uint16_t pageNumber, uint8_t* data); + + // writes _eraseblockBuffer to flash - overrides Plattform::writeBufferedEraseBlock() for performance optimization only + void writeBufferedEraseBlock(); + + private: + void init(); + uint32_t _MemoryEnd = 0; + uint32_t _MemoryStart = 0; + uint32_t _pageSize; + uint32_t _rowSize; + uint32_t _pageCnt; + + uint32_t getRowAddr(uint32_t flasAddr); + void write(const volatile void* flash_ptr, const void* data, uint32_t size); + void erase(const volatile void* flash_ptr, uint32_t size); + void eraseRow(const volatile void* flash_ptr); #endif + }; +} +#endif \ No newline at end of file diff --git a/src/knx/platform/stm32_platform.cpp b/src/knx/platform/stm32_platform.cpp index aae418af..0cb0001e 100644 --- a/src/knx/platform/stm32_platform.cpp +++ b/src/knx/platform/stm32_platform.cpp @@ -8,67 +8,69 @@ #define KNX_SERIAL Serial2 #endif -Stm32Platform::Stm32Platform() +namespace Knx +{ + Stm32Platform::Stm32Platform() #ifndef KNX_NO_DEFAULT_UART - : ArduinoPlatform(&KNX_SERIAL) + : ArduinoPlatform(&KNX_SERIAL) #endif -{ -} + { + } -Stm32Platform::Stm32Platform( HardwareSerial* s) : ArduinoPlatform(s) -{ -} + Stm32Platform::Stm32Platform( HardwareSerial* s) : ArduinoPlatform(s) + { + } -Stm32Platform::~Stm32Platform() -{ - delete [] _eepromPtr; -} + Stm32Platform::~Stm32Platform() + { + delete [] _eepromPtr; + } -uint32_t Stm32Platform::uniqueSerialNumber() -{ - return HAL_GetUIDw0() ^ HAL_GetUIDw1() ^ HAL_GetUIDw2(); -} + uint32_t Stm32Platform::uniqueSerialNumber() + { + return HAL_GetUIDw0() ^ HAL_GetUIDw1() ^ HAL_GetUIDw2(); + } -void Stm32Platform::restart() -{ - NVIC_SystemReset(); -} + void Stm32Platform::restart() + { + NVIC_SystemReset(); + } -uint8_t* Stm32Platform::getEepromBuffer(uint32_t size) -{ - // check if the buffer already exists - if (_eepromPtr == nullptr) // we need to initialize the buffer first + uint8_t* Stm32Platform::getEepromBuffer(uint32_t size) { - if (size > E2END + 1) + // check if the buffer already exists + if (_eepromPtr == nullptr) // we need to initialize the buffer first { - fatalError(); - } + if (size > E2END + 1) + { + fatalError(); + } - _eepromSize = size; - _eepromPtr = new uint8_t[size]; - eeprom_buffer_fill(); + _eepromSize = size; + _eepromPtr = new uint8_t[size]; + eeprom_buffer_fill(); - for (uint16_t i = 0; i < size; ++i) - _eepromPtr[i] = eeprom_buffered_read_byte(i); - } + for (uint16_t i = 0; i < size; ++i) + _eepromPtr[i] = eeprom_buffered_read_byte(i); + } - return _eepromPtr; -} + return _eepromPtr; + } -void Stm32Platform::commitToEeprom() -{ - if (_eepromPtr == nullptr || _eepromSize == 0) - return; + void Stm32Platform::commitToEeprom() + { + if (_eepromPtr == nullptr || _eepromSize == 0) + return; - for (uint16_t i = 0; i < _eepromSize; ++i) - eeprom_buffered_write_byte(i, _eepromPtr[i]); + for (uint16_t i = 0; i < _eepromSize; ++i) + eeprom_buffered_write_byte(i, _eepromPtr[i]); - // For some GD32 chips, the flash needs to be unlocked twice - // and the first call will fail. If the first call is - // successful, the second one (inside eeprom_buffer_flush) - // does nothing. - HAL_FLASH_Unlock(); - eeprom_buffer_flush(); + // For some GD32 chips, the flash needs to be unlocked twice + // and the first call will fail. If the first call is + // successful, the second one (inside eeprom_buffer_flush) + // does nothing. + HAL_FLASH_Unlock(); + eeprom_buffer_flush(); + } } - -#endif +#endif \ No newline at end of file diff --git a/src/knx/platform/stm32_platform.h b/src/knx/platform/stm32_platform.h index daa50a04..e86549d1 100644 --- a/src/knx/platform/stm32_platform.h +++ b/src/knx/platform/stm32_platform.h @@ -1,25 +1,27 @@ #ifdef ARDUINO_ARCH_STM32 #include "arduino_platform.h" -class Stm32Platform : public ArduinoPlatform +namespace Knx { - public: - Stm32Platform(); - Stm32Platform( HardwareSerial* s); - ~Stm32Platform(); + class Stm32Platform : public ArduinoPlatform + { + public: + Stm32Platform(); + Stm32Platform( HardwareSerial* s); + ~Stm32Platform(); - // unique serial number - uint32_t uniqueSerialNumber() override; + // unique serial number + uint32_t uniqueSerialNumber() override; - // basic stuff - void restart(); + // basic stuff + void restart(); - //memory - uint8_t* getEepromBuffer(uint32_t size); - void commitToEeprom(); - private: - uint8_t* _eepromPtr = nullptr; - uint16_t _eepromSize = 0; -}; - -#endif + //memory + uint8_t* getEepromBuffer(uint32_t size); + void commitToEeprom(); + private: + uint8_t* _eepromPtr = nullptr; + uint16_t _eepromSize = 0; + }; +} +#endif \ No newline at end of file diff --git a/src/knx/rf/bau27B0.cpp b/src/knx/rf/bau27B0.cpp index 0afe806f..ea387331 100644 --- a/src/knx/rf/bau27B0.cpp +++ b/src/knx/rf/bau27B0.cpp @@ -5,199 +5,202 @@ #include #include -Bau27B0::Bau27B0(Platform& platform) - : BauSystemBDevice(platform), - _dlLayer(_deviceObj, _rfMediumObj, _netLayer.getInterface(), _platform) +namespace Knx +{ + Bau27B0::Bau27B0(Platform& platform) + : BauSystemBDevice(platform), + _dlLayer(_deviceObj, _rfMediumObj, _netLayer.getInterface(), _platform) #ifdef USE_CEMI_SERVER - , _cemiServer(*this) + , _cemiServer(*this) #endif -{ - _netLayer.getInterface().dataLinkLayer(_dlLayer); - _memory.addSaveRestore(&_rfMediumObj); + { + _netLayer.getInterface().dataLinkLayer(_dlLayer); + _memory.addSaveRestore(&_rfMediumObj); #ifdef USE_CEMI_SERVER - _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_RF); - _cemiServer.dataLinkLayer(_dlLayer); - _dlLayer.cemiServer(_cemiServer); - _memory.addSaveRestore(&_cemiServerObject); + _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_RF); + _cemiServer.dataLinkLayer(_dlLayer); + _dlLayer.cemiServer(_cemiServer); + _memory.addSaveRestore(&_cemiServerObject); #endif - // Set Mask Version in Device Object depending on the BAU - _deviceObj.maskVersion(0x27B0); - - // Set the maximum APDU length - // ETS will consider this value while programming the device - // For KNX-RF we use a smallest allowed value for now, - // although long frame are also supported by the implementation. - // Needs some experimentation. - _deviceObj.maxApduLength(15); - - // Set which interface objects are available in the device object - // This differs from BAU to BAU with different medium types. - // See PID_IO_LIST - Property* prop = _deviceObj.property(PID_IO_LIST); - prop->write(1, (uint16_t) OT_DEVICE); - prop->write(2, (uint16_t) OT_ADDR_TABLE); - prop->write(3, (uint16_t) OT_ASSOC_TABLE); - prop->write(4, (uint16_t) OT_GRP_OBJ_TABLE); - prop->write(5, (uint16_t) OT_APPLICATION_PROG); - prop->write(6, (uint16_t) OT_RF_MEDIUM); + // Set Mask Version in Device Object depending on the BAU + _deviceObj.maskVersion(0x27B0); + + // Set the maximum APDU length + // ETS will consider this value while programming the device + // For KNX-RF we use a smallest allowed value for now, + // although long frame are also supported by the implementation. + // Needs some experimentation. + _deviceObj.maxApduLength(15); + + // Set which interface objects are available in the device object + // This differs from BAU to BAU with different medium types. + // See PID_IO_LIST + Property* prop = _deviceObj.property(PID_IO_LIST); + prop->write(1, (uint16_t) OT_DEVICE); + prop->write(2, (uint16_t) OT_ADDR_TABLE); + prop->write(3, (uint16_t) OT_ASSOC_TABLE); + prop->write(4, (uint16_t) OT_GRP_OBJ_TABLE); + prop->write(5, (uint16_t) OT_APPLICATION_PROG); + prop->write(6, (uint16_t) OT_RF_MEDIUM); #if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER) - prop->write(7, (uint16_t) OT_SECURITY); - prop->write(8, (uint16_t) OT_CEMI_SERVER); + prop->write(7, (uint16_t) OT_SECURITY); + prop->write(8, (uint16_t) OT_CEMI_SERVER); #elif defined(USE_DATASECURE) - prop->write(7, (uint16_t) OT_SECURITY); + prop->write(7, (uint16_t) OT_SECURITY); #elif defined(USE_CEMI_SERVER) - prop->write(7, (uint16_t)OT_CEMI_SERVER); + prop->write(7, (uint16_t)OT_CEMI_SERVER); #endif -} + } -// see KNX AN160 p.74 for mask 27B0 -InterfaceObject* Bau27B0::getInterfaceObject(uint8_t idx) -{ - switch (idx) + // see KNX AN160 p.74 for mask 27B0 + InterfaceObject* Bau27B0::getInterfaceObject(uint8_t idx) { - case 0: - return &_deviceObj; + switch (idx) + { + case 0: + return &_deviceObj; - case 1: - return &_addrTable; + case 1: + return &_addrTable; - case 2: - return &_assocTable; + case 2: + return &_assocTable; - case 3: - return &_groupObjTable; + case 3: + return &_groupObjTable; - case 4: - return &_appProgram; + case 4: + return &_appProgram; - case 5: // would be app_program 2 - return nullptr; + case 5: // would be app_program 2 + return nullptr; - case 6: - return &_rfMediumObj; + case 6: + return &_rfMediumObj; #if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER) - case 7: - return &_secIfObj; + case 7: + return &_secIfObj; - case 8: - return &_cemiServerObject; + case 8: + return &_cemiServerObject; #elif defined(USE_CEMI_SERVER) - case 7: - return &_cemiServerObject; + case 7: + return &_cemiServerObject; #elif defined(USE_DATASECURE) - case 7: - return &_secIfObj; + case 7: + return &_secIfObj; #endif - default: - return nullptr; + default: + return nullptr; + } } -} -InterfaceObject* Bau27B0::getInterfaceObject(ObjectType objectType, uint16_t objectInstance) -{ - // We do not use it right now. - // Required for coupler mode as there are multiple router objects for example - (void) objectInstance; - - switch (objectType) + InterfaceObject* Bau27B0::getInterfaceObject(ObjectType objectType, uint16_t objectInstance) { - case OT_DEVICE: - return &_deviceObj; + // We do not use it right now. + // Required for coupler mode as there are multiple router objects for example + (void) objectInstance; + + switch (objectType) + { + case OT_DEVICE: + return &_deviceObj; - case OT_ADDR_TABLE: - return &_addrTable; + case OT_ADDR_TABLE: + return &_addrTable; - case OT_ASSOC_TABLE: - return &_assocTable; + case OT_ASSOC_TABLE: + return &_assocTable; - case OT_GRP_OBJ_TABLE: - return &_groupObjTable; + case OT_GRP_OBJ_TABLE: + return &_groupObjTable; - case OT_APPLICATION_PROG: - return &_appProgram; + case OT_APPLICATION_PROG: + return &_appProgram; - case OT_RF_MEDIUM: - return &_rfMediumObj; + case OT_RF_MEDIUM: + return &_rfMediumObj; #ifdef USE_DATASECURE - case OT_SECURITY: - return &_secIfObj; + case OT_SECURITY: + return &_secIfObj; #endif #ifdef USE_CEMI_SERVER - case OT_CEMI_SERVER: - return &_cemiServerObject; + case OT_CEMI_SERVER: + return &_cemiServerObject; #endif - default: - return nullptr; + default: + return nullptr; + } } -} -void Bau27B0::doMasterReset(EraseCode eraseCode, uint8_t channel) -{ - // Common SystemB objects - BauSystemB::doMasterReset(eraseCode, channel); + void Bau27B0::doMasterReset(EraseCode eraseCode, uint8_t channel) + { + // Common SystemB objects + BauSystemB::doMasterReset(eraseCode, channel); - _rfMediumObj.masterReset(eraseCode, channel); -} + _rfMediumObj.masterReset(eraseCode, channel); + } -bool Bau27B0::enabled() -{ - return _dlLayer.enabled(); -} + bool Bau27B0::enabled() + { + return _dlLayer.enabled(); + } -void Bau27B0::enabled(bool value) -{ - _dlLayer.enabled(value); -} + void Bau27B0::enabled(bool value) + { + _dlLayer.enabled(value); + } -void Bau27B0::loop() -{ - _dlLayer.loop(); - BauSystemBDevice::loop(); + void Bau27B0::loop() + { + _dlLayer.loop(); + BauSystemBDevice::loop(); #ifdef USE_CEMI_SERVER - _cemiServer.loop(); + _cemiServer.loop(); #endif -} + } -void Bau27B0::domainAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, - const uint8_t* knxSerialNumber) -{ - // If the received serial number matches our serial number - // then store the received RF domain address in the RF medium object - if (!memcmp(knxSerialNumber, _deviceObj.propertyData(PID_SERIAL_NUMBER), 6)) - _rfMediumObj.rfDomainAddress(rfDoA); -} + void Bau27B0::domainAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, + const uint8_t* knxSerialNumber) + { + // If the received serial number matches our serial number + // then store the received RF domain address in the RF medium object + if (!memcmp(knxSerialNumber, _deviceObj.propertyData(PID_SERIAL_NUMBER), 6)) + _rfMediumObj.rfDomainAddress(rfDoA); + } -void Bau27B0::domainAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber) -{ - // If the received serial number matches our serial number - // then send a response with the current RF domain address stored in the RF medium object - if (!memcmp(knxSerialNumber, _deviceObj.propertyData(PID_SERIAL_NUMBER), 6)) - _appLayer.domainAddressSerialNumberReadResponse(priority, hopType, secCtrl, _rfMediumObj.rfDomainAddress(), knxSerialNumber); -} + void Bau27B0::domainAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber) + { + // If the received serial number matches our serial number + // then send a response with the current RF domain address stored in the RF medium object + if (!memcmp(knxSerialNumber, _deviceObj.propertyData(PID_SERIAL_NUMBER), 6)) + _appLayer.domainAddressSerialNumberReadResponse(priority, hopType, secCtrl, _rfMediumObj.rfDomainAddress(), knxSerialNumber); + } -void Bau27B0::individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber) -{ + void Bau27B0::individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber) + { #pragma warning "individualAddressSerialNumberReadIndication is not available for rf" -} + } -void Bau27B0::domainAddressSerialNumberWriteLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, - const uint8_t* knxSerialNumber, bool status) -{ -} + void Bau27B0::domainAddressSerialNumberWriteLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, + const uint8_t* knxSerialNumber, bool status) + { + } -void Bau27B0::domainAddressSerialNumberReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber, bool status) -{ -} + void Bau27B0::domainAddressSerialNumberReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber, bool status) + { + } -RfDataLinkLayer* Bau27B0::getDataLinkLayer() -{ - return (RfDataLinkLayer*)&_dlLayer; + RfDataLinkLayer* Bau27B0::getDataLinkLayer() + { + return (RfDataLinkLayer*)&_dlLayer; + } } \ No newline at end of file diff --git a/src/knx/rf/bau27B0.h b/src/knx/rf/bau27B0.h index 8400c0f9..a3d45661 100644 --- a/src/knx/rf/bau27B0.h +++ b/src/knx/rf/bau27B0.h @@ -13,33 +13,36 @@ #include "../cemi_server/cemi_server.h" #include "../cemi_server/cemi_server_object.h" -class Bau27B0 : public BauSystemBDevice +namespace Knx { - public: - Bau27B0(Platform& platform); - void loop() override; - bool enabled() override; - void enabled(bool value) override; + class Bau27B0 : public BauSystemBDevice + { + public: + Bau27B0(Platform& platform); + void loop() override; + bool enabled() override; + void enabled(bool value) override; - RfDataLinkLayer* getDataLinkLayer(); - protected: - InterfaceObject* getInterfaceObject(uint8_t idx); - InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance); + RfDataLinkLayer* getDataLinkLayer(); + protected: + InterfaceObject* getInterfaceObject(uint8_t idx); + InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance); - void doMasterReset(EraseCode eraseCode, uint8_t channel) override; - private: - RfDataLinkLayer _dlLayer; - RfMediumObject _rfMediumObj; + void doMasterReset(EraseCode eraseCode, uint8_t channel) override; + private: + RfDataLinkLayer _dlLayer; + RfMediumObject _rfMediumObj; #ifdef USE_CEMI_SERVER - CemiServer _cemiServer; - CemiServerObject _cemiServerObject; + CemiServer _cemiServer; + CemiServerObject _cemiServerObject; #endif - void domainAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, - const uint8_t* knxSerialNumber) override; - void domainAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber) override; - void individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber) override; - void domainAddressSerialNumberWriteLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, - const uint8_t* knxSerialNumber, bool status) override; - void domainAddressSerialNumberReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber, bool status) override; -}; + void domainAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, + const uint8_t* knxSerialNumber) override; + void domainAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber) override; + void individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber) override; + void domainAddressSerialNumberWriteLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, + const uint8_t* knxSerialNumber, bool status) override; + void domainAddressSerialNumberReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber, bool status) override; + }; +} \ No newline at end of file diff --git a/src/knx/rf/rf_data_link_layer.cpp b/src/knx/rf/rf_data_link_layer.cpp index 96078465..16eb06a5 100644 --- a/src/knx/rf/rf_data_link_layer.cpp +++ b/src/knx/rf/rf_data_link_layer.cpp @@ -16,366 +16,369 @@ #include #include -void RfDataLinkLayer::loop() +namespace Knx { - if (!_enabled) - return; + void RfDataLinkLayer::loop() + { + if (!_enabled) + return; - _rfPhy.loop(); -} + _rfPhy.loop(); + } -bool RfDataLinkLayer::sendFrame(CemiFrame& frame) -{ - // If no serial number of domain address was set, - // use our own SN/DoA - if (frame.rfSerialOrDoA() == nullptr) + bool RfDataLinkLayer::sendFrame(CemiFrame& frame) { - // Depending on this flag, use either KNX Serial Number - // or the RF domain address that was programmed by ETS - if (frame.systemBroadcast() == SysBroadcast) + // If no serial number of domain address was set, + // use our own SN/DoA + if (frame.rfSerialOrDoA() == nullptr) { - frame.rfSerialOrDoA((uint8_t*)_deviceObject.propertyData(PID_SERIAL_NUMBER)); + // Depending on this flag, use either KNX Serial Number + // or the RF domain address that was programmed by ETS + if (frame.systemBroadcast() == SysBroadcast) + { + frame.rfSerialOrDoA((uint8_t*)_deviceObject.propertyData(PID_SERIAL_NUMBER)); + } + else + { + frame.rfSerialOrDoA(_rfMediumObj.rfDomainAddress()); + } } - else + + // If Link Layer frame is set to 0xFF, + // use our own counter + if (frame.rfLfn() == 0xFF) { - frame.rfSerialOrDoA(_rfMediumObj.rfDomainAddress()); + // Set Data Link Layer Frame Number + frame.rfLfn(_frameNumber); + // Link Layer frame number counts 0..7 + _frameNumber = (_frameNumber + 1) & 0x7; } - } - // If Link Layer frame is set to 0xFF, - // use our own counter - if (frame.rfLfn() == 0xFF) - { - // Set Data Link Layer Frame Number - frame.rfLfn(_frameNumber); - // Link Layer frame number counts 0..7 - _frameNumber = (_frameNumber + 1) & 0x7; - } + // bidirectional device, battery is ok, signal strength indication is void (no measurement) + frame.rfInfo(0x02); - // bidirectional device, battery is ok, signal strength indication is void (no measurement) - frame.rfInfo(0x02); + if (!_enabled) + { + dataConReceived(frame, false); + return false; + } - if (!_enabled) - { - dataConReceived(frame, false); - return false; - } + // TODO: Is queueing really required? + // According to the spec. the upper layer may only send a new L_Data.req if it received + // the L_Data.con for the previous L_Data.req. + addFrameTxQueue(frame); - // TODO: Is queueing really required? - // According to the spec. the upper layer may only send a new L_Data.req if it received - // the L_Data.con for the previous L_Data.req. - addFrameTxQueue(frame); - - // TODO: For now L_data.req is confirmed immediately (L_Data.con) - // see 3.6.3 p.80: L_Data.con shall be generated AFTER transmission of the corresponsing frame - // RF sender will never generate L_Data.con with C=1 (Error), but only if the TX buffer overflows - // The RF sender cannot detect if the RF frame was transmitted successfully or not according to the spec. - dataConReceived(frame, true); - - return true; -} - -RfDataLinkLayer::RfDataLinkLayer(DeviceObject& devObj, RfMediumObject& rfMediumObj, - NetworkLayerEntity& netLayerEntity, Platform& platform) - : DataLinkLayer(devObj, netLayerEntity, platform), - _rfMediumObj(rfMediumObj), - _rfPhy(*this, platform) -{ -} + // TODO: For now L_data.req is confirmed immediately (L_Data.con) + // see 3.6.3 p.80: L_Data.con shall be generated AFTER transmission of the corresponsing frame + // RF sender will never generate L_Data.con with C=1 (Error), but only if the TX buffer overflows + // The RF sender cannot detect if the RF frame was transmitted successfully or not according to the spec. + dataConReceived(frame, true); -void RfDataLinkLayer::frameBytesReceived(uint8_t* rfPacketBuf, uint16_t length) -{ - // RF data link layer frame format - // See 3.2.5 p.22 + return true; + } - // First block + smallest KNX telegram will give a minimum size of 22 bytes with checksum bytes - if (length < 21) + RfDataLinkLayer::RfDataLinkLayer(DeviceObject& devObj, RfMediumObject& rfMediumObj, + NetworkLayerEntity& netLayerEntity, Platform& platform) + : DataLinkLayer(devObj, netLayerEntity, platform), + _rfMediumObj(rfMediumObj), + _rfPhy(*this, platform) { - print("Received packet is too small. length: "); - println(length); - return; } + void RfDataLinkLayer::frameBytesReceived(uint8_t* rfPacketBuf, uint16_t length) + { + // RF data link layer frame format + // See 3.2.5 p.22 + + // First block + smallest KNX telegram will give a minimum size of 22 bytes with checksum bytes + if (length < 21) + { + print("Received packet is too small. length: "); + println(length); + return; + } + #if defined(DeviceFamily_CC13X0) - // Small optimization: - // We do not calculate the CRC16-DNP again for the first block. - // It was already done in the CC13x0 RX driver during reception. - // Also the two fixed bytes 0x44 and 0xFF are also there. - // So if we get here we can assume a valid block 1 + // Small optimization: + // We do not calculate the CRC16-DNP again for the first block. + // It was already done in the CC13x0 RX driver during reception. + // Also the two fixed bytes 0x44 and 0xFF are also there. + // So if we get here we can assume a valid block 1 #else - // CRC16-DNP of first block is always located here - uint16_t block1Crc = rfPacketBuf[10] << 8 | rfPacketBuf[11]; - - // If the checksum was ok and the other - // two constant header bytes match the KNX-RF spec. (C-field: 0x44 and ESC-field: 0xFF)... - // then we seem to have a valid first block of an KNX RF frame. - // The first block basically contains the RF-info field and the KNX SN/Domain address. - if ((rfPacketBuf[1] == 0x44) && - (rfPacketBuf[2] == 0xFF) && - (crc16Dnp(rfPacketBuf, 10) == block1Crc)) + // CRC16-DNP of first block is always located here + uint16_t block1Crc = rfPacketBuf[10] << 8 | rfPacketBuf[11]; + + // If the checksum was ok and the other + // two constant header bytes match the KNX-RF spec. (C-field: 0x44 and ESC-field: 0xFF)... + // then we seem to have a valid first block of an KNX RF frame. + // The first block basically contains the RF-info field and the KNX SN/Domain address. + if ((rfPacketBuf[1] == 0x44) && + (rfPacketBuf[2] == 0xFF) && + (crc16Dnp(rfPacketBuf, 10) == block1Crc)) #endif - { - // bytes left from the remaining block(s) - uint16_t bytesLeft = length - 12; - // we use two pointers to move over the two buffers - uint8_t* pRfPacketBuf = &rfPacketBuf[12]; // pointer to start of RF frame block 2 (with CTRL field) - // Reserve 1 byte (+1) for the second ctrl field - // cEMI frame has two CTRL fields, but RF frame has only one, but uses ALWAYS extended frames - // Information for BOTH cEMI CTRL fields is distributed in a RF frame (RF CTRL field and RF L/NPCI field) - // So we cannot just copy an RF frame with CTRL fields as is - // KNX RF frame will be placed starting at cEMI CTRL2 field (so RF CTRL field is CTRL2 field cEMI) - uint8_t* pBuffer = &_buffer[CEMI_HEADER_SIZE + 1]; - // New length of the packet with CRC bytes removed, add space for CEMI header and the second CTRL field - uint16_t newLength = CEMI_HEADER_SIZE + 1; - - // Now check each block checksum and copy the payload of the block - // into a new buffer without checksum - uint16_t blockCrc; - bool crcOk = true; - - while (bytesLeft > 18) { - // Get CRC16 from end of the block - blockCrc = pRfPacketBuf[16] << 8 | pRfPacketBuf[17]; - - if (crc16Dnp(pRfPacketBuf, 16) == blockCrc) + // bytes left from the remaining block(s) + uint16_t bytesLeft = length - 12; + // we use two pointers to move over the two buffers + uint8_t* pRfPacketBuf = &rfPacketBuf[12]; // pointer to start of RF frame block 2 (with CTRL field) + // Reserve 1 byte (+1) for the second ctrl field + // cEMI frame has two CTRL fields, but RF frame has only one, but uses ALWAYS extended frames + // Information for BOTH cEMI CTRL fields is distributed in a RF frame (RF CTRL field and RF L/NPCI field) + // So we cannot just copy an RF frame with CTRL fields as is + // KNX RF frame will be placed starting at cEMI CTRL2 field (so RF CTRL field is CTRL2 field cEMI) + uint8_t* pBuffer = &_buffer[CEMI_HEADER_SIZE + 1]; + // New length of the packet with CRC bytes removed, add space for CEMI header and the second CTRL field + uint16_t newLength = CEMI_HEADER_SIZE + 1; + + // Now check each block checksum and copy the payload of the block + // into a new buffer without checksum + uint16_t blockCrc; + bool crcOk = true; + + while (bytesLeft > 18) { - // Copy only the payload without the checksums - memcpy(pBuffer, pRfPacketBuf, 16); - } - else - { - crcOk = false; - break; - } + // Get CRC16 from end of the block + blockCrc = pRfPacketBuf[16] << 8 | pRfPacketBuf[17]; - pBuffer += 16; - pRfPacketBuf += 18; - newLength += 16; - bytesLeft -= 18; - } + if (crc16Dnp(pRfPacketBuf, 16) == blockCrc) + { + // Copy only the payload without the checksums + memcpy(pBuffer, pRfPacketBuf, 16); + } + else + { + crcOk = false; + break; + } - // Now process the last block - blockCrc = pRfPacketBuf[bytesLeft - 2] << 8 | pRfPacketBuf[bytesLeft - 1]; - crcOk = crcOk && (crc16Dnp(&pRfPacketBuf[0], bytesLeft - 2) == blockCrc); + pBuffer += 16; + pRfPacketBuf += 18; + newLength += 16; + bytesLeft -= 18; + } - // If all checksums were ok, then... - if (crcOk) - { - // Copy rest of the received packet without checksum - memcpy(pBuffer, pRfPacketBuf, bytesLeft - 2); - newLength += bytesLeft - 2; - - // Prepare CEMI by writing/overwriting certain fields in the buffer (contiguous frame without CRC checksums) - // See 3.6.3 p.79: L_Data services for KNX RF asynchronous frames - // For now we do not use additional info, but use normal method arguments for CEMI - _buffer[0] = (uint8_t) L_data_ind; // L_data.ind - _buffer[1] = 0; // Additional info length (spec. says that local dev management is not required to use AddInfo internally) - _buffer[2] = 0; // CTRL1 field (will be set later, this is the field we reserved space for) - _buffer[3] &= 0x0F; // CTRL2 field (take only RFCtrl.b3..0, b7..4 shall always be 0 for asynchronous KNX RF) - - // Now get all control bits from the L/NPCI field of the RF frame - // so that we can overwrite it afterwards with the correct NPDU length - // Get data link layer frame number (LFN field) from L/NPCI.LFN (bit 3..1) - uint8_t lfn = (_buffer[8] & 0x0E) >> 1; - // Get address type from L/NPCI.LFN (bit 7) - AddressType addressType = (_buffer[8] & 0x80) ? GroupAddress : IndividualAddress; - // Get routing counter from L/NPCI.LFN (bit 6..4) and map to hop count in Ctrl2.b6-4 - uint8_t hopCount = (_buffer[8] & 0x70) >> 4; - // Get AddrExtensionType from L/NPCI.LFN (bit 7) and map to system broadcast flag in Ctrl1.b4 - SystemBroadcast systemBroadcast = (_buffer[8] & 0x01) ? Broadcast : SysBroadcast; - - // Setup L field of the cEMI frame with the NPDU length - // newLength -8 bytes (NPDU_LPDU_DIFF, no AddInfo) -1 byte length field -1 byte TPCI/APCI bits - _buffer[8] = newLength - NPDU_LPDU_DIFF - 1 - 1; - - // If we have a broadcast message (within the domain), - // then we received the domain address and not the KNX serial number - if (systemBroadcast == Broadcast) + // Now process the last block + blockCrc = pRfPacketBuf[bytesLeft - 2] << 8 | pRfPacketBuf[bytesLeft - 1]; + crcOk = crcOk && (crc16Dnp(&pRfPacketBuf[0], bytesLeft - 2) == blockCrc); + + // If all checksums were ok, then... + if (crcOk) { - // Check if the received RF domain address matches the one stored in the RF medium object - // If it does not match then skip the remaining processing - if (memcmp(_rfMediumObj.rfDomainAddress(), &rfPacketBuf[4], 6)) + // Copy rest of the received packet without checksum + memcpy(pBuffer, pRfPacketBuf, bytesLeft - 2); + newLength += bytesLeft - 2; + + // Prepare CEMI by writing/overwriting certain fields in the buffer (contiguous frame without CRC checksums) + // See 3.6.3 p.79: L_Data services for KNX RF asynchronous frames + // For now we do not use additional info, but use normal method arguments for CEMI + _buffer[0] = (uint8_t) L_data_ind; // L_data.ind + _buffer[1] = 0; // Additional info length (spec. says that local dev management is not required to use AddInfo internally) + _buffer[2] = 0; // CTRL1 field (will be set later, this is the field we reserved space for) + _buffer[3] &= 0x0F; // CTRL2 field (take only RFCtrl.b3..0, b7..4 shall always be 0 for asynchronous KNX RF) + + // Now get all control bits from the L/NPCI field of the RF frame + // so that we can overwrite it afterwards with the correct NPDU length + // Get data link layer frame number (LFN field) from L/NPCI.LFN (bit 3..1) + uint8_t lfn = (_buffer[8] & 0x0E) >> 1; + // Get address type from L/NPCI.LFN (bit 7) + AddressType addressType = (_buffer[8] & 0x80) ? GroupAddress : IndividualAddress; + // Get routing counter from L/NPCI.LFN (bit 6..4) and map to hop count in Ctrl2.b6-4 + uint8_t hopCount = (_buffer[8] & 0x70) >> 4; + // Get AddrExtensionType from L/NPCI.LFN (bit 7) and map to system broadcast flag in Ctrl1.b4 + SystemBroadcast systemBroadcast = (_buffer[8] & 0x01) ? Broadcast : SysBroadcast; + + // Setup L field of the cEMI frame with the NPDU length + // newLength -8 bytes (NPDU_LPDU_DIFF, no AddInfo) -1 byte length field -1 byte TPCI/APCI bits + _buffer[8] = newLength - NPDU_LPDU_DIFF - 1 - 1; + + // If we have a broadcast message (within the domain), + // then we received the domain address and not the KNX serial number + if (systemBroadcast == Broadcast) { - println("RX domain address does not match. Skipping..."); - return; + // Check if the received RF domain address matches the one stored in the RF medium object + // If it does not match then skip the remaining processing + if (memcmp(_rfMediumObj.rfDomainAddress(), &rfPacketBuf[4], 6)) + { + println("RX domain address does not match. Skipping..."); + return; + } } - } - // TODO - // Frame duplication prevention based on LFN (see KKNX RF spec. 3.2.5 p.28) - - // Prepare the cEMI frame - CemiFrame frame(_buffer, newLength); - frame.frameType(ExtendedFrame); // KNX RF uses only extended frame format - frame.priority(SystemPriority); // Not used in KNX RF - frame.ack(AckDontCare); // Not used in KNX RF - frame.systemBroadcast(systemBroadcast); // Mapped from flag AddrExtensionType (KNX serial(0) or Domain Address(1)) - frame.hopCount(hopCount); // Hop count from routing counter - frame.addressType(addressType); // Group address or individual address - frame.rfSerialOrDoA(&rfPacketBuf[4]); // Copy pointer to field Serial or Domain Address (check broadcast flag what it is exactly) - frame.rfInfo(rfPacketBuf[3]); // RF-info field (1 byte) - frame.rfLfn(lfn); // Data link layer frame number (LFN field) - /* - print("RX LFN: "); - print(lfn); - print(" len: "); - print(newLength); - - print(" data: "); - printHex(" data: ", _buffer, newLength); - */ - frameReceived(frame); + // TODO + // Frame duplication prevention based on LFN (see KKNX RF spec. 3.2.5 p.28) + + // Prepare the cEMI frame + CemiFrame frame(_buffer, newLength); + frame.frameType(ExtendedFrame); // KNX RF uses only extended frame format + frame.priority(SystemPriority); // Not used in KNX RF + frame.ack(AckDontCare); // Not used in KNX RF + frame.systemBroadcast(systemBroadcast); // Mapped from flag AddrExtensionType (KNX serial(0) or Domain Address(1)) + frame.hopCount(hopCount); // Hop count from routing counter + frame.addressType(addressType); // Group address or individual address + frame.rfSerialOrDoA(&rfPacketBuf[4]); // Copy pointer to field Serial or Domain Address (check broadcast flag what it is exactly) + frame.rfInfo(rfPacketBuf[3]); // RF-info field (1 byte) + frame.rfLfn(lfn); // Data link layer frame number (LFN field) + /* + print("RX LFN: "); + print(lfn); + print(" len: "); + print(newLength); + + print(" data: "); + printHex(" data: ", _buffer, newLength); + */ + frameReceived(frame); + } } } -} -void RfDataLinkLayer::enabled(bool value) -{ - if (value && !_enabled) + void RfDataLinkLayer::enabled(bool value) { - if (_rfPhy.InitChip()) + if (value && !_enabled) { - _enabled = true; - print("ownaddr "); - println(_deviceObject.individualAddress(), HEX); + if (_rfPhy.InitChip()) + { + _enabled = true; + print("ownaddr "); + println(_deviceObject.individualAddress(), HEX); + } + else + { + _enabled = false; + println("ERROR, RF transceiver not responding"); + } + + return; } - else + + if (!value && _enabled) { + _rfPhy.stopChip(); _enabled = false; - println("ERROR, RF transceiver not responding"); + return; } - - return; } - if (!value && _enabled) + bool RfDataLinkLayer::enabled() const { - _rfPhy.stopChip(); - _enabled = false; - return; + return _enabled; } -} -bool RfDataLinkLayer::enabled() const -{ - return _enabled; -} + DptMedium RfDataLinkLayer::mediumType() const + { + return DptMedium::KNX_RF; + } -DptMedium RfDataLinkLayer::mediumType() const -{ - return DptMedium::KNX_RF; -} + void RfDataLinkLayer::fillRfFrame(CemiFrame& frame, uint8_t* data) + { + uint16_t crc; + uint16_t length = frame.telegramLengthtRF(); -void RfDataLinkLayer::fillRfFrame(CemiFrame& frame, uint8_t* data) -{ - uint16_t crc; - uint16_t length = frame.telegramLengthtRF(); + data[0] = 9 + length; // Length block1 (always 9 bytes, without length itself) + Length of KNX telegram without CRCs + data[1] = 0x44; // C field: According to IEC870-5. KNX only uses SEND/NO REPLY (C = 44h) + data[2] = 0xFF; // ESC field: This field shall have the fixed value FFh. + data[3] = frame.rfInfo(); // RF-info field - data[0] = 9 + length; // Length block1 (always 9 bytes, without length itself) + Length of KNX telegram without CRCs - data[1] = 0x44; // C field: According to IEC870-5. KNX only uses SEND/NO REPLY (C = 44h) - data[2] = 0xFF; // ESC field: This field shall have the fixed value FFh. - data[3] = frame.rfInfo(); // RF-info field + // Generate CRC16-DNP over the first block of data + pushByteArray(frame.rfSerialOrDoA(), 6, &data[4]); + crc = crc16Dnp(&data[0], 10); + pushWord(crc, &data[10]); - // Generate CRC16-DNP over the first block of data - pushByteArray(frame.rfSerialOrDoA(), 6, &data[4]); - crc = crc16Dnp(&data[0], 10); - pushWord(crc, &data[10]); + // Put the complete KNX telegram into a temporary buffer + // as we have to add CRC16 checksums after each block of 16 bytes + frame.fillTelegramRF(_buffer); - // Put the complete KNX telegram into a temporary buffer - // as we have to add CRC16 checksums after each block of 16 bytes - frame.fillTelegramRF(_buffer); + // Create a checksum for each block of full 16 bytes + uint16_t bytesLeft = length; + uint8_t* pBuffer = &_buffer[0]; + uint8_t* pData = &data[12]; - // Create a checksum for each block of full 16 bytes - uint16_t bytesLeft = length; - uint8_t* pBuffer = &_buffer[0]; - uint8_t* pData = &data[12]; + while (bytesLeft > 16) + { + memcpy(pData, pBuffer, 16); + crc = crc16Dnp(pData, 16); + pushWord(crc, &pData[16]); - while (bytesLeft > 16) - { - memcpy(pData, pBuffer, 16); - crc = crc16Dnp(pData, 16); - pushWord(crc, &pData[16]); + pBuffer += 16; + pData += 18; + bytesLeft -= 16; + } - pBuffer += 16; - pData += 18; - bytesLeft -= 16; + // Copy remaining bytes of last block. Could be less than 16 bytes + memcpy(pData, pBuffer, bytesLeft); + // And add last CRC + crc = crc16Dnp(pData, bytesLeft); + pushWord(crc, &pData[bytesLeft]); } - // Copy remaining bytes of last block. Could be less than 16 bytes - memcpy(pData, pBuffer, bytesLeft); - // And add last CRC - crc = crc16Dnp(pData, bytesLeft); - pushWord(crc, &pData[bytesLeft]); -} - -void RfDataLinkLayer::addFrameTxQueue(CemiFrame& frame) -{ - _tx_queue_frame_t* tx_frame = new _tx_queue_frame_t; + void RfDataLinkLayer::addFrameTxQueue(CemiFrame& frame) + { + _tx_queue_frame_t* tx_frame = new _tx_queue_frame_t; - uint16_t length = frame.telegramLengthtRF(); // Just the pure KNX telegram from CTRL field until end of APDU - uint8_t nrFullBlocks = length / 16; // Number of full (16 bytes) RF blocks required - uint8_t bytesLeft = length % 16; // Remaining bytes of the last packet + uint16_t length = frame.telegramLengthtRF(); // Just the pure KNX telegram from CTRL field until end of APDU + uint8_t nrFullBlocks = length / 16; // Number of full (16 bytes) RF blocks required + uint8_t bytesLeft = length % 16; // Remaining bytes of the last packet - // Calculate total number of bytes required to store the complete raw RF frame - // Block1 always requires 12 bytes including Length and CRC - // Each full block has 16 bytes payload plus 2 bytes CRC - // Add remaining bytes of the last block and add 2 bytes for CRC - uint16_t totalLength = 12 + (nrFullBlocks * 18) + bytesLeft + 2; + // Calculate total number of bytes required to store the complete raw RF frame + // Block1 always requires 12 bytes including Length and CRC + // Each full block has 16 bytes payload plus 2 bytes CRC + // Add remaining bytes of the last block and add 2 bytes for CRC + uint16_t totalLength = 12 + (nrFullBlocks * 18) + bytesLeft + 2; - tx_frame->length = totalLength; - tx_frame->data = new uint8_t[tx_frame->length]; - tx_frame->next = NULL; + tx_frame->length = totalLength; + tx_frame->data = new uint8_t[tx_frame->length]; + tx_frame->next = NULL; - // Prepare the raw RF frame - fillRfFrame(frame, tx_frame->data); + // Prepare the raw RF frame + fillRfFrame(frame, tx_frame->data); - /* - print("TX LFN: "); - print(frame.rfLfn()); + /* + print("TX LFN: "); + print(frame.rfLfn()); - print(" len: "); - print(totalLength); + print(" len: "); + print(totalLength); - printHex(" data:", tx_frame->data, totalLength); - */ - 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; + printHex(" data:", tx_frame->data, totalLength); + */ + 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 RfDataLinkLayer::isTxQueueEmpty() -{ - if (_tx_queue.front == NULL) + bool RfDataLinkLayer::isTxQueueEmpty() { - return true; - } + if (_tx_queue.front == NULL) + { + return true; + } - return false; -} + return false; + } -void RfDataLinkLayer::loadNextTxFrame(uint8_t** sendBuffer, uint16_t* sendBufferLength) -{ - if (_tx_queue.front == NULL) + void RfDataLinkLayer::loadNextTxFrame(uint8_t** sendBuffer, uint16_t* sendBufferLength) { - return; - } + 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; + _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; - } + if (_tx_queue.front == NULL) + { + _tx_queue.back = NULL; + } - delete tx_frame; + delete tx_frame; + } } \ No newline at end of file diff --git a/src/knx/rf/rf_data_link_layer.h b/src/knx/rf/rf_data_link_layer.h index 3c846d6b..7132b3c2 100644 --- a/src/knx/rf/rf_data_link_layer.h +++ b/src/knx/rf/rf_data_link_layer.h @@ -1,9 +1,9 @@ #pragma once #if defined(DeviceFamily_CC13X0) - #include "rf_physical_layer_cc1310.h" + #include "rf_physical_layer_cc1310.h" #else - #include "rf_physical_layer_cc1101.h" + #include "rf_physical_layer_cc1101.h" #endif #include "../config.h" @@ -14,58 +14,61 @@ #define MAX_KNX_TELEGRAM_SIZE 263 -class RfMediumObject; - -class RfDataLinkLayer : public DataLinkLayer +namespace Knx { + class RfMediumObject; + + class RfDataLinkLayer : public DataLinkLayer + { #if defined(DeviceFamily_CC13X0) - friend class RfPhysicalLayerCC1310; + friend class RfPhysicalLayerCC1310; #else - friend class RfPhysicalLayerCC1101; + friend class RfPhysicalLayerCC1101; #endif - using DataLinkLayer::_deviceObject; - using DataLinkLayer::_platform; + using DataLinkLayer::_deviceObject; + using DataLinkLayer::_platform; - public: - RfDataLinkLayer(DeviceObject& devObj, RfMediumObject& rfMediumObj, NetworkLayerEntity& netLayerEntity, - Platform& platform); + public: + RfDataLinkLayer(DeviceObject& devObj, RfMediumObject& rfMediumObj, NetworkLayerEntity& netLayerEntity, + Platform& platform); - void loop(); - void enabled(bool value); - bool enabled() const; - DptMedium mediumType() const override; + void loop(); + void enabled(bool value); + bool enabled() const; + DptMedium mediumType() const override; - private: - bool _enabled = false; - uint8_t _loopState = 0; + private: + bool _enabled = false; + uint8_t _loopState = 0; - uint8_t _buffer[512]; + uint8_t _buffer[512]; - uint8_t _frameNumber = 0; + uint8_t _frameNumber = 0; - struct _tx_queue_frame_t - { - uint8_t* data; - uint16_t length; - _tx_queue_frame_t* next; - }; + 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; + struct _tx_queue_t + { + _tx_queue_frame_t* front = NULL; + _tx_queue_frame_t* back = NULL; + } _tx_queue; - RfMediumObject& _rfMediumObj; + RfMediumObject& _rfMediumObj; #if defined(DeviceFamily_CC13X0) - RfPhysicalLayerCC1310 _rfPhy; + RfPhysicalLayerCC1310 _rfPhy; #else - RfPhysicalLayerCC1101 _rfPhy; + RfPhysicalLayerCC1101 _rfPhy; #endif - void fillRfFrame(CemiFrame& frame, uint8_t* data); - void addFrameTxQueue(CemiFrame& frame); - bool isTxQueueEmpty(); - void loadNextTxFrame(uint8_t** sendBuffer, uint16_t* sendBufferLength); - bool sendFrame(CemiFrame& frame); - void frameBytesReceived(uint8_t* buffer, uint16_t length); -}; + void fillRfFrame(CemiFrame& frame, uint8_t* data); + void addFrameTxQueue(CemiFrame& frame); + bool isTxQueueEmpty(); + void loadNextTxFrame(uint8_t** sendBuffer, uint16_t* sendBufferLength); + bool sendFrame(CemiFrame& frame); + void frameBytesReceived(uint8_t* buffer, uint16_t length); + }; +} \ No newline at end of file diff --git a/src/knx/rf/rf_medium_object.cpp b/src/knx/rf/rf_medium_object.cpp index 2c0c732f..9ec0f993 100644 --- a/src/knx/rf/rf_medium_object.cpp +++ b/src/knx/rf/rf_medium_object.cpp @@ -4,53 +4,56 @@ #include -RfMediumObject::RfMediumObject() +namespace Knx { - uint8_t rfDomainAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // see KNX RF S-Mode AN160 p.11 - Property* properties[] = + RfMediumObject::RfMediumObject() { - new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_RF_MEDIUM), - new DataProperty(PID_RF_MULTI_TYPE, true, PDT_GENERIC_01, 1, ReadLv3 | WriteLv2, (uint8_t)0x00), - new DataProperty(PID_RF_RETRANSMITTER, false, PDT_GENERIC_01, 1, ReadLv3 | WriteLv0, (uint8_t)0x00), - new DataProperty(PID_RF_DOMAIN_ADDRESS, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv2, rfDomainAddress), - new FunctionProperty(this, PID_RF_BIDIR_TIMEOUT, - [](RfMediumObject * io, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) + uint8_t rfDomainAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // see KNX RF S-Mode AN160 p.11 + Property* properties[] = { - resultData[0] = 0x00; // success - resultData[1] = 0xFF; // permanent bidirectional device - resultData[2] = 0xFF; // permanent bidirectional device - resultLength = 3; - }, - [](RfMediumObject * io, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) - { - resultData[0] = 0x00; // success - resultData[1] = 0xFF; // permanent bidirectional device - resultData[2] = 0xFF; // permanent bidirectional device - resultLength = 3; - }), - /* These properties are used in NMP_LinkBudget_Measure to diagnose the Link Budget of the communication. - This in not implemented yet. - new DataProperty(PID_RF_DIAG_SA_FILTER_TABLE, true, PDT_GENERIC_03, 8, ReadLv3 | WriteLv3), - new DataProperty(PID_RF_DIAG_BUDGET_TABLE, false, PDT_GENERIC_03, 8, ReadLv3 | WriteLv0), - new FunctionProperty(this, PID_RF_DIAG_PROBE, - [](RfMediumObject* io, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) - { - }, - [](RfMediumObject* io, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) - { - }), */ - }; - initializeProperties(sizeof(properties), properties); -} + new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_RF_MEDIUM), + new DataProperty(PID_RF_MULTI_TYPE, true, PDT_GENERIC_01, 1, ReadLv3 | WriteLv2, (uint8_t)0x00), + new DataProperty(PID_RF_RETRANSMITTER, false, PDT_GENERIC_01, 1, ReadLv3 | WriteLv0, (uint8_t)0x00), + new DataProperty(PID_RF_DOMAIN_ADDRESS, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv2, rfDomainAddress), + new FunctionProperty(this, PID_RF_BIDIR_TIMEOUT, + [](RfMediumObject * io, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) + { + resultData[0] = 0x00; // success + resultData[1] = 0xFF; // permanent bidirectional device + resultData[2] = 0xFF; // permanent bidirectional device + resultLength = 3; + }, + [](RfMediumObject * io, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) + { + resultData[0] = 0x00; // success + resultData[1] = 0xFF; // permanent bidirectional device + resultData[2] = 0xFF; // permanent bidirectional device + resultLength = 3; + }), + /* These properties are used in NMP_LinkBudget_Measure to diagnose the Link Budget of the communication. + This in not implemented yet. + new DataProperty(PID_RF_DIAG_SA_FILTER_TABLE, true, PDT_GENERIC_03, 8, ReadLv3 | WriteLv3), + new DataProperty(PID_RF_DIAG_BUDGET_TABLE, false, PDT_GENERIC_03, 8, ReadLv3 | WriteLv0), + new FunctionProperty(this, PID_RF_DIAG_PROBE, + [](RfMediumObject* io, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) + { + }, + [](RfMediumObject* io, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) + { + }), */ + }; + initializeProperties(sizeof(properties), properties); + } -const uint8_t* RfMediumObject::rfDomainAddress() -{ - DataProperty* prop = (DataProperty*)property(PID_RF_DOMAIN_ADDRESS); - return prop->data(); -} + const uint8_t* RfMediumObject::rfDomainAddress() + { + DataProperty* prop = (DataProperty*)property(PID_RF_DOMAIN_ADDRESS); + return prop->data(); + } -void RfMediumObject::rfDomainAddress(const uint8_t* value) -{ - Property* prop = property(PID_RF_DOMAIN_ADDRESS); - prop->write(value); -} + void RfMediumObject::rfDomainAddress(const uint8_t* value) + { + Property* prop = property(PID_RF_DOMAIN_ADDRESS); + prop->write(value); + } +} \ No newline at end of file diff --git a/src/knx/rf/rf_medium_object.h b/src/knx/rf/rf_medium_object.h index d3ef8598..9a478fba 100644 --- a/src/knx/rf/rf_medium_object.h +++ b/src/knx/rf/rf_medium_object.h @@ -2,14 +2,17 @@ #include "../interface_object/interface_object.h" -class RfMediumObject: public InterfaceObject +namespace Knx { - public: - RfMediumObject(); - const uint8_t* rfDomainAddress(); - void rfDomainAddress(const uint8_t* value); + class RfMediumObject: public InterfaceObject + { + public: + RfMediumObject(); + const uint8_t* rfDomainAddress(); + void rfDomainAddress(const uint8_t* value); - private: - uint8_t _rfDiagSourceAddressFilterTable[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; - uint8_t _rfDiagLinkBudgetTable[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; -}; + private: + uint8_t _rfDiagSourceAddressFilterTable[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; + uint8_t _rfDiagLinkBudgetTable[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; + }; +} \ No newline at end of file diff --git a/src/knx/rf/rf_physical_layer.h b/src/knx/rf/rf_physical_layer.h index 2b45b823..115d7dca 100644 --- a/src/knx/rf/rf_physical_layer.h +++ b/src/knx/rf/rf_physical_layer.h @@ -7,19 +7,22 @@ // Calculate the real packet size out of the L-field of FT3 frame data. See KNX-RF spec. 3.2.5 Data Link Layer frame format #define PACKET_SIZE(lField) ((((lField - 10 /*size of first pkt*/))/16 + 2 /*CRC in first pkt */) * 2 /*to bytes*/ +lField + 1 /*size of len byte*/) -class RfDataLinkLayer; - -class RfPhysicalLayer +namespace Knx { - public: - RfPhysicalLayer(RfDataLinkLayer& rfDataLinkLayer, Platform& platform) - : _rfDataLinkLayer(rfDataLinkLayer), _platform(platform) {} + class RfDataLinkLayer; + + class RfPhysicalLayer + { + public: + RfPhysicalLayer(RfDataLinkLayer& rfDataLinkLayer, Platform& platform) + : _rfDataLinkLayer(rfDataLinkLayer), _platform(platform) {} - virtual bool InitChip() = 0; - virtual void stopChip() = 0; - virtual void loop() = 0; + virtual bool InitChip() = 0; + virtual void stopChip() = 0; + virtual void loop() = 0; - protected: - RfDataLinkLayer& _rfDataLinkLayer; - Platform& _platform; -}; + protected: + RfDataLinkLayer& _rfDataLinkLayer; + Platform& _platform; + }; +} \ No newline at end of file diff --git a/src/knx/rf/rf_physical_layer_cc1101.cpp b/src/knx/rf/rf_physical_layer_cc1101.cpp index 2c4e069d..f31864ce 100644 --- a/src/knx/rf/rf_physical_layer_cc1101.cpp +++ b/src/knx/rf/rf_physical_layer_cc1101.cpp @@ -9,772 +9,774 @@ #include #include - -// Table for encoding 4-bit data into a 8-bit Manchester encoding. -const uint8_t RfPhysicalLayerCC1101::manchEncodeTab[16] = {0xAA, // 0x0 Manchester encoded - 0xA9, // 0x1 Manchester encoded - 0xA6, // 0x2 Manchester encoded - 0xA5, // 0x3 Manchester encoded - 0x9A, // 0x4 Manchester encoded - 0x99, // 0x5 Manchester encoded - 0x96, // 0x6 Manchester encoded - 0x95, // 0x7 Manchester encoded - 0x6A, // 0x8 Manchester encoded - 0x69, // 0x9 Manchester encoded - 0x66, // 0xA Manchester encoded - 0x65, // 0xB Manchester encoded - 0x5A, // 0xC Manchester encoded - 0x59, // 0xD Manchester encoded - 0x56, // 0xE Manchester encoded - 0x55 - }; // 0xF Manchester encoded - -// Table for decoding 4-bit Manchester encoded data into 2-bit -// data. 0xFF indicates invalid Manchester encoding -const uint8_t RfPhysicalLayerCC1101::manchDecodeTab[16] = {0xFF, // Manchester encoded 0x0 decoded - 0xFF, // Manchester encoded 0x1 decoded - 0xFF, // Manchester encoded 0x2 decoded - 0xFF, // Manchester encoded 0x3 decoded - 0xFF, // Manchester encoded 0x4 decoded - 0x03, // Manchester encoded 0x5 decoded - 0x02, // Manchester encoded 0x6 decoded - 0xFF, // Manchester encoded 0x7 decoded - 0xFF, // Manchester encoded 0x8 decoded - 0x01, // Manchester encoded 0x9 decoded - 0x00, // Manchester encoded 0xA decoded - 0xFF, // Manchester encoded 0xB decoded - 0xFF, // Manchester encoded 0xC decoded - 0xFF, // Manchester encoded 0xD decoded - 0xFF, // Manchester encoded 0xE decoded - 0xFF - };// Manchester encoded 0xF decoded - -// Product = CC1101 -// Chip version = A (VERSION = 0x04) -// Crystal accuracy = 10 ppm -// X-tal frequency = 26 MHz -// RF output power = + 10 dBm -// RX filterbandwidth = 270 kHz -// Deviation = 47 kHz -// Datarate = 32.73 kBaud -// Modulation = (0) 2-FSK -// Manchester enable = (0) Manchester disabled -// RF Frequency = 868.299866 MHz -// Channel spacing = 199.951172 kHz -// Channel number = 0 -// Optimization = - -// Sync mode = (5) 15/16 + carrier-sense above threshold -// Format of RX/TX data = (0) Normal mode, use FIFOs for RX and TX -// CRC operation = (0) CRC disabled for TX and RX -// Forward Error Correction = (0) FEC disabled -// Length configuration = (0) Fixed length packets, length configured in PKTLEN register. -// Packetlength = 255 -// Preamble count = (2) 4 bytes -// Append status = 0 -// Address check = (0) No address check -// FIFO autoflush = 0 -// Device address = 0 -// GDO0 signal selection = ( 6) Asserts when sync word has been sent / received, and de-asserts at the end of the packet -// GDO2 signal selection = ( 0) Asserts when RX FiFO threshold -const uint8_t RfPhysicalLayerCC1101::cc1101_2FSK_32_7_kb[CFG_REGISTER] = -{ - 0x00, // IOCFG2 GDO2 Output Pin Configuration - 0x2E, // IOCFG1 GDO1 Output Pin Configuration - 0x06, // IOCFG0 GDO0 Output Pin Configuration - 0x40, // FIFOTHR RX FIFO and TX FIFO Thresholds // 4 bytes in RX FIFO (2 bytes manchester encoded) - 0x76, // SYNC1 Sync Word - 0x96, // SYNC0 Sync Word - 0xFF, // PKTLEN Packet Length - 0x00, // PKTCTRL1 Packet Automation Control - 0x00, // PKTCTRL0 Packet Automation Control - 0x00, // ADDR Device Address - 0x00, // CHANNR Channel Number - 0x08, // FSCTRL1 Frequency Synthesizer Control - 0x00, // FSCTRL0 Frequency Synthesizer Control - 0x21, // FREQ2 Frequency Control Word - 0x65, // FREQ1 Frequency Control Word - 0x6A, // FREQ0 Frequency Control Word - 0x6A, // MDMCFG4 Modem Configuration - 0x4A, // MDMCFG3 Modem Configuration - 0x05, // MDMCFG2 Modem Configuration - 0x22, // MDMCFG1 Modem Configuration - 0xF8, // MDMCFG0 Modem Configuration - 0x47, // DEVIATN Modem Deviation Setting - 0x07, // MCSM2 Main Radio Control State Machine Configuration - 0x30, // MCSM1 Main Radio Control State Machine Configuration (IDLE after TX and RX) - 0x18, // MCSM0 Main Radio Control State Machine Configuration - 0x2E, // FOCCFG Frequency Offset Compensation Configuration - 0x6D, // BSCFG Bit Synchronization Configuration - 0x43, // AGCCTRL2 AGC Control 0x04, // AGCCTRL2 magn target 33dB vs 36dB (max LNA+LNA2 gain vs. ) (highest gain cannot be used vs. all gain settings) - 0x40, // AGCCTRL1 AGC Control 0x09, // AGCCTRL1 carrier sense threshold disabled vs. 7dB below magn target (LNA prio strat. 1 vs 0) - 0x91, // AGCCTRL0 AGC Control 0xB2, // AGCCTRL0 channel filter samples 16 vs.32 - 0x87, // WOREVT1 High Byte Event0 Timeout - 0x6B, // WOREVT0 Low Byte Event0 Timeout - 0xFB, // WORCTRL Wake On Radio Control - 0xB6, // FREND1 Front End RX Configuration - 0x10, // FREND0 Front End TX Configuration - 0xE9, // FSCAL3 Frequency Synthesizer Calibration 0xEA, // FSCAL3 - 0x2A, // FSCAL2 Frequency Synthesizer Calibration - 0x00, // FSCAL1 Frequency Synthesizer Calibration - 0x1F, // FSCAL0 Frequency Synthesizer Calibration - 0x41, // RCCTRL1 RC Oscillator Configuration - 0x00, // RCCTRL0 RC Oscillator Configuration - 0x59, // FSTEST Frequency Synthesizer Calibration Control - 0x7F, // PTEST Production Test - 0x3F, // AGCTEST AGC Test - 0x81, // TEST2 Various Test Settings - 0x35, // TEST1 Various Test Settings - 0x09 // TEST0 Various Test Settings -}; - -//Patable index: -30 -20- -15 -10 0 5 7 10 dBm -const uint8_t RfPhysicalLayerCC1101::paTablePower868[8] = {0x03, 0x17, 0x1D, 0x26, 0x50, 0x86, 0xCD, 0xC0}; - -RfPhysicalLayerCC1101::RfPhysicalLayerCC1101(RfDataLinkLayer& rfDataLinkLayer, Platform& platform) - : RfPhysicalLayer(rfDataLinkLayer, platform) -{ -} - -void RfPhysicalLayerCC1101::manchEncode(uint8_t* uncodedData, uint8_t* encodedData) +namespace Knx { - uint8_t data0, data1; - - // - Shift to get 4-bit data values - data1 = (((*uncodedData) >> 4) & 0x0F); - data0 = ((*uncodedData) & 0x0F); - // - Perform Manchester encoding - - *encodedData = (manchEncodeTab[data1]); - *(encodedData + 1) = manchEncodeTab[data0]; -} + // Table for encoding 4-bit data into a 8-bit Manchester encoding. + const uint8_t RfPhysicalLayerCC1101::manchEncodeTab[16] = {0xAA, // 0x0 Manchester encoded + 0xA9, // 0x1 Manchester encoded + 0xA6, // 0x2 Manchester encoded + 0xA5, // 0x3 Manchester encoded + 0x9A, // 0x4 Manchester encoded + 0x99, // 0x5 Manchester encoded + 0x96, // 0x6 Manchester encoded + 0x95, // 0x7 Manchester encoded + 0x6A, // 0x8 Manchester encoded + 0x69, // 0x9 Manchester encoded + 0x66, // 0xA Manchester encoded + 0x65, // 0xB Manchester encoded + 0x5A, // 0xC Manchester encoded + 0x59, // 0xD Manchester encoded + 0x56, // 0xE Manchester encoded + 0x55 + }; // 0xF Manchester encoded + + // Table for decoding 4-bit Manchester encoded data into 2-bit + // data. 0xFF indicates invalid Manchester encoding + const uint8_t RfPhysicalLayerCC1101::manchDecodeTab[16] = {0xFF, // Manchester encoded 0x0 decoded + 0xFF, // Manchester encoded 0x1 decoded + 0xFF, // Manchester encoded 0x2 decoded + 0xFF, // Manchester encoded 0x3 decoded + 0xFF, // Manchester encoded 0x4 decoded + 0x03, // Manchester encoded 0x5 decoded + 0x02, // Manchester encoded 0x6 decoded + 0xFF, // Manchester encoded 0x7 decoded + 0xFF, // Manchester encoded 0x8 decoded + 0x01, // Manchester encoded 0x9 decoded + 0x00, // Manchester encoded 0xA decoded + 0xFF, // Manchester encoded 0xB decoded + 0xFF, // Manchester encoded 0xC decoded + 0xFF, // Manchester encoded 0xD decoded + 0xFF, // Manchester encoded 0xE decoded + 0xFF + };// Manchester encoded 0xF decoded + + // Product = CC1101 + // Chip version = A (VERSION = 0x04) + // Crystal accuracy = 10 ppm + // X-tal frequency = 26 MHz + // RF output power = + 10 dBm + // RX filterbandwidth = 270 kHz + // Deviation = 47 kHz + // Datarate = 32.73 kBaud + // Modulation = (0) 2-FSK + // Manchester enable = (0) Manchester disabled + // RF Frequency = 868.299866 MHz + // Channel spacing = 199.951172 kHz + // Channel number = 0 + // Optimization = - + // Sync mode = (5) 15/16 + carrier-sense above threshold + // Format of RX/TX data = (0) Normal mode, use FIFOs for RX and TX + // CRC operation = (0) CRC disabled for TX and RX + // Forward Error Correction = (0) FEC disabled + // Length configuration = (0) Fixed length packets, length configured in PKTLEN register. + // Packetlength = 255 + // Preamble count = (2) 4 bytes + // Append status = 0 + // Address check = (0) No address check + // FIFO autoflush = 0 + // Device address = 0 + // GDO0 signal selection = ( 6) Asserts when sync word has been sent / received, and de-asserts at the end of the packet + // GDO2 signal selection = ( 0) Asserts when RX FiFO threshold + const uint8_t RfPhysicalLayerCC1101::cc1101_2FSK_32_7_kb[CFG_REGISTER] = + { + 0x00, // IOCFG2 GDO2 Output Pin Configuration + 0x2E, // IOCFG1 GDO1 Output Pin Configuration + 0x06, // IOCFG0 GDO0 Output Pin Configuration + 0x40, // FIFOTHR RX FIFO and TX FIFO Thresholds // 4 bytes in RX FIFO (2 bytes manchester encoded) + 0x76, // SYNC1 Sync Word + 0x96, // SYNC0 Sync Word + 0xFF, // PKTLEN Packet Length + 0x00, // PKTCTRL1 Packet Automation Control + 0x00, // PKTCTRL0 Packet Automation Control + 0x00, // ADDR Device Address + 0x00, // CHANNR Channel Number + 0x08, // FSCTRL1 Frequency Synthesizer Control + 0x00, // FSCTRL0 Frequency Synthesizer Control + 0x21, // FREQ2 Frequency Control Word + 0x65, // FREQ1 Frequency Control Word + 0x6A, // FREQ0 Frequency Control Word + 0x6A, // MDMCFG4 Modem Configuration + 0x4A, // MDMCFG3 Modem Configuration + 0x05, // MDMCFG2 Modem Configuration + 0x22, // MDMCFG1 Modem Configuration + 0xF8, // MDMCFG0 Modem Configuration + 0x47, // DEVIATN Modem Deviation Setting + 0x07, // MCSM2 Main Radio Control State Machine Configuration + 0x30, // MCSM1 Main Radio Control State Machine Configuration (IDLE after TX and RX) + 0x18, // MCSM0 Main Radio Control State Machine Configuration + 0x2E, // FOCCFG Frequency Offset Compensation Configuration + 0x6D, // BSCFG Bit Synchronization Configuration + 0x43, // AGCCTRL2 AGC Control 0x04, // AGCCTRL2 magn target 33dB vs 36dB (max LNA+LNA2 gain vs. ) (highest gain cannot be used vs. all gain settings) + 0x40, // AGCCTRL1 AGC Control 0x09, // AGCCTRL1 carrier sense threshold disabled vs. 7dB below magn target (LNA prio strat. 1 vs 0) + 0x91, // AGCCTRL0 AGC Control 0xB2, // AGCCTRL0 channel filter samples 16 vs.32 + 0x87, // WOREVT1 High Byte Event0 Timeout + 0x6B, // WOREVT0 Low Byte Event0 Timeout + 0xFB, // WORCTRL Wake On Radio Control + 0xB6, // FREND1 Front End RX Configuration + 0x10, // FREND0 Front End TX Configuration + 0xE9, // FSCAL3 Frequency Synthesizer Calibration 0xEA, // FSCAL3 + 0x2A, // FSCAL2 Frequency Synthesizer Calibration + 0x00, // FSCAL1 Frequency Synthesizer Calibration + 0x1F, // FSCAL0 Frequency Synthesizer Calibration + 0x41, // RCCTRL1 RC Oscillator Configuration + 0x00, // RCCTRL0 RC Oscillator Configuration + 0x59, // FSTEST Frequency Synthesizer Calibration Control + 0x7F, // PTEST Production Test + 0x3F, // AGCTEST AGC Test + 0x81, // TEST2 Various Test Settings + 0x35, // TEST1 Various Test Settings + 0x09 // TEST0 Various Test Settings + }; + + //Patable index: -30 -20- -15 -10 0 5 7 10 dBm + const uint8_t RfPhysicalLayerCC1101::paTablePower868[8] = {0x03, 0x17, 0x1D, 0x26, 0x50, 0x86, 0xCD, 0xC0}; + + RfPhysicalLayerCC1101::RfPhysicalLayerCC1101(RfDataLinkLayer& rfDataLinkLayer, Platform& platform) + : RfPhysicalLayer(rfDataLinkLayer, platform) + { + } -bool RfPhysicalLayerCC1101::manchDecode(uint8_t* encodedData, uint8_t* decodedData) -{ - uint8_t data0, data1, data2, data3; + void RfPhysicalLayerCC1101::manchEncode(uint8_t* uncodedData, uint8_t* encodedData) + { + uint8_t data0, data1; - // - Shift to get 4 bit data and decode - data3 = ((*encodedData >> 4) & 0x0F); - data2 = ( *encodedData & 0x0F); - data1 = ((*(encodedData + 1) >> 4) & 0x0F); - data0 = ((*(encodedData + 1)) & 0x0F); + // - Shift to get 4-bit data values + data1 = (((*uncodedData) >> 4) & 0x0F); + data0 = ((*uncodedData) & 0x0F); - // Check for invalid Manchester encoding - if ( (manchDecodeTab[data3] == 0xFF ) | (manchDecodeTab[data2] == 0xFF ) | - (manchDecodeTab[data1] == 0xFF ) | (manchDecodeTab[data0] == 0xFF ) ) - { - return false; + // - Perform Manchester encoding - + *encodedData = (manchEncodeTab[data1]); + *(encodedData + 1) = manchEncodeTab[data0]; } - // Shift result into a byte - *decodedData = (manchDecodeTab[data3] << 6) | (manchDecodeTab[data2] << 4) | - (manchDecodeTab[data1] << 2) | manchDecodeTab[data0]; + bool RfPhysicalLayerCC1101::manchDecode(uint8_t* encodedData, uint8_t* decodedData) + { + uint8_t data0, data1, data2, data3; - return true; -} + // - Shift to get 4 bit data and decode + data3 = ((*encodedData >> 4) & 0x0F); + data2 = ( *encodedData & 0x0F); + data1 = ((*(encodedData + 1) >> 4) & 0x0F); + data0 = ((*(encodedData + 1)) & 0x0F); -uint8_t RfPhysicalLayerCC1101::sIdle() -{ - uint8_t marcState; - uint32_t timeStart; + // Check for invalid Manchester encoding + if ( (manchDecodeTab[data3] == 0xFF ) | (manchDecodeTab[data2] == 0xFF ) | + (manchDecodeTab[data1] == 0xFF ) | (manchDecodeTab[data0] == 0xFF ) ) + { + return false; + } - spiWriteStrobe(SIDLE); //sets to idle first. must be in + // Shift result into a byte + *decodedData = (manchDecodeTab[data3] << 6) | (manchDecodeTab[data2] << 4) | + (manchDecodeTab[data1] << 2) | manchDecodeTab[data0]; - marcState = 0xFF; //set unknown/dummy state value - timeStart = millis(); + return true; + } - while ((marcState != MARCSTATE_IDLE) && ((millis() - timeStart) < CC1101_TIMEOUT)) //0x01 = sidle + uint8_t RfPhysicalLayerCC1101::sIdle() { - marcState = (spiReadRegister(MARCSTATE) & MARCSTATE_BITMASK); //read out state of cc1101 to be sure in RX - } + uint8_t marcState; + uint32_t timeStart; - //print("marcstate: 0x"); - //println(marcState, HEX); + spiWriteStrobe(SIDLE); //sets to idle first. must be in - if (marcState != MARCSTATE_IDLE) - { - println("Timeout when trying to set idle state."); - return false; - } + marcState = 0xFF; //set unknown/dummy state value + timeStart = millis(); - return true; -} + while ((marcState != MARCSTATE_IDLE) && ((millis() - timeStart) < CC1101_TIMEOUT)) //0x01 = sidle + { + marcState = (spiReadRegister(MARCSTATE) & MARCSTATE_BITMASK); //read out state of cc1101 to be sure in RX + } -uint8_t RfPhysicalLayerCC1101::sReceive() -{ - uint8_t marcState; - uint32_t timeStart; + //print("marcstate: 0x"); + //println(marcState, HEX); - spiWriteStrobe(SRX); //writes receive strobe (receive mode) + if (marcState != MARCSTATE_IDLE) + { + println("Timeout when trying to set idle state."); + return false; + } - marcState = 0xFF; //set unknown/dummy state value - timeStart = millis(); + return true; + } - while ((marcState != MARCSTATE_RX) && ((millis() - timeStart) < CC1101_TIMEOUT)) //0x0D = RX + uint8_t RfPhysicalLayerCC1101::sReceive() { - marcState = (spiReadRegister(MARCSTATE) & MARCSTATE_BITMASK); //read out state of cc1101 to be sure in RX - } + uint8_t marcState; + uint32_t timeStart; - //print("marcstate: 0x"); - //println(marcState, HEX); + spiWriteStrobe(SRX); //writes receive strobe (receive mode) - if (marcState != MARCSTATE_RX) - { - println("Timeout when trying to set receive state."); - return false; - } + marcState = 0xFF; //set unknown/dummy state value + timeStart = millis(); - return true; -} + while ((marcState != MARCSTATE_RX) && ((millis() - timeStart) < CC1101_TIMEOUT)) //0x0D = RX + { + marcState = (spiReadRegister(MARCSTATE) & MARCSTATE_BITMASK); //read out state of cc1101 to be sure in RX + } -void RfPhysicalLayerCC1101::spiWriteRegister(uint8_t spi_instr, uint8_t value) -{ - uint8_t tbuf[2] = {0}; - tbuf[0] = spi_instr | WRITE_SINGLE_BYTE; - tbuf[1] = value; - uint8_t len = 2; - digitalWrite(SPI_SS_PIN, LOW); - _platform.readWriteSpi(tbuf, len); - digitalWrite(SPI_SS_PIN, HIGH); -} + //print("marcstate: 0x"); + //println(marcState, HEX); -uint8_t RfPhysicalLayerCC1101::spiReadRegister(uint8_t spi_instr) -{ - uint8_t value; - uint8_t rbuf[2] = {0}; - rbuf[0] = spi_instr | READ_SINGLE_BYTE; - uint8_t len = 2; - digitalWrite(SPI_SS_PIN, LOW); - _platform.readWriteSpi(rbuf, len); - digitalWrite(SPI_SS_PIN, HIGH); - value = rbuf[1]; - //printf("SPI_arr_0: 0x%02X\n", rbuf[0]); - //printf("SPI_arr_1: 0x%02X\n", rbuf[1]); - return value; -} + if (marcState != MARCSTATE_RX) + { + println("Timeout when trying to set receive state."); + return false; + } -uint8_t RfPhysicalLayerCC1101::spiWriteStrobe(uint8_t spi_instr) -{ - uint8_t tbuf[1] = {0}; - tbuf[0] = spi_instr; - //printf("SPI_data: 0x%02X\n", tbuf[0]); - digitalWrite(SPI_SS_PIN, LOW); - _platform.readWriteSpi(tbuf, 1); - digitalWrite(SPI_SS_PIN, HIGH); - return tbuf[0]; -} + return true; + } -void RfPhysicalLayerCC1101::spiReadBurst(uint8_t spi_instr, uint8_t* pArr, uint8_t len) -{ - uint8_t rbuf[len + 1]; - rbuf[0] = spi_instr | READ_BURST; - digitalWrite(SPI_SS_PIN, LOW); - _platform.readWriteSpi(rbuf, len + 1); - digitalWrite(SPI_SS_PIN, HIGH); + void RfPhysicalLayerCC1101::spiWriteRegister(uint8_t spi_instr, uint8_t value) + { + uint8_t tbuf[2] = {0}; + tbuf[0] = spi_instr | WRITE_SINGLE_BYTE; + tbuf[1] = value; + uint8_t len = 2; + digitalWrite(SPI_SS_PIN, LOW); + _platform.readWriteSpi(tbuf, len); + digitalWrite(SPI_SS_PIN, HIGH); + } - for (uint8_t i = 0; i < len ; i++ ) + uint8_t RfPhysicalLayerCC1101::spiReadRegister(uint8_t spi_instr) { - pArr[i] = rbuf[i + 1]; - //printf("SPI_arr_read: 0x%02X\n", pArr[i]); + uint8_t value; + uint8_t rbuf[2] = {0}; + rbuf[0] = spi_instr | READ_SINGLE_BYTE; + uint8_t len = 2; + digitalWrite(SPI_SS_PIN, LOW); + _platform.readWriteSpi(rbuf, len); + digitalWrite(SPI_SS_PIN, HIGH); + value = rbuf[1]; + //printf("SPI_arr_0: 0x%02X\n", rbuf[0]); + //printf("SPI_arr_1: 0x%02X\n", rbuf[1]); + return value; } -} -void RfPhysicalLayerCC1101::spiWriteBurst(uint8_t spi_instr, const uint8_t* pArr, uint8_t len) -{ - uint8_t tbuf[len + 1]; - tbuf[0] = spi_instr | WRITE_BURST; + uint8_t RfPhysicalLayerCC1101::spiWriteStrobe(uint8_t spi_instr) + { + uint8_t tbuf[1] = {0}; + tbuf[0] = spi_instr; + //printf("SPI_data: 0x%02X\n", tbuf[0]); + digitalWrite(SPI_SS_PIN, LOW); + _platform.readWriteSpi(tbuf, 1); + digitalWrite(SPI_SS_PIN, HIGH); + return tbuf[0]; + } - for (uint8_t i = 0; i < len ; i++ ) + void RfPhysicalLayerCC1101::spiReadBurst(uint8_t spi_instr, uint8_t* pArr, uint8_t len) { - tbuf[i + 1] = pArr[i]; - //printf("SPI_arr_write: 0x%02X\n", tbuf[i+1]); + uint8_t rbuf[len + 1]; + rbuf[0] = spi_instr | READ_BURST; + digitalWrite(SPI_SS_PIN, LOW); + _platform.readWriteSpi(rbuf, len + 1); + digitalWrite(SPI_SS_PIN, HIGH); + + for (uint8_t i = 0; i < len ; i++ ) + { + pArr[i] = rbuf[i + 1]; + //printf("SPI_arr_read: 0x%02X\n", pArr[i]); + } } - digitalWrite(SPI_SS_PIN, LOW); - _platform.readWriteSpi(tbuf, len + 1); - digitalWrite(SPI_SS_PIN, HIGH); -} + void RfPhysicalLayerCC1101::spiWriteBurst(uint8_t spi_instr, const uint8_t* pArr, uint8_t len) + { + uint8_t tbuf[len + 1]; + tbuf[0] = spi_instr | WRITE_BURST; -void RfPhysicalLayerCC1101::powerDownCC1101() -{ - // Set IDLE state first - sIdle(); - delayMicroseconds(100); - // CC1101 Power Down - spiWriteStrobe(SPWD); -} + for (uint8_t i = 0; i < len ; i++ ) + { + tbuf[i + 1] = pArr[i]; + //printf("SPI_arr_write: 0x%02X\n", tbuf[i+1]); + } -void RfPhysicalLayerCC1101::setOutputPowerLevel(int8_t dBm) -{ - uint8_t pa = 0xC0; - - if (dBm <= -30) - pa = 0x00; - else if (dBm <= -20) - pa = 0x01; - else if (dBm <= -15) - pa = 0x02; - else if (dBm <= -10) - pa = 0x03; - else if (dBm <= 0) - pa = 0x04; - else if (dBm <= 5) - pa = 0x05; - else if (dBm <= 7) - pa = 0x06; - else if (dBm <= 10) - pa = 0x07; - - spiWriteRegister(FREND0, pa); -} + digitalWrite(SPI_SS_PIN, LOW); + _platform.readWriteSpi(tbuf, len + 1); + digitalWrite(SPI_SS_PIN, HIGH); + } -bool RfPhysicalLayerCC1101::InitChip() -{ - // Setup SPI and GPIOs - _platform.setupSpi(); - pinMode(GPIO_GDO2_PIN, INPUT); - pinMode(GPIO_GDO0_PIN, INPUT); - pinMode(SPI_SS_PIN, OUTPUT); - - // Toggle chip select signal as described in CC11xx manual - digitalWrite(SPI_SS_PIN, HIGH); - delayMicroseconds(30); - digitalWrite(SPI_SS_PIN, LOW); - delayMicroseconds(30); - digitalWrite(SPI_SS_PIN, HIGH); - delayMicroseconds(45); - - // Send SRES command - digitalWrite(SPI_SS_PIN, LOW); - delay(10); // Normally we would have to poll MISO here: while(_platform.readGpio(SPI_MISO_PIN)); - spiWriteStrobe(SRES); - // Wait for chip to finish internal reset - delay(10); // Normally we would have to poll MISO here: while(_platform.readGpio(SPI_MISO_PIN)); - digitalWrite(SPI_SS_PIN, HIGH); - - // Flush the FIFOs - spiWriteStrobe(SFTX); - delayMicroseconds(100); - spiWriteStrobe(SFRX); - delayMicroseconds(100); - - uint8_t partnum = spiReadRegister(PARTNUM); //reads CC1101 partnumber; - uint8_t version = spiReadRegister(VERSION); //reads CC1101 version number; - - // Checks if valid chip ID is found. Usually 0x03 or 0x14. if not -> abort - if (version == 0x00 || version == 0xFF) + void RfPhysicalLayerCC1101::powerDownCC1101() { - println("No CC11xx found!"); - stopChip(); - return false; + // Set IDLE state first + sIdle(); + delayMicroseconds(100); + // CC1101 Power Down + spiWriteStrobe(SPWD); } - print("Partnumber: 0x"); - println(partnum, HEX); - print("Version : 0x"); - println(version, HEX); + void RfPhysicalLayerCC1101::setOutputPowerLevel(int8_t dBm) + { + uint8_t pa = 0xC0; + + if (dBm <= -30) + pa = 0x00; + else if (dBm <= -20) + pa = 0x01; + else if (dBm <= -15) + pa = 0x02; + else if (dBm <= -10) + pa = 0x03; + else if (dBm <= 0) + pa = 0x04; + else if (dBm <= 5) + pa = 0x05; + else if (dBm <= 7) + pa = 0x06; + else if (dBm <= 10) + pa = 0x07; + + spiWriteRegister(FREND0, pa); + } - // Set modulation mode 2FSK, 32768kbit/s - spiWriteBurst(WRITE_BURST, cc1101_2FSK_32_7_kb, CFG_REGISTER); + bool RfPhysicalLayerCC1101::InitChip() + { + // Setup SPI and GPIOs + _platform.setupSpi(); + pinMode(GPIO_GDO2_PIN, INPUT); + pinMode(GPIO_GDO0_PIN, INPUT); + pinMode(SPI_SS_PIN, OUTPUT); + + // Toggle chip select signal as described in CC11xx manual + digitalWrite(SPI_SS_PIN, HIGH); + delayMicroseconds(30); + digitalWrite(SPI_SS_PIN, LOW); + delayMicroseconds(30); + digitalWrite(SPI_SS_PIN, HIGH); + delayMicroseconds(45); + + // Send SRES command + digitalWrite(SPI_SS_PIN, LOW); + delay(10); // Normally we would have to poll MISO here: while(_platform.readGpio(SPI_MISO_PIN)); + spiWriteStrobe(SRES); + // Wait for chip to finish internal reset + delay(10); // Normally we would have to poll MISO here: while(_platform.readGpio(SPI_MISO_PIN)); + digitalWrite(SPI_SS_PIN, HIGH); + + // Flush the FIFOs + spiWriteStrobe(SFTX); + delayMicroseconds(100); + spiWriteStrobe(SFRX); + delayMicroseconds(100); + + uint8_t partnum = spiReadRegister(PARTNUM); //reads CC1101 partnumber; + uint8_t version = spiReadRegister(VERSION); //reads CC1101 version number; + + // Checks if valid chip ID is found. Usually 0x03 or 0x14. if not -> abort + if (version == 0x00 || version == 0xFF) + { + println("No CC11xx found!"); + stopChip(); + return false; + } - // Set PA table - spiWriteBurst(PATABLE_BURST, paTablePower868, 8); + print("Partnumber: 0x"); + println(partnum, HEX); + print("Version : 0x"); + println(version, HEX); - // Set ISM band to 868.3MHz - spiWriteRegister(FREQ2, 0x21); - spiWriteRegister(FREQ1, 0x65); - spiWriteRegister(FREQ0, 0x6A); + // Set modulation mode 2FSK, 32768kbit/s + spiWriteBurst(WRITE_BURST, cc1101_2FSK_32_7_kb, CFG_REGISTER); - // Set channel 0 in ISM band - spiWriteRegister(CHANNR, 0); + // Set PA table + spiWriteBurst(PATABLE_BURST, paTablePower868, 8); - // Set PA to 0dBm as default - setOutputPowerLevel(0); + // Set ISM band to 868.3MHz + spiWriteRegister(FREQ2, 0x21); + spiWriteRegister(FREQ1, 0x65); + spiWriteRegister(FREQ0, 0x6A); - return true; -} + // Set channel 0 in ISM band + spiWriteRegister(CHANNR, 0); -void RfPhysicalLayerCC1101::stopChip() -{ - powerDownCC1101(); + // Set PA to 0dBm as default + setOutputPowerLevel(0); - _platform.closeSpi(); -} + return true; + } -void RfPhysicalLayerCC1101::showRegisterSettings() -{ - uint8_t config_reg_verify[CFG_REGISTER]; - uint8_t Patable_verify[CFG_REGISTER]; + void RfPhysicalLayerCC1101::stopChip() + { + powerDownCC1101(); - spiReadBurst(READ_BURST, config_reg_verify, CFG_REGISTER); //reads all 47 config register from cc1101 - spiReadBurst(PATABLE_BURST, Patable_verify, 8); //reads output power settings from cc1101 + _platform.closeSpi(); + } - println("Config Register:"); - printHex("", config_reg_verify, CFG_REGISTER); + void RfPhysicalLayerCC1101::showRegisterSettings() + { + uint8_t config_reg_verify[CFG_REGISTER]; + uint8_t Patable_verify[CFG_REGISTER]; - println("PaTable:"); - printHex("", Patable_verify, 8); -} + spiReadBurst(READ_BURST, config_reg_verify, CFG_REGISTER); //reads all 47 config register from cc1101 + spiReadBurst(PATABLE_BURST, Patable_verify, 8); //reads output power settings from cc1101 -void RfPhysicalLayerCC1101::loop() -{ - switch (_loopState) + println("Config Register:"); + printHex("", config_reg_verify, CFG_REGISTER); + + println("PaTable:"); + printHex("", Patable_verify, 8); + } + + void RfPhysicalLayerCC1101::loop() { - case TX_START: + switch (_loopState) { - prevStatusGDO0 = 0; - prevStatusGDO2 = 0; - // Set sync word in TX mode - // The same sync word is used in RX mode, but we use it in different way here: - // Important: the TX FIFO must provide the last byte of the - // sync word - spiWriteRegister(SYNC1, 0x54); - spiWriteRegister(SYNC0, 0x76); - // Set TX FIFO threshold to 33 bytes - spiWriteRegister(FIFOTHR, 0x47); - // Set GDO2 to be TX FIFO threshold signal - spiWriteRegister(IOCFG2, 0x02); - // Set GDO0 to be packet transmitted signal - spiWriteRegister(IOCFG0, 0x06); - // Flush TX FIFO - spiWriteStrobe(SFTX); - - _rfDataLinkLayer.loadNextTxFrame(&sendBuffer, &sendBufferLength); - - // Calculate total number of bytes in the KNX RF packet from L-field - pktLen = PACKET_SIZE(sendBuffer[0]); - - // Check for valid length - if ((pktLen == 0) || (pktLen > 290)) + case TX_START: { - println("TX packet length error!"); - break; - } + prevStatusGDO0 = 0; + prevStatusGDO2 = 0; + // Set sync word in TX mode + // The same sync word is used in RX mode, but we use it in different way here: + // Important: the TX FIFO must provide the last byte of the + // sync word + spiWriteRegister(SYNC1, 0x54); + spiWriteRegister(SYNC0, 0x76); + // Set TX FIFO threshold to 33 bytes + spiWriteRegister(FIFOTHR, 0x47); + // Set GDO2 to be TX FIFO threshold signal + spiWriteRegister(IOCFG2, 0x02); + // Set GDO0 to be packet transmitted signal + spiWriteRegister(IOCFG0, 0x06); + // Flush TX FIFO + spiWriteStrobe(SFTX); + + _rfDataLinkLayer.loadNextTxFrame(&sendBuffer, &sendBufferLength); + + // Calculate total number of bytes in the KNX RF packet from L-field + pktLen = PACKET_SIZE(sendBuffer[0]); + + // Check for valid length + if ((pktLen == 0) || (pktLen > 290)) + { + println("TX packet length error!"); + break; + } - // Manchester encoded data takes twice the space plus - // 1 byte for postamble and 1 byte (LSB) of the synchronization word - bytesLeft = (2 * pktLen) + 2; - // Last byte of synchronization word - buffer[0] = 0x96; + // Manchester encoded data takes twice the space plus + // 1 byte for postamble and 1 byte (LSB) of the synchronization word + bytesLeft = (2 * pktLen) + 2; + // Last byte of synchronization word + buffer[0] = 0x96; - // Manchester encode packet - for (int i = 0; i < pktLen; i++) - { - manchEncode(&sendBuffer[i], &buffer[1 + i * 2]); - } + // Manchester encode packet + for (int i = 0; i < pktLen; i++) + { + manchEncode(&sendBuffer[i], &buffer[1 + i * 2]); + } - // Append the postamble sequence - buffer[1 + bytesLeft - 1] = 0x55; + // Append the postamble sequence + buffer[1 + bytesLeft - 1] = 0x55; - // Fill TX FIFO - pByteIndex = &buffer[0]; + // Fill TX FIFO + pByteIndex = &buffer[0]; - // Set fixed packet length mode if less than 256 bytes to transmit - if (bytesLeft < 256) - { - spiWriteRegister(PKTLEN, bytesLeft); - spiWriteRegister(PKTCTRL0, 0x00); // Set fixed pktlen mode - fixedLengthMode = true; - } - else // Else set infinite length mode - { - uint8_t fixedLength = bytesLeft % 256; - spiWriteRegister(PKTLEN, fixedLength); - spiWriteRegister(PKTCTRL0, 0x02); - fixedLengthMode = false; - } - - uint8_t bytesToWrite = MIN(64, bytesLeft); - spiWriteBurst(TXFIFO_BURST, pByteIndex, bytesToWrite); - pByteIndex += bytesToWrite; - bytesLeft -= bytesToWrite; - - // Enable transmission of packet - spiWriteStrobe(STX); + // Set fixed packet length mode if less than 256 bytes to transmit + if (bytesLeft < 256) + { + spiWriteRegister(PKTLEN, bytesLeft); + spiWriteRegister(PKTCTRL0, 0x00); // Set fixed pktlen mode + fixedLengthMode = true; + } + else // Else set infinite length mode + { + uint8_t fixedLength = bytesLeft % 256; + spiWriteRegister(PKTLEN, fixedLength); + spiWriteRegister(PKTCTRL0, 0x02); + fixedLengthMode = false; + } - _loopState = TX_ACTIVE; - } + uint8_t bytesToWrite = MIN(64, bytesLeft); + spiWriteBurst(TXFIFO_BURST, pByteIndex, bytesToWrite); + pByteIndex += bytesToWrite; + bytesLeft -= bytesToWrite; - // Fall through + // Enable transmission of packet + spiWriteStrobe(STX); - case TX_ACTIVE: - { - // Check if we have an incomplete packet transmission - if (syncStart && (millis() - packetStartTime > TX_PACKET_TIMEOUT)) - { - println("TX packet timeout!"); - // Set transceiver to IDLE (no RX or TX) - sIdle(); - _loopState = TX_END; - break; + _loopState = TX_ACTIVE; } - // Detect falling edge 1->0 on GDO2 - statusGDO2 = digitalRead(GPIO_GDO2_PIN); + // Fall through - if (prevStatusGDO2 != statusGDO2) + case TX_ACTIVE: { - prevStatusGDO2 = statusGDO2; - - // Check if signal GDO2 is de-asserted (TX FIFO is below threshold of 33 bytes, i.e. TX FIFO is half full) - if (statusGDO2 == 0) + // Check if we have an incomplete packet transmission + if (syncStart && (millis() - packetStartTime > TX_PACKET_TIMEOUT)) { - // - TX FIFO half full detected (< 33 bytes) - // Write data fragment to TX FIFO - uint8_t bytesToWrite = MIN(64, bytesLeft); - spiWriteBurst(TXFIFO_BURST, pByteIndex, bytesToWrite); - pByteIndex += bytesToWrite; - bytesLeft -= bytesToWrite; - - // Set fixed length mode if less than 256 left to transmit - if ( (bytesLeft < (256 - 64)) && !fixedLengthMode ) - { - spiWriteRegister(PKTCTRL0, 0x00); // Set fixed pktlen mode - fixedLengthMode = true; - } + println("TX packet timeout!"); + // Set transceiver to IDLE (no RX or TX) + sIdle(); + _loopState = TX_END; + break; } - } - // Detect falling edge 1->0 on GDO0 - statusGDO0 = digitalRead(GPIO_GDO0_PIN); + // Detect falling edge 1->0 on GDO2 + statusGDO2 = digitalRead(GPIO_GDO2_PIN); - if (prevStatusGDO0 != statusGDO0) - { - prevStatusGDO0 = statusGDO0; - - // If GDO0 is de-asserted: TX packet complete or TX FIFO underflow - if (statusGDO0 == 0x00) + if (prevStatusGDO2 != statusGDO2) { - // There might be an TX FIFO underflow - uint8_t chipStatusBytes = spiWriteStrobe(SNOP); + prevStatusGDO2 = statusGDO2; - if ((chipStatusBytes & CHIPSTATUS_STATE_BITMASK) == CHIPSTATUS_STATE_TX_UNDERFLOW) + // Check if signal GDO2 is de-asserted (TX FIFO is below threshold of 33 bytes, i.e. TX FIFO is half full) + if (statusGDO2 == 0) { - println("TX FIFO underflow!"); - // Set transceiver to IDLE (no RX or TX) - sIdle(); + // - TX FIFO half full detected (< 33 bytes) + // Write data fragment to TX FIFO + uint8_t bytesToWrite = MIN(64, bytesLeft); + spiWriteBurst(TXFIFO_BURST, pByteIndex, bytesToWrite); + pByteIndex += bytesToWrite; + bytesLeft -= bytesToWrite; + + // Set fixed length mode if less than 256 left to transmit + if ( (bytesLeft < (256 - 64)) && !fixedLengthMode ) + { + spiWriteRegister(PKTCTRL0, 0x00); // Set fixed pktlen mode + fixedLengthMode = true; + } } - - _loopState = TX_END; } - else + + // Detect falling edge 1->0 on GDO0 + statusGDO0 = digitalRead(GPIO_GDO0_PIN); + + if (prevStatusGDO0 != statusGDO0) { - // GDO0 asserted because sync word was transmitted - //println("TX Syncword!"); - // wait for TX_PACKET_TIMEOUT milliseconds - // Complete packet must have been transmitted within this time - packetStartTime = millis(); - syncStart = true; - } - } - } - break; + prevStatusGDO0 = statusGDO0; - case TX_END: - { - // free buffer - delete sendBuffer; - // Go back to RX after TX - _loopState = RX_START; - } - break; + // If GDO0 is de-asserted: TX packet complete or TX FIFO underflow + if (statusGDO0 == 0x00) + { + // There might be an TX FIFO underflow + uint8_t chipStatusBytes = spiWriteStrobe(SNOP); - case RX_START: - { - prevStatusGDO2 = 0; - prevStatusGDO0 = 0; - syncStart = false; - packetStart = true; - fixedLengthMode = false; - pByteIndex = buffer; - bytesLeft = 0; - pktLen = 0; - // Set sync word in RX mode - // The same sync word is used in TX mode, but we use it in different way - spiWriteRegister(SYNC1, 0x76); - spiWriteRegister(SYNC0, 0x96); - // Set GDO2 to be RX FIFO threshold signal - spiWriteRegister(IOCFG2, 0x00); - // Set GDO0 to be packet received signal - spiWriteRegister(IOCFG0, 0x06); - // Set RX FIFO threshold to 4 bytes - spiWriteRegister(FIFOTHR, 0x40); - // Set infinite pktlen mode - spiWriteRegister(PKTCTRL0, 0x02); - // Flush RX FIFO - spiWriteStrobe(SFRX); - // Start RX - sReceive(); - _loopState = RX_ACTIVE; - } - break; + if ((chipStatusBytes & CHIPSTATUS_STATE_BITMASK) == CHIPSTATUS_STATE_TX_UNDERFLOW) + { + println("TX FIFO underflow!"); + // Set transceiver to IDLE (no RX or TX) + sIdle(); + } - case RX_ACTIVE: - { - if (!_rfDataLinkLayer.isTxQueueEmpty() && !syncStart) - { - sIdle(); - _loopState = TX_START; - break; + _loopState = TX_END; + } + else + { + // GDO0 asserted because sync word was transmitted + //println("TX Syncword!"); + // wait for TX_PACKET_TIMEOUT milliseconds + // Complete packet must have been transmitted within this time + packetStartTime = millis(); + syncStart = true; + } + } } + break; - // Check if we have an incomplete packet reception - // This is related to CC1101 errata "Radio stays in RX state instead of entering RXFIFO_OVERFLOW state" - if (syncStart && (millis() - packetStartTime > RX_PACKET_TIMEOUT)) + case TX_END: { - println("RX packet timeout!"); - //uint8_t marcState = (spiReadRegister(MARCSTATE) & MARCSTATE_BITMASK); //read out state of cc1101 to be sure in RX - //print("marcstate: 0x"); - //println(marcState, HEX); - sIdle(); + // free buffer + delete sendBuffer; + // Go back to RX after TX _loopState = RX_START; - break; } + break; - // Detect rising edge 0->1 on GDO2 - statusGDO2 = digitalRead(GPIO_GDO2_PIN); - - if (prevStatusGDO2 != statusGDO2) + case RX_START: { - prevStatusGDO2 = statusGDO2; + prevStatusGDO2 = 0; + prevStatusGDO0 = 0; + syncStart = false; + packetStart = true; + fixedLengthMode = false; + pByteIndex = buffer; + bytesLeft = 0; + pktLen = 0; + // Set sync word in RX mode + // The same sync word is used in TX mode, but we use it in different way + spiWriteRegister(SYNC1, 0x76); + spiWriteRegister(SYNC0, 0x96); + // Set GDO2 to be RX FIFO threshold signal + spiWriteRegister(IOCFG2, 0x00); + // Set GDO0 to be packet received signal + spiWriteRegister(IOCFG0, 0x06); + // Set RX FIFO threshold to 4 bytes + spiWriteRegister(FIFOTHR, 0x40); + // Set infinite pktlen mode + spiWriteRegister(PKTCTRL0, 0x02); + // Flush RX FIFO + spiWriteStrobe(SFRX); + // Start RX + sReceive(); + _loopState = RX_ACTIVE; + } + break; - // Check if signal GDO2 is asserted (RX FIFO is equal to or above threshold of 4 bytes) - if (statusGDO2 == 1) + case RX_ACTIVE: + { + if (!_rfDataLinkLayer.isTxQueueEmpty() && !syncStart) { - if (packetStart) - { - // - RX FIFO 4 bytes detected - - // Calculate the total length of the packet, and set fixed mode if less - // than 255 bytes to receive + sIdle(); + _loopState = TX_START; + break; + } - // Read the 2 first bytes - spiReadBurst(RXFIFO_BURST, pByteIndex, 2); + // Check if we have an incomplete packet reception + // This is related to CC1101 errata "Radio stays in RX state instead of entering RXFIFO_OVERFLOW state" + if (syncStart && (millis() - packetStartTime > RX_PACKET_TIMEOUT)) + { + println("RX packet timeout!"); + //uint8_t marcState = (spiReadRegister(MARCSTATE) & MARCSTATE_BITMASK); //read out state of cc1101 to be sure in RX + //print("marcstate: 0x"); + //println(marcState, HEX); + sIdle(); + _loopState = RX_START; + break; + } - // Decode the L-field - if (!manchDecode(&buffer[0], &packet[0])) - { - //println("Could not decode L-field: manchester code violation"); - _loopState = RX_START; - break; - } + // Detect rising edge 0->1 on GDO2 + statusGDO2 = digitalRead(GPIO_GDO2_PIN); - // Get bytes to receive from L-field, multiply by 2 because of manchester code - pktLen = 2 * PACKET_SIZE(packet[0]); + if (prevStatusGDO2 != statusGDO2) + { + prevStatusGDO2 = statusGDO2; - // - Length mode - - if (pktLen < 256) + // Check if signal GDO2 is asserted (RX FIFO is equal to or above threshold of 4 bytes) + if (statusGDO2 == 1) + { + if (packetStart) { - // Set fixed packet length mode is less than 256 bytes - spiWriteRegister(PKTLEN, pktLen); - spiWriteRegister(PKTCTRL0, 0x00); // Set fixed pktlen mode - fixedLengthMode = true; + // - RX FIFO 4 bytes detected - + // Calculate the total length of the packet, and set fixed mode if less + // than 255 bytes to receive + + // Read the 2 first bytes + spiReadBurst(RXFIFO_BURST, pByteIndex, 2); + + // Decode the L-field + if (!manchDecode(&buffer[0], &packet[0])) + { + //println("Could not decode L-field: manchester code violation"); + _loopState = RX_START; + break; + } + + // Get bytes to receive from L-field, multiply by 2 because of manchester code + pktLen = 2 * PACKET_SIZE(packet[0]); + + // - Length mode - + if (pktLen < 256) + { + // Set fixed packet length mode is less than 256 bytes + spiWriteRegister(PKTLEN, pktLen); + spiWriteRegister(PKTCTRL0, 0x00); // Set fixed pktlen mode + fixedLengthMode = true; + } + else + { + // Infinite packet length mode is more than 255 bytes + // Calculate the PKTLEN value + uint8_t fixedLength = pktLen % 256; + spiWriteRegister(PKTLEN, fixedLength); + } + + pByteIndex += 2; + bytesLeft = pktLen - 2; + + // Set RX FIFO threshold to 32 bytes + packetStart = false; + spiWriteRegister(FIFOTHR, 0x47); } else { - // Infinite packet length mode is more than 255 bytes - // Calculate the PKTLEN value - uint8_t fixedLength = pktLen % 256; - spiWriteRegister(PKTLEN, fixedLength); + // - RX FIFO Half Full detected - + // Read out the RX FIFO and set fixed mode if less + // than 255 bytes to receive + + // - Length mode - + // Set fixed packet length mode if less than 256 bytes + if ((bytesLeft < 256 ) && !fixedLengthMode) + { + spiWriteRegister(PKTCTRL0, 0x00); // Set fixed pktlen mode + fixedLengthMode = true; + } + + // Read out the RX FIFO + // Do not empty the FIFO (See the CC110x or 2500 Errata Note) + spiReadBurst(RXFIFO_BURST, pByteIndex, 32 - 1); + + bytesLeft -= (32 - 1); + pByteIndex += (32 - 1); } + } + } - pByteIndex += 2; - bytesLeft = pktLen - 2; + // Detect falling edge 1->0 on GDO0 + statusGDO0 = digitalRead(GPIO_GDO0_PIN); - // Set RX FIFO threshold to 32 bytes - packetStart = false; - spiWriteRegister(FIFOTHR, 0x47); - } - else + if (prevStatusGDO0 != statusGDO0) + { + prevStatusGDO0 = statusGDO0; + + // If GDO0 is de-asserted: RX packet complete or RX FIFO overflow + if (statusGDO0 == 0x00) { - // - RX FIFO Half Full detected - - // Read out the RX FIFO and set fixed mode if less - // than 255 bytes to receive + // There might be an RX FIFO overflow + uint8_t chipStatusBytes = spiWriteStrobe(SNOP); - // - Length mode - - // Set fixed packet length mode if less than 256 bytes - if ((bytesLeft < 256 ) && !fixedLengthMode) + if ((chipStatusBytes & CHIPSTATUS_STATE_BITMASK) == CHIPSTATUS_STATE_RX_OVERFLOW) { - spiWriteRegister(PKTCTRL0, 0x00); // Set fixed pktlen mode - fixedLengthMode = true; + println("RX FIFO overflow!"); + _loopState = RX_START; + break; } - // Read out the RX FIFO - // Do not empty the FIFO (See the CC110x or 2500 Errata Note) - spiReadBurst(RXFIFO_BURST, pByteIndex, 32 - 1); - - bytesLeft -= (32 - 1); - pByteIndex += (32 - 1); + // Check if we are in the middle of the packet reception + if (!packetStart) + { + // Complete packet received + // Read out remaining bytes in the RX FIFO + spiReadBurst(RXFIFO_BURST, pByteIndex, bytesLeft); + _loopState = RX_END; + } + } + else + { + // GDO0 asserted because sync word was received and recognized + //println("RX Syncword!"); + // wait for RX_PACKET_TIMEOUT milliseconds + // Complete packet must have been received within this time + packetStartTime = millis(); + syncStart = true; } } } + break; - // Detect falling edge 1->0 on GDO0 - statusGDO0 = digitalRead(GPIO_GDO0_PIN); - - if (prevStatusGDO0 != statusGDO0) + case RX_END: { - prevStatusGDO0 = statusGDO0; + uint16_t pLen = PACKET_SIZE(packet[0]); + // Decode the first block (always 10 bytes + 2 bytes CRC) + bool decodeOk = true; - // If GDO0 is de-asserted: RX packet complete or RX FIFO overflow - if (statusGDO0 == 0x00) + for (uint16_t i = 1; i < pLen; i++) { - // There might be an RX FIFO overflow - uint8_t chipStatusBytes = spiWriteStrobe(SNOP); - - if ((chipStatusBytes & CHIPSTATUS_STATE_BITMASK) == CHIPSTATUS_STATE_RX_OVERFLOW) + // Check for manchester violation, abort if there is one + if (!manchDecode(&buffer[i * 2], &packet[i])) { - println("RX FIFO overflow!"); - _loopState = RX_START; + println("Could not decode packet: manchester code violation"); + decodeOk = false; break; } - - // Check if we are in the middle of the packet reception - if (!packetStart) - { - // Complete packet received - // Read out remaining bytes in the RX FIFO - spiReadBurst(RXFIFO_BURST, pByteIndex, bytesLeft); - _loopState = RX_END; - } - } - else - { - // GDO0 asserted because sync word was received and recognized - //println("RX Syncword!"); - // wait for RX_PACKET_TIMEOUT milliseconds - // Complete packet must have been received within this time - packetStartTime = millis(); - syncStart = true; } - } - } - break; - - case RX_END: - { - uint16_t pLen = PACKET_SIZE(packet[0]); - // Decode the first block (always 10 bytes + 2 bytes CRC) - bool decodeOk = true; - for (uint16_t i = 1; i < pLen; i++) - { - // Check for manchester violation, abort if there is one - if (!manchDecode(&buffer[i * 2], &packet[i])) + if (decodeOk) { - println("Could not decode packet: manchester code violation"); - decodeOk = false; - break; + _rfDataLinkLayer.frameBytesReceived(&packet[0], pLen); } - } - if (decodeOk) - { - _rfDataLinkLayer.frameBytesReceived(&packet[0], pLen); + _loopState = RX_START; } - - _loopState = RX_START; + break; } - break; } } - #endif // DeviceFamily_CC13X0 \ No newline at end of file diff --git a/src/knx/rf/rf_physical_layer_cc1101.h b/src/knx/rf/rf_physical_layer_cc1101.h index 7eed58b9..7ea6855b 100644 --- a/src/knx/rf/rf_physical_layer_cc1101.h +++ b/src/knx/rf/rf_physical_layer_cc1101.h @@ -8,17 +8,16 @@ #include -/*----------------------------------[standard]--------------------------------*/ +namespace Knx +{ + /*----------------------------------[standard]--------------------------------*/ #define CC1101_TIMEOUT 2000 // Time to wait for a response from CC1101 #define RX_PACKET_TIMEOUT 20 // Wait 20ms for packet reception to complete #define TX_PACKET_TIMEOUT 20 // Wait 20ms for packet reception to complete -#ifdef __linux__ // Linux Platform - extern void delayMicroseconds (unsigned int howLong); -#endif -/*----------------------[CC1101 - misc]---------------------------------------*/ + /*----------------------[CC1101 - misc]---------------------------------------*/ #define CRYSTAL_FREQUENCY 26000000 #define CFG_REGISTER 0x2F // 47 registers #define FIFOBUFFER 0x42 // size of Fifo Buffer +2 for rssi and lqi @@ -34,23 +33,23 @@ #define CC1101_TEMP_ADC_MV 3.225 // 3.3V/1023 . mV pro digit #define CC1101_TEMP_CELS_CO 2.47 // Temperature coefficient 2.47mV per Grad Celsius -/*---------------------------[CC1101 - R/W offsets]---------------------------*/ + /*---------------------------[CC1101 - R/W offsets]---------------------------*/ #define WRITE_SINGLE_BYTE 0x00 #define WRITE_BURST 0x40 #define READ_SINGLE_BYTE 0x80 #define READ_BURST 0xC0 -/*---------------------------[END R/W offsets]--------------------------------*/ + /*---------------------------[END R/W offsets]--------------------------------*/ -/*------------------------[CC1101 - FIFO commands]----------------------------*/ + /*------------------------[CC1101 - FIFO commands]----------------------------*/ #define TXFIFO_BURST 0x7F // write burst only #define TXFIFO_SINGLE_BYTE 0x3F // write single only #define RXFIFO_BURST 0xFF // read burst only #define RXFIFO_SINGLE_BYTE 0xBF // read single only #define PATABLE_BURST 0x7E // power control read/write #define PATABLE_SINGLE_BYTE 0xFE // power control read/write -/*---------------------------[END FIFO commands]------------------------------*/ + /*---------------------------[END FIFO commands]------------------------------*/ -/*----------------------[CC1101 - config register]----------------------------*/ + /*----------------------[CC1101 - config register]----------------------------*/ #define IOCFG2 0x00 // GDO2 output pin configuration #define IOCFG1 0x01 // GDO1 output pin configuration #define IOCFG0 0x02 // GDO0 output pin configuration @@ -98,9 +97,9 @@ #define TEST2 0x2C // Various test settings #define TEST1 0x2D // Various test settings #define TEST0 0x2E // Various test settings -/*-------------------------[END config register]------------------------------*/ + /*-------------------------[END config register]------------------------------*/ -/*------------------------[CC1101-command strobes]----------------------------*/ + /*------------------------[CC1101-command strobes]----------------------------*/ #define SRES 0x30 // Reset chip #define SFSTXON 0x31 // Enable/calibrate freq synthesizer #define SXOFF 0x32 // Turn off crystal oscillator. @@ -115,9 +114,9 @@ #define SFTX 0x3B // Flush the TX FIFO buffer. #define SWORRST 0x3C // Reset real time clock. #define SNOP 0x3D // No operation. -/*-------------------------[END command strobes]------------------------------*/ + /*-------------------------[END command strobes]------------------------------*/ -/*----------------------[CC1101 - status register]----------------------------*/ + /*----------------------[CC1101 - status register]----------------------------*/ #define PARTNUM 0xF0 // Part number #define VERSION 0xF1 // Current version number #define FREQEST 0xF2 // Frequency offset estimate @@ -132,9 +131,9 @@ #define RXBYTES 0xFB // Overflow and # of bytes in RXFIFO #define RCCTRL1_STATUS 0xFC //Last RC Oscillator Calibration Result #define RCCTRL0_STATUS 0xFD //Last RC Oscillator Calibration Result -//--------------------------[END status register]------------------------------- + //--------------------------[END status register]------------------------------- -/*----------------------[CC1101 - Main Radio Control State Machine states]-----*/ + /*----------------------[CC1101 - Main Radio Control State Machine states]-----*/ #define MARCSTATE_BITMASK 0x1F #define MARCSTATE_SLEEP 0x00 #define MARCSTATE_IDLE 0x01 @@ -160,12 +159,12 @@ #define MARCSTATE_RXTX_SWITCH 0x15 #define MARCSTATE_TXFIFO_UNDERFLOW 0x16 -// Chip Status Byte -// Bit fields in the chip status byte + // Chip Status Byte + // Bit fields in the chip status byte #define CHIPSTATUS_CHIP_RDYn_BITMASK 0x80 #define CHIPSTATUS_STATE_BITMASK 0x70 #define CHIPSTATUS_FIFO_BYTES_AVAILABLE_BITMASK 0x0F -// Chip states + // Chip states #define CHIPSTATUS_STATE_IDLE 0x00 #define CHIPSTATUS_STATE_RX 0x10 #define CHIPSTATUS_STATE_TX 0x20 @@ -175,7 +174,7 @@ #define CHIPSTATUS_STATE_RX_OVERFLOW 0x60 #define CHIPSTATUS_STATE_TX_UNDERFLOW 0x70 -// loop states + // loop states #define RX_START 0 #define RX_ACTIVE 1 #define RX_END 2 @@ -183,59 +182,59 @@ #define TX_ACTIVE 4 #define TX_END 5 -class RfDataLinkLayer; - -class RfPhysicalLayerCC1101 : public RfPhysicalLayer -{ - public: - RfPhysicalLayerCC1101(RfDataLinkLayer& rfDataLinkLayer, Platform& platform); - - bool InitChip(); - void showRegisterSettings(); - void stopChip(); - void loop(); - - private: - // Table for encoding 4-bit data into a 8-bit Manchester encoding. - static const uint8_t manchEncodeTab[16]; - // Table for decoding 4-bit Manchester encoded data into 2-bit - static const uint8_t manchDecodeTab[16]; - - static const uint8_t cc1101_2FSK_32_7_kb[CFG_REGISTER]; - static const uint8_t paTablePower868[8]; - - void manchEncode(uint8_t* uncodedData, uint8_t* encodedData); - bool manchDecode(uint8_t* encodedData, uint8_t* decodedData); - - void powerDownCC1101(); - void setOutputPowerLevel(int8_t dBm); - - uint8_t sIdle(); - uint8_t sReceive(); - - void spiWriteRegister(uint8_t spi_instr, uint8_t value); - uint8_t spiReadRegister(uint8_t spi_instr); - uint8_t spiWriteStrobe(uint8_t spi_instr); - void spiReadBurst(uint8_t spi_instr, uint8_t* pArr, uint8_t len); - void spiWriteBurst(uint8_t spi_instr, const uint8_t* pArr, uint8_t len); - - uint8_t _loopState = RX_START; - - bool syncStart = false; - bool packetStart = true; - bool fixedLengthMode = false; - uint8_t* sendBuffer {0}; - uint16_t sendBufferLength {0}; - uint8_t packet[512]; - uint8_t buffer[sizeof(packet) * 2]; // We need twice the space due to manchester encoding - uint8_t* pByteIndex = &buffer[0]; - uint16_t pktLen {0}; - uint16_t bytesLeft = {0}; - uint8_t statusGDO0 {0}; - uint8_t statusGDO2 {0}; - uint8_t prevStatusGDO0 {0}; // for edge detection during polling - uint8_t prevStatusGDO2 {0}; // for edge detection during polling - uint32_t packetStartTime {0}; -}; - + class RfDataLinkLayer; + + class RfPhysicalLayerCC1101 : public RfPhysicalLayer + { + public: + RfPhysicalLayerCC1101(RfDataLinkLayer& rfDataLinkLayer, Platform& platform); + + bool InitChip(); + void showRegisterSettings(); + void stopChip(); + void loop(); + + private: + // Table for encoding 4-bit data into a 8-bit Manchester encoding. + static const uint8_t manchEncodeTab[16]; + // Table for decoding 4-bit Manchester encoded data into 2-bit + static const uint8_t manchDecodeTab[16]; + + static const uint8_t cc1101_2FSK_32_7_kb[CFG_REGISTER]; + static const uint8_t paTablePower868[8]; + + void manchEncode(uint8_t* uncodedData, uint8_t* encodedData); + bool manchDecode(uint8_t* encodedData, uint8_t* decodedData); + + void powerDownCC1101(); + void setOutputPowerLevel(int8_t dBm); + + uint8_t sIdle(); + uint8_t sReceive(); + + void spiWriteRegister(uint8_t spi_instr, uint8_t value); + uint8_t spiReadRegister(uint8_t spi_instr); + uint8_t spiWriteStrobe(uint8_t spi_instr); + void spiReadBurst(uint8_t spi_instr, uint8_t* pArr, uint8_t len); + void spiWriteBurst(uint8_t spi_instr, const uint8_t* pArr, uint8_t len); + + uint8_t _loopState = RX_START; + + bool syncStart = false; + bool packetStart = true; + bool fixedLengthMode = false; + uint8_t* sendBuffer {0}; + uint16_t sendBufferLength {0}; + uint8_t packet[512]; + uint8_t buffer[sizeof(packet) * 2]; // We need twice the space due to manchester encoding + uint8_t* pByteIndex = &buffer[0]; + uint16_t pktLen {0}; + uint16_t bytesLeft = {0}; + uint8_t statusGDO0 {0}; + uint8_t statusGDO2 {0}; + uint8_t prevStatusGDO0 {0}; // for edge detection during polling + uint8_t prevStatusGDO2 {0}; // for edge detection during polling + uint32_t packetStartTime {0}; + }; +} #endif // DeviceFamily_CC13X0 \ No newline at end of file diff --git a/src/knx/rf/rf_physical_layer_cc1310.cpp b/src/knx/rf/rf_physical_layer_cc1310.cpp index 833b250a..b28f730c 100644 --- a/src/knx/rf/rf_physical_layer_cc1310.cpp +++ b/src/knx/rf/rf_physical_layer_cc1310.cpp @@ -23,328 +23,287 @@ #define DEBUG_DUMP_PACKETS -static RF_Object rfObject; -static RF_Handle rfHandle; -static RF_CmdHandle rxCommandHandle; +namespace Knx +{ + static RF_Object rfObject; + static RF_Handle rfHandle; + static RF_CmdHandle rxCommandHandle; -static uint8_t rxBuffer[sizeof(rfc_dataEntryPartial_t) + RX_MAX_BUFFER_LENGTH] __attribute__((aligned(4))); -static rfc_dataEntryPartial_t* pDataEntry = (rfc_dataEntryPartial_t*)& rxBuffer; -static dataQueue_t dataQueue; + static uint8_t rxBuffer[sizeof(rfc_dataEntryPartial_t) + RX_MAX_BUFFER_LENGTH] __attribute__((aligned(4))); + static rfc_dataEntryPartial_t* pDataEntry = (rfc_dataEntryPartial_t*)& rxBuffer; + static dataQueue_t dataQueue; -static uint8_t addrFilterTable[2] = {0x44, 0xFF}; // Do not modify the size without changing RF_cmdPropRxAdv.addrConf.addrSize! + static uint8_t addrFilterTable[2] = {0x44, 0xFF}; // Do not modify the size without changing RF_cmdPropRxAdv.addrConf.addrSize! -static rfc_propRxOutput_t rxStatistics; + static rfc_propRxOutput_t rxStatistics; -static uint8_t packetLength; -static uint8_t* packetDataPointer; -static int32_t packetStartTime = 0; + static uint8_t packetLength; + static uint8_t* packetDataPointer; + static int32_t packetStartTime = 0; -static volatile bool rfDone = false; -static volatile int rfErr = 0; -static volatile int err; + static volatile bool rfDone = false; + static volatile int rfErr = 0; + static volatile int err; -static void RxCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) -{ - /* - static uint32_t count = 0; - - print("count: ");println(count++); - print("nextIndex: ");println(pDataEntry->nextIndex); - //print("pktStatus.numElements: ");println(pDataEntry->pktStatus.numElements); - print("RF_cmdPropRxAdv.status: ");println(RF_cmdPropRxAdv.status, HEX); - print("pktStatus.bEntryOpen: ");println(pDataEntry->pktStatus.bEntryOpen, HEX); - print("RF_EventMask: ");println(e, HEX); - */ - - if (e & RF_EventNDataWritten) + static void RxCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) { - // Make sure sure we are at the beginning of the packet - if (packetStartTime == 0) + /* + static uint32_t count = 0; + + print("count: ");println(count++); + print("nextIndex: ");println(pDataEntry->nextIndex); + //print("pktStatus.numElements: ");println(pDataEntry->pktStatus.numElements); + print("RF_cmdPropRxAdv.status: ");println(RF_cmdPropRxAdv.status, HEX); + print("pktStatus.bEntryOpen: ");println(pDataEntry->pktStatus.bEntryOpen, HEX); + print("RF_EventMask: ");println(e, HEX); + */ + + if (e & RF_EventNDataWritten) { - packetStartTime = millis(); + // Make sure sure we are at the beginning of the packet + if (packetStartTime == 0) + { + packetStartTime = millis(); - // pDataEntry->rxData contains the first byte of the received packet. - // Just get the address to get the start address of the receive buffer - uint8_t* pData = &pDataEntry->rxData; + // pDataEntry->rxData contains the first byte of the received packet. + // Just get the address to get the start address of the receive buffer + uint8_t* pData = &pDataEntry->rxData; - // Make sure we have a valid first block - if (((pData[1] != addrFilterTable[0]) || (pData[2] != addrFilterTable[1])) || - (crc16Dnp(pData, 10) != ((pData[10] << 8) | pData[11]))) - { - // cancel early because it does not seem to be KNX RF packet - RF_cancelCmd(rfHandle, rxCommandHandle, 0 /* force abort RF */); - return; - } + // Make sure we have a valid first block + if (((pData[1] != addrFilterTable[0]) || (pData[2] != addrFilterTable[1])) || + (crc16Dnp(pData, 10) != ((pData[10] << 8) | pData[11]))) + { + // cancel early because it does not seem to be KNX RF packet + RF_cancelCmd(rfHandle, rxCommandHandle, 0 /* force abort RF */); + return; + } - // First block is valid, so the length is valid - uint8_t len = pDataEntry->rxData; - struct rfc_CMD_PROP_SET_LEN_s RF_cmdPropSetLen = - { - .commandNo = CMD_PROP_SET_LEN, // command identifier - .rxLen = (uint16_t)PACKET_SIZE(len) // packet length to set - }; + // First block is valid, so the length is valid + uint8_t len = pDataEntry->rxData; + struct rfc_CMD_PROP_SET_LEN_s RF_cmdPropSetLen = + { + .commandNo = CMD_PROP_SET_LEN, // command identifier + .rxLen = (uint16_t)PACKET_SIZE(len) // packet length to set + }; - //RF_runImmediateCmd(rfHandle, (uint32_t*)&RF_cmdPropSetLen); // for length > 255 - RF_Stat status = RF_runDirectCmd(rfHandle, (uint32_t)&RF_cmdPropSetLen); + //RF_runImmediateCmd(rfHandle, (uint32_t*)&RF_cmdPropSetLen); // for length > 255 + RF_Stat status = RF_runDirectCmd(rfHandle, (uint32_t)&RF_cmdPropSetLen); - if (status != RF_StatCmdDoneSuccess) + if (status != RF_StatCmdDoneSuccess) + { + println("RF CMD_PROP_SET_LEN failed!"); + } + } + } + else if (e & RF_TERMINATION_EVENT_MASK) + { + if (e & RF_EventCmdAborted) { - println("RF CMD_PROP_SET_LEN failed!"); + println("RX ABORT"); } + + rfDone = true; + rfErr = e & (RF_EventCmdStopped | RF_EventCmdAborted | RF_EventCmdCancelled); } - } - else if (e & RF_TERMINATION_EVENT_MASK) - { - if (e & RF_EventCmdAborted) + else /* unknown reason - should not occur */ { - println("RX ABORT"); + pDataEntry->status = DATA_ENTRY_PENDING; + err++; } - - rfDone = true; - rfErr = e & (RF_EventCmdStopped | RF_EventCmdAborted | RF_EventCmdCancelled); } - else /* unknown reason - should not occur */ + + RfPhysicalLayerCC1310::RfPhysicalLayerCC1310(RfDataLinkLayer& rfDataLinkLayer, Platform& platform) + : RfPhysicalLayer(rfDataLinkLayer, platform) { - pDataEntry->status = DATA_ENTRY_PENDING; - err++; } -} -RfPhysicalLayerCC1310::RfPhysicalLayerCC1310(RfDataLinkLayer& rfDataLinkLayer, Platform& platform) - : RfPhysicalLayer(rfDataLinkLayer, platform) -{ -} - -void RfPhysicalLayerCC1310::setOutputPowerLevel(int8_t dBm) -{ - RF_TxPowerTable_Entry* rfPowerTable = NULL; - RF_TxPowerTable_Value newValue; - uint8_t rfPowerTableSize = 0; + void RfPhysicalLayerCC1310::setOutputPowerLevel(int8_t dBm) + { + RF_TxPowerTable_Entry* rfPowerTable = NULL; + RF_TxPowerTable_Value newValue; + uint8_t rfPowerTableSize = 0; - // Search the default PA power table for the desired power level - newValue = RF_TxPowerTable_findValue((RF_TxPowerTable_Entry*)PROP_RF_txPowerTable, dBm); + // Search the default PA power table for the desired power level + newValue = RF_TxPowerTable_findValue((RF_TxPowerTable_Entry*)PROP_RF_txPowerTable, dBm); - if (newValue.rawValue != RF_TxPowerTable_INVALID_VALUE) - { - // Found a valid entry - rfPowerTable = (RF_TxPowerTable_Entry*)PROP_RF_txPowerTable; - rfPowerTableSize = PROP_RF_txPowerTableSize; - } + if (newValue.rawValue != RF_TxPowerTable_INVALID_VALUE) + { + // Found a valid entry + rfPowerTable = (RF_TxPowerTable_Entry*)PROP_RF_txPowerTable; + rfPowerTableSize = PROP_RF_txPowerTableSize; + } - // if max power is requested then the CCFG_FORCE_VDDR_HH must be set in - // the ccfg + // if max power is requested then the CCFG_FORCE_VDDR_HH must be set in + // the ccfg #if (CCFG_FORCE_VDDR_HH != 0x1) - if ((newValue.paType == RF_TxPowerTable_DefaultPA) && - (dBm == rfPowerTable[rfPowerTableSize - 2].power)) - { - // The desired power level is set to the maximum supported under the - // default PA settings, but the boost mode (CCFG_FORCE_VDDR_HH) is not - // turned on - return; - } + if ((newValue.paType == RF_TxPowerTable_DefaultPA) && + (dBm == rfPowerTable[rfPowerTableSize - 2].power)) + { + // The desired power level is set to the maximum supported under the + // default PA settings, but the boost mode (CCFG_FORCE_VDDR_HH) is not + // turned on + return; + } #endif - RF_Stat rfStatus = RF_setTxPower(rfHandle, newValue); + RF_Stat rfStatus = RF_setTxPower(rfHandle, newValue); - if (rfStatus == RF_StatSuccess) - { - print("Successfully set TX output power to: "); - println(newValue.rawValue); - } - else - { - print("Could not set TX output power to: "); - println(newValue.rawValue); + if (rfStatus == RF_StatSuccess) + { + print("Successfully set TX output power to: "); + println(newValue.rawValue); + } + else + { + print("Could not set TX output power to: "); + println(newValue.rawValue); + } } -} -bool RfPhysicalLayerCC1310::InitChip() -{ - RF_Params rfParams; - RF_Params_init(&rfParams); - - pDataEntry->length = 255; - pDataEntry->config.type = DATA_ENTRY_TYPE_PARTIAL; // --> DATA_ENTRY_TYPE_PARTIAL adds a 12 Byte Header - pDataEntry-> config.irqIntv = 12; // KNX-RF first block consists of 12 bytes (one length byte, 0x44, 0xFF, one RFinfo byte, six Serial/DoA bytes, two CRC bytes) - pDataEntry-> config.lenSz = 0; // no length indicator at beginning of data entry - pDataEntry->status = DATA_ENTRY_PENDING; - pDataEntry->pNextEntry = (uint8_t*)pDataEntry; - - dataQueue.pCurrEntry = (uint8_t*)pDataEntry; - dataQueue.pLastEntry = NULL; - - // Set buffer with address. We use the two fixed bytes 0x44 and 0xFF as our address to let the - // packet engine do more filtering on itself - RF_cmdPropRxAdv.pAddr = (uint8_t*)&addrFilterTable; - // Set the Data Entity queue for received data - RF_cmdPropRxAdv.pQueue = &dataQueue; - // Set the output buffer for RX packet statistics - RF_cmdPropRxAdv.pOutput = (uint8_t*)&rxStatistics; - - // Request access to the radio - rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams); - - /* Set the frequency */ - RF_runCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0); - return true; -} - -void RfPhysicalLayerCC1310::stopChip() -{ - RF_cancelCmd(rfHandle, rxCommandHandle, 0 /* do not stop gracefully, instead hard abort RF */); - RF_pendCmd(rfHandle, rxCommandHandle, RF_TERMINATION_EVENT_MASK); - RF_yield(rfHandle); - RF_close(rfHandle); -} - -void RfPhysicalLayerCC1310::loop() -{ - switch (_loopState) + bool RfPhysicalLayerCC1310::InitChip() { - case TX_START: - { - uint8_t* sendBuffer {nullptr}; - uint16_t sendBufferLength {0}; + RF_Params rfParams; + RF_Params_init(&rfParams); - //println("TX_START..."); - _rfDataLinkLayer.loadNextTxFrame(&sendBuffer, &sendBufferLength); - uint16_t pktLen = PACKET_SIZE(sendBuffer[0]); + pDataEntry->length = 255; + pDataEntry->config.type = DATA_ENTRY_TYPE_PARTIAL; // --> DATA_ENTRY_TYPE_PARTIAL adds a 12 Byte Header + pDataEntry-> config.irqIntv = 12; // KNX-RF first block consists of 12 bytes (one length byte, 0x44, 0xFF, one RFinfo byte, six Serial/DoA bytes, two CRC bytes) + pDataEntry-> config.lenSz = 0; // no length indicator at beginning of data entry + pDataEntry->status = DATA_ENTRY_PENDING; + pDataEntry->pNextEntry = (uint8_t*)pDataEntry; - if (pktLen != sendBufferLength) - { - print("Error TX: SendBuffer[0]="); - println(sendBuffer[0]); - print("Error TX: SendBufferLength="); - println(sendBufferLength); - print("Error TX: PACKET_SIZE="); - println(PACKET_SIZE(sendBuffer[0])); - } + dataQueue.pCurrEntry = (uint8_t*)pDataEntry; + dataQueue.pLastEntry = NULL; - // Calculate total number of bytes in the KNX RF packet from L-field - // Check for valid length - if ((pktLen == 0) || (pktLen > 290)) - { - println("TX packet length error!"); - break; - } + // Set buffer with address. We use the two fixed bytes 0x44 and 0xFF as our address to let the + // packet engine do more filtering on itself + RF_cmdPropRxAdv.pAddr = (uint8_t*)&addrFilterTable; + // Set the Data Entity queue for received data + RF_cmdPropRxAdv.pQueue = &dataQueue; + // Set the output buffer for RX packet statistics + RF_cmdPropRxAdv.pOutput = (uint8_t*)&rxStatistics; - if (pktLen > 255) - { - println("Unhandled: TX packet > 255"); - break; - } + // Request access to the radio + rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams); - RF_cmdPropTx.pktLen = pktLen; - RF_cmdPropTx.pPkt = sendBuffer; - RF_cmdPropTx.startTrigger.triggerType = TRIG_NOW; - RF_EventMask result = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, NULL, RF_TERMINATION_EVENT_MASK); - //print("TX: RF_EventMask: ");println(result, HEX); + /* Set the frequency */ + RF_runCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0); + return true; + } -#if defined(DEBUG_DUMP_PACKETS) - printHex("TX: ", sendBuffer, pktLen); -#endif - delete sendBuffer; + void RfPhysicalLayerCC1310::stopChip() + { + RF_cancelCmd(rfHandle, rxCommandHandle, 0 /* do not stop gracefully, instead hard abort RF */); + RF_pendCmd(rfHandle, rxCommandHandle, RF_TERMINATION_EVENT_MASK); + RF_yield(rfHandle); + RF_close(rfHandle); + } - if (result != RF_EventLastCmdDone) + void RfPhysicalLayerCC1310::loop() + { + switch (_loopState) + { + case TX_START: { - print("Unexpected result command: "); - println(result, HEX); - } + uint8_t* sendBuffer {nullptr}; + uint16_t sendBufferLength {0}; - //println("Restart RX..."); - _loopState = RX_START; - } - break; + //println("TX_START..."); + _rfDataLinkLayer.loadNextTxFrame(&sendBuffer, &sendBufferLength); + uint16_t pktLen = PACKET_SIZE(sendBuffer[0]); - case RX_START: - { - packetStartTime = 0; - rfDone = false; - rfErr = 0; - err = 0; - pDataEntry->status = DATA_ENTRY_PENDING; + if (pktLen != sendBufferLength) + { + print("Error TX: SendBuffer[0]="); + println(sendBuffer[0]); + print("Error TX: SendBufferLength="); + println(sendBufferLength); + print("Error TX: PACKET_SIZE="); + println(PACKET_SIZE(sendBuffer[0])); + } - rxCommandHandle = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdPropRxAdv, RF_PriorityNormal, &RxCallback, RF_EventNDataWritten | RF_EventRxAborted); + // Calculate total number of bytes in the KNX RF packet from L-field + // Check for valid length + if ((pktLen == 0) || (pktLen > 290)) + { + println("TX packet length error!"); + break; + } - if (rxCommandHandle == RF_ALLOC_ERROR) - { - println("Error: nRF_pendCmd() failed"); - return; - } + if (pktLen > 255) + { + println("Unhandled: TX packet > 255"); + break; + } - _loopState = RX_ACTIVE; - } - break; + RF_cmdPropTx.pktLen = pktLen; + RF_cmdPropTx.pPkt = sendBuffer; + RF_cmdPropTx.startTrigger.triggerType = TRIG_NOW; + RF_EventMask result = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, NULL, RF_TERMINATION_EVENT_MASK); + //print("TX: RF_EventMask: ");println(result, HEX); - case RX_ACTIVE: - { - if (!_rfDataLinkLayer.isTxQueueEmpty()) - { - RF_cancelCmd(rfHandle, rxCommandHandle, RF_ABORT_GRACEFULLY); - RF_pendCmd(rfHandle, rxCommandHandle, RF_TERMINATION_EVENT_MASK); +#if defined(DEBUG_DUMP_PACKETS) + printHex("TX: ", sendBuffer, pktLen); +#endif + delete sendBuffer; - if (RF_cmdPropTx.status != PROP_DONE_OK) + if (result != RF_EventLastCmdDone) { - print("Unexpected RF_cmdPropTx.status after stopping RX: "); - println(RF_cmdPropTx.status, HEX); + print("Unexpected result command: "); + println(result, HEX); } - _loopState = TX_START; - break; - } - - // Check if we have an incomplete packet reception - if (!rfDone && ((packetStartTime > 0) && (millis() - packetStartTime > RX_PACKET_TIMEOUT))) - { - println("RX packet timeout!"); - RF_cancelCmd(rfHandle, rxCommandHandle, RF_ABORT_GRACEFULLY); - RF_pendCmd(rfHandle, rxCommandHandle, RF_TERMINATION_EVENT_MASK); - /* - print("nRxOk = ");println(rxStatistics.nRxOk); // Number of packets that have been received with payload, CRC OK and not ignored - print("nRxNok = ");println(rxStatistics.nRxNok); // Number of packets that have been received with CRC error - print("nRxIgnored = ");println(rxStatistics.nRxIgnored); // Number of packets that have been received with CRC OK and ignored due to address mismatch - print("nRxStopped = ");println(rxStatistics.nRxStopped); // Number of packets not received due to illegal length or address mismatch with pktConf.filterOp = 1 - print("nRxBufFull = ");println(rxStatistics.nRxBufFull); // Number of packets that have been received and discarded due to lack of buffer space - */ + //println("Restart RX..."); _loopState = RX_START; - break; } - else if (rfDone) + break; + + case RX_START: { - RF_EventMask result = RF_pendCmd(rfHandle, rxCommandHandle, RF_TERMINATION_EVENT_MASK); + packetStartTime = 0; + rfDone = false; + rfErr = 0; + err = 0; + pDataEntry->status = DATA_ENTRY_PENDING; - if ((result & RF_EventCmdCancelled) || (result & RF_EventCmdStopped) || (result & RF_EventCmdAborted)) - { - println("RF terminated because of RF_flushCmd() or RF_cancelCmd()"); - } - else if ((result & RF_EventLastCmdDone) != RF_EventLastCmdDone) - { - print("Unexpected Rx result command: "); - println(result, HEX); - } - else if (rfErr) + rxCommandHandle = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdPropRxAdv, RF_PriorityNormal, &RxCallback, RF_EventNDataWritten | RF_EventRxAborted); + + if (rxCommandHandle == RF_ALLOC_ERROR) { - println("Rx is no KNX frame"); + println("Error: nRF_pendCmd() failed"); + return; } - else if ((result & RF_EventLastCmdDone) == RF_EventLastCmdDone) + + _loopState = RX_ACTIVE; + } + break; + + case RX_ACTIVE: + { + if (!_rfDataLinkLayer.isTxQueueEmpty()) { - // add CRC sizes for received blocks, but do not add the length of the L-field (1 byte) itself - packetLength = PACKET_SIZE(pDataEntry->rxData); - packetDataPointer = (uint8_t*) &pDataEntry->rxData; + RF_cancelCmd(rfHandle, rxCommandHandle, RF_ABORT_GRACEFULLY); + RF_pendCmd(rfHandle, rxCommandHandle, RF_TERMINATION_EVENT_MASK); - // Sanity check: the partial data entry index points to the next free location in the partial RX buffer - if (packetLength != (pDataEntry->nextIndex - 1)) + if (RF_cmdPropTx.status != PROP_DONE_OK) { - println("Mismatch between packetLength and pDataEntry->nextIndex: "); - print("packetLength = "); - print(packetLength); - print(", pDataEntry->nextIndex = "); - println(pDataEntry->nextIndex); + print("Unexpected RF_cmdPropTx.status after stopping RX: "); + println(RF_cmdPropTx.status, HEX); } + _loopState = TX_START; + break; + } + + // Check if we have an incomplete packet reception + if (!rfDone && ((packetStartTime > 0) && (millis() - packetStartTime > RX_PACKET_TIMEOUT))) + { + println("RX packet timeout!"); + RF_cancelCmd(rfHandle, rxCommandHandle, RF_ABORT_GRACEFULLY); + RF_pendCmd(rfHandle, rxCommandHandle, RF_TERMINATION_EVENT_MASK); /* print("nRxOk = ");println(rxStatistics.nRxOk); // Number of packets that have been received with payload, CRC OK and not ignored print("nRxNok = ");println(rxStatistics.nRxNok); // Number of packets that have been received with CRC error @@ -352,20 +311,63 @@ void RfPhysicalLayerCC1310::loop() print("nRxStopped = ");println(rxStatistics.nRxStopped); // Number of packets not received due to illegal length or address mismatch with pktConf.filterOp = 1 print("nRxBufFull = ");println(rxStatistics.nRxBufFull); // Number of packets that have been received and discarded due to lack of buffer space */ + _loopState = RX_START; + break; + } + else if (rfDone) + { + RF_EventMask result = RF_pendCmd(rfHandle, rxCommandHandle, RF_TERMINATION_EVENT_MASK); + + if ((result & RF_EventCmdCancelled) || (result & RF_EventCmdStopped) || (result & RF_EventCmdAborted)) + { + println("RF terminated because of RF_flushCmd() or RF_cancelCmd()"); + } + else if ((result & RF_EventLastCmdDone) != RF_EventLastCmdDone) + { + print("Unexpected Rx result command: "); + println(result, HEX); + } + else if (rfErr) + { + println("Rx is no KNX frame"); + } + else if ((result & RF_EventLastCmdDone) == RF_EventLastCmdDone) + { + // add CRC sizes for received blocks, but do not add the length of the L-field (1 byte) itself + packetLength = PACKET_SIZE(pDataEntry->rxData); + packetDataPointer = (uint8_t*) &pDataEntry->rxData; + + // Sanity check: the partial data entry index points to the next free location in the partial RX buffer + if (packetLength != (pDataEntry->nextIndex - 1)) + { + println("Mismatch between packetLength and pDataEntry->nextIndex: "); + print("packetLength = "); + print(packetLength); + print(", pDataEntry->nextIndex = "); + println(pDataEntry->nextIndex); + } + + /* + print("nRxOk = ");println(rxStatistics.nRxOk); // Number of packets that have been received with payload, CRC OK and not ignored + print("nRxNok = ");println(rxStatistics.nRxNok); // Number of packets that have been received with CRC error + print("nRxIgnored = ");println(rxStatistics.nRxIgnored); // Number of packets that have been received with CRC OK and ignored due to address mismatch + print("nRxStopped = ");println(rxStatistics.nRxStopped); // Number of packets not received due to illegal length or address mismatch with pktConf.filterOp = 1 + print("nRxBufFull = ");println(rxStatistics.nRxBufFull); // Number of packets that have been received and discarded due to lack of buffer space + */ #if defined(DEBUG_DUMP_PACKETS) - printHex("RX: ", packetDataPointer, packetLength, false); - print ("- RSSI: "); - println(rxStatistics.lastRssi); + printHex("RX: ", packetDataPointer, packetLength, false); + print ("- RSSI: "); + println(rxStatistics.lastRssi); #endif - _rfDataLinkLayer.frameBytesReceived(packetDataPointer, packetLength); - } + _rfDataLinkLayer.frameBytesReceived(packetDataPointer, packetLength); + } - _loopState = RX_START; + _loopState = RX_START; + } } + break; } - break; } } - #endif // DeviceFamily_CC13X0 \ No newline at end of file diff --git a/src/knx/rf/rf_physical_layer_cc1310.h b/src/knx/rf/rf_physical_layer_cc1310.h index d7dfa60e..58d86034 100644 --- a/src/knx/rf/rf_physical_layer_cc1310.h +++ b/src/knx/rf/rf_physical_layer_cc1310.h @@ -17,21 +17,23 @@ #define TX_ACTIVE 4 #define TX_END 5 -class RfDataLinkLayer; - -class RfPhysicalLayerCC1310 : public RfPhysicalLayer +namespace Knx { - public: - RfPhysicalLayerCC1310(RfDataLinkLayer& rfDataLinkLayer, Platform& platform); + class RfDataLinkLayer; - bool InitChip() override; - void stopChip() override; - void loop() override; + class RfPhysicalLayerCC1310 : public RfPhysicalLayer + { + public: + RfPhysicalLayerCC1310(RfDataLinkLayer& rfDataLinkLayer, Platform& platform); - void setOutputPowerLevel(int8_t dBm); + bool InitChip() override; + void stopChip() override; + void loop() override; - private: - uint8_t _loopState = RX_START; -}; + void setOutputPowerLevel(int8_t dBm); + private: + uint8_t _loopState = RX_START; + }; +} #endif // DeviceFamily_CC13X0 \ No newline at end of file diff --git a/src/knx/tp/bau07B0.cpp b/src/knx/tp/bau07B0.cpp index 9b0576df..a7ac5d30 100644 --- a/src/knx/tp/bau07B0.cpp +++ b/src/knx/tp/bau07B0.cpp @@ -5,170 +5,173 @@ #include #include -Bau07B0::Bau07B0(Platform& platform) - : BauSystemBDevice(platform), DataLinkLayerCallbacks(), - _dlLayer(_deviceObj, _netLayer.getInterface(), _platform, (ITpUartCallBacks&) * this, (DataLinkLayerCallbacks*) this) +namespace Knx +{ + Bau07B0::Bau07B0(Platform& platform) + : BauSystemBDevice(platform), DataLinkLayerCallbacks(), + _dlLayer(_deviceObj, _netLayer.getInterface(), _platform, (ITpUartCallBacks&) * this, (DataLinkLayerCallbacks*) this) #ifdef USE_CEMI_SERVER - , _cemiServer(*this) + , _cemiServer(*this) #endif -{ - _netLayer.getInterface().dataLinkLayer(_dlLayer); + { + _netLayer.getInterface().dataLinkLayer(_dlLayer); #ifdef USE_CEMI_SERVER - _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_TP1); - _cemiServer.dataLinkLayer(_dlLayer); - _dlLayer.cemiServer(_cemiServer); - _memory.addSaveRestore(&_cemiServerObject); + _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_TP1); + _cemiServer.dataLinkLayer(_dlLayer); + _dlLayer.cemiServer(_cemiServer); + _memory.addSaveRestore(&_cemiServerObject); #endif - // Set Mask Version in Device Object depending on the BAU - _deviceObj.maskVersion(0x07B0); - - // Set which interface objects are available in the device object - // This differs from BAU to BAU with different medium types. - // See PID_IO_LIST - Property* prop = _deviceObj.property(PID_IO_LIST); - prop->write(1, (uint16_t) OT_DEVICE); - prop->write(2, (uint16_t) OT_ADDR_TABLE); - prop->write(3, (uint16_t) OT_ASSOC_TABLE); - prop->write(4, (uint16_t) OT_GRP_OBJ_TABLE); - prop->write(5, (uint16_t) OT_APPLICATION_PROG); + // Set Mask Version in Device Object depending on the BAU + _deviceObj.maskVersion(0x07B0); + + // Set which interface objects are available in the device object + // This differs from BAU to BAU with different medium types. + // See PID_IO_LIST + Property* prop = _deviceObj.property(PID_IO_LIST); + prop->write(1, (uint16_t) OT_DEVICE); + prop->write(2, (uint16_t) OT_ADDR_TABLE); + prop->write(3, (uint16_t) OT_ASSOC_TABLE); + prop->write(4, (uint16_t) OT_GRP_OBJ_TABLE); + prop->write(5, (uint16_t) OT_APPLICATION_PROG); #if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER) - prop->write(6, (uint16_t) OT_SECURITY); - prop->write(7, (uint16_t) OT_CEMI_SERVER); + prop->write(6, (uint16_t) OT_SECURITY); + prop->write(7, (uint16_t) OT_CEMI_SERVER); #elif defined(USE_DATASECURE) - prop->write(6, (uint16_t) OT_SECURITY); + prop->write(6, (uint16_t) OT_SECURITY); #elif defined(USE_CEMI_SERVER) - prop->write(6, (uint16_t) OT_CEMI_SERVER); + prop->write(6, (uint16_t) OT_CEMI_SERVER); #endif -} + } -InterfaceObject* Bau07B0::getInterfaceObject(uint8_t idx) -{ - switch (idx) + InterfaceObject* Bau07B0::getInterfaceObject(uint8_t idx) { - case 0: - return &_deviceObj; + switch (idx) + { + case 0: + return &_deviceObj; - case 1: - return &_addrTable; + case 1: + return &_addrTable; - case 2: - return &_assocTable; + case 2: + return &_assocTable; - case 3: - return &_groupObjTable; + case 3: + return &_groupObjTable; - case 4: - return &_appProgram; + case 4: + return &_appProgram; - case 5: // would be app_program 2 - return nullptr; + case 5: // would be app_program 2 + return nullptr; #if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER) - case 6: - return &_secIfObj; + case 6: + return &_secIfObj; - case 7: - return &_cemiServerObject; + case 7: + return &_cemiServerObject; #elif defined(USE_CEMI_SERVER) - case 6: - return &_cemiServerObject; + case 6: + return &_cemiServerObject; #elif defined(USE_DATASECURE) - case 6: - return &_secIfObj; + case 6: + return &_secIfObj; #endif - default: - return nullptr; + default: + return nullptr; + } } -} - -InterfaceObject* Bau07B0::getInterfaceObject(ObjectType objectType, uint16_t objectInstance) -{ - // We do not use it right now. - // Required for coupler mode as there are multiple router objects for example - (void) objectInstance; - switch (objectType) + InterfaceObject* Bau07B0::getInterfaceObject(ObjectType objectType, uint16_t objectInstance) { - case OT_DEVICE: - return &_deviceObj; + // We do not use it right now. + // Required for coupler mode as there are multiple router objects for example + (void) objectInstance; - case OT_ADDR_TABLE: - return &_addrTable; + switch (objectType) + { + case OT_DEVICE: + return &_deviceObj; - case OT_ASSOC_TABLE: - return &_assocTable; + case OT_ADDR_TABLE: + return &_addrTable; - case OT_GRP_OBJ_TABLE: - return &_groupObjTable; + case OT_ASSOC_TABLE: + return &_assocTable; - case OT_APPLICATION_PROG: - return &_appProgram; + case OT_GRP_OBJ_TABLE: + return &_groupObjTable; + + case OT_APPLICATION_PROG: + return &_appProgram; #ifdef USE_DATASECURE - case OT_SECURITY: - return &_secIfObj; + case OT_SECURITY: + return &_secIfObj; #endif #ifdef USE_CEMI_SERVER - case OT_CEMI_SERVER: - return &_cemiServerObject; + case OT_CEMI_SERVER: + return &_cemiServerObject; #endif - default: - return nullptr; + default: + return nullptr; + } } -} -bool Bau07B0::enabled() -{ - return _dlLayer.enabled(); -} + bool Bau07B0::enabled() + { + return _dlLayer.enabled(); + } -void Bau07B0::enabled(bool value) -{ - _dlLayer.enabled(value); -} + void Bau07B0::enabled(bool value) + { + _dlLayer.enabled(value); + } -void Bau07B0::loop() -{ - _dlLayer.loop(); - BauSystemBDevice::loop(); + void Bau07B0::loop() + { + _dlLayer.loop(); + BauSystemBDevice::loop(); #ifdef USE_CEMI_SERVER - _cemiServer.loop(); + _cemiServer.loop(); #endif -} + } -TPAckType Bau07B0::isAckRequired(uint16_t address, bool isGrpAddr) -{ - if (isGrpAddr) + TPAckType Bau07B0::isAckRequired(uint16_t address, bool isGrpAddr) { - // ACK for broadcasts - if (address == 0) + if (isGrpAddr) + { + // ACK for broadcasts + if (address == 0) + return TPAckType::AckReqAck; + + // is group address in group address table? ACK if yes. + if (_addrTable.contains(address)) + return TPAckType::AckReqAck; + else + return TPAckType::AckReqNone; + } + + // Also ACK for our own individual address + if (address == _deviceObj.individualAddress()) return TPAckType::AckReqAck; - // is group address in group address table? ACK if yes. - if (_addrTable.contains(address)) - return TPAckType::AckReqAck; - else - return TPAckType::AckReqNone; - } + if (address == 0) + { + println("Invalid broadcast detected: destination address is 0, but address type is \"individual\""); + } - // Also ACK for our own individual address - if (address == _deviceObj.individualAddress()) - return TPAckType::AckReqAck; + return TPAckType::AckReqNone; + } - if (address == 0) + TpUartDataLinkLayer* Bau07B0::getDataLinkLayer() { - println("Invalid broadcast detected: destination address is 0, but address type is \"individual\""); + return (TpUartDataLinkLayer*)&_dlLayer; } - - return TPAckType::AckReqNone; -} - -TpUartDataLinkLayer* Bau07B0::getDataLinkLayer() -{ - return (TpUartDataLinkLayer*)&_dlLayer; } \ No newline at end of file diff --git a/src/knx/tp/bau07B0.h b/src/knx/tp/bau07B0.h index af5521ad..d74461ff 100644 --- a/src/knx/tp/bau07B0.h +++ b/src/knx/tp/bau07B0.h @@ -7,26 +7,29 @@ #include "../cemi_server/cemi_server.h" #include "../cemi_server/cemi_server_object.h" -class Bau07B0 : public BauSystemBDevice, public ITpUartCallBacks, public DataLinkLayerCallbacks +namespace Knx { - public: - Bau07B0(Platform& platform); - void loop() override; - bool enabled() override; - void enabled(bool value) override; + class Bau07B0 : public BauSystemBDevice, public ITpUartCallBacks, public DataLinkLayerCallbacks + { + public: + Bau07B0(Platform& platform); + void loop() override; + bool enabled() override; + void enabled(bool value) override; - TpUartDataLinkLayer* getDataLinkLayer(); - protected: - InterfaceObject* getInterfaceObject(uint8_t idx); - InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance); + TpUartDataLinkLayer* getDataLinkLayer(); + protected: + InterfaceObject* getInterfaceObject(uint8_t idx); + InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance); - // For TP1 only - TPAckType isAckRequired(uint16_t address, bool isGrpAddr) override; + // For TP1 only + TPAckType isAckRequired(uint16_t address, bool isGrpAddr) override; - private: - TpUartDataLinkLayer _dlLayer; + private: + TpUartDataLinkLayer _dlLayer; #ifdef USE_CEMI_SERVER - CemiServer _cemiServer; - CemiServerObject _cemiServerObject; + CemiServer _cemiServer; + CemiServerObject _cemiServerObject; #endif -}; + }; +} \ No newline at end of file diff --git a/src/knx/tp/tp_frame.cpp b/src/knx/tp/tp_frame.cpp index 101376a1..eaf191bf 100644 --- a/src/knx/tp/tp_frame.cpp +++ b/src/knx/tp/tp_frame.cpp @@ -2,26 +2,29 @@ #include "../bits.h" -void TpFrame::printIt() const +namespace Knx { - print_ia(source()); - print(" -> "); + void TpFrame::printIt() const + { + print_ia(source()); + print(" -> "); - if (isGroupAddress()) - print_ga(destination()); - else - print_ia(destination()); + if (isGroupAddress()) + print_ga(destination()); + else + print_ia(destination()); - print(" ["); - print((flags() & TP_FRAME_FLAG_INVALID) ? 'I' : '_'); // Invalid - print((flags() & TP_FRAME_FLAG_EXTENDED) ? 'E' : '_'); // Extended - print((flags() & TP_FRAME_FLAG_REPEATED) ? 'R' : '_'); // Repeat - print((flags() & TP_FRAME_FLAG_ECHO) ? 'T' : '_'); // Send by me - print((flags() & TP_FRAME_FLAG_ADDRESSED) ? 'D' : '_'); // Recv for me - print((flags() & TP_FRAME_FLAG_ACK_NACK) ? 'N' : '_'); // ACK + NACK - print((flags() & TP_FRAME_FLAG_ACK_BUSY) ? 'B' : '_'); // ACK + BUSY - print((flags() & TP_FRAME_FLAG_ACK) ? 'A' : '_'); // ACK - print("] "); - printHex("( ", data(), size(), false); - print(")"); + print(" ["); + print((flags() & TP_FRAME_FLAG_INVALID) ? 'I' : '_'); // Invalid + print((flags() & TP_FRAME_FLAG_EXTENDED) ? 'E' : '_'); // Extended + print((flags() & TP_FRAME_FLAG_REPEATED) ? 'R' : '_'); // Repeat + print((flags() & TP_FRAME_FLAG_ECHO) ? 'T' : '_'); // Send by me + print((flags() & TP_FRAME_FLAG_ADDRESSED) ? 'D' : '_'); // Recv for me + print((flags() & TP_FRAME_FLAG_ACK_NACK) ? 'N' : '_'); // ACK + NACK + print((flags() & TP_FRAME_FLAG_ACK_BUSY) ? 'B' : '_'); // ACK + BUSY + print((flags() & TP_FRAME_FLAG_ACK) ? 'A' : '_'); // ACK + print("] "); + printHex("( ", data(), size(), false); + print(")"); + } } \ No newline at end of file diff --git a/src/knx/tp/tp_frame.h b/src/knx/tp/tp_frame.h index d30bcc55..7c78001f 100644 --- a/src/knx/tp/tp_frame.h +++ b/src/knx/tp/tp_frame.h @@ -30,260 +30,263 @@ // Means that the frame has been acked #define TP_FRAME_FLAG_ACK 0b00000001 -class TpFrame +namespace Knx { - private: - uint8_t* _data; - uint16_t _size; - uint16_t _maxSize; - uint8_t _flags = 0; - - /* - * Sets a few flags based on the control byte - */ - inline void presetFlags() - { - if (isExtended()) - addFlags(TP_FRAME_FLAG_EXTENDED); - - if (isRepeated()) - addFlags(TP_FRAME_FLAG_REPEATED); - } - - public: - /* - * Convert a CemiFrame into a TpFrame - */ - TpFrame(CemiFrame& cemiFrame) - { - _size = cemiFrame.telegramLengthtTP(); - _maxSize = cemiFrame.telegramLengthtTP(); - _data = new uint8_t[cemiFrame.telegramLengthtTP()]; - cemiFrame.fillTelegramTP(_data); - presetFlags(); - } - - /* - * Create a TpFrame with a reserved space. - * Used for incoming parsing. - */ - TpFrame(uint16_t maxSize = 263) - : _maxSize(maxSize) - { - _data = new uint8_t[_maxSize]; - _size = 0; - } - - /* - * Free the data area - */ - ~TpFrame() - { - delete[] _data; - } - - /* - * Add a byte at end. - * Used for incoming parsing. - */ - inline void addByte(uint8_t byte) - { - if (!isFull()) + class TpFrame + { + private: + uint8_t* _data; + uint16_t _size; + uint16_t _maxSize; + uint8_t _flags = 0; + + /* + * Sets a few flags based on the control byte + */ + inline void presetFlags() { - _data[_size] = byte; - _size++; + if (isExtended()) + addFlags(TP_FRAME_FLAG_EXTENDED); + + if (isRepeated()) + addFlags(TP_FRAME_FLAG_REPEATED); } - // Read meta data for flags - if (_size == 1) + public: + /* + * Convert a CemiFrame into a TpFrame + */ + TpFrame(CemiFrame& cemiFrame) + { + _size = cemiFrame.telegramLengthtTP(); + _maxSize = cemiFrame.telegramLengthtTP(); + _data = new uint8_t[cemiFrame.telegramLengthtTP()]; + cemiFrame.fillTelegramTP(_data); presetFlags(); - } - - /* - * Current frame size. This may differ from the actual size as long as the frame is not complete. - */ - inline uint16_t size() const - { - return _size; - } - - /* - * Returns the assigned flags - */ - inline uint16_t flags() const - { - return _flags; - } - - /* - * Adds one or more flags - */ - inline void addFlags(uint8_t flags) - { - _flags |= flags; - } - - /* - * Returns a pointer to the data - */ - inline const uint8_t* data() const - { - return _data; - } - - /* - * Returns the byte corresponding to the specified position - */ - inline uint8_t data(uint16_t pos) - { - return _data[pos]; - } - - /* - * Resets the internal values to refill the frame. - */ - inline void reset() - { - _size = 0; - _flags = 0; - // It is important to fill the _data with zeros so that the length is 0 as long as the value has not yet been read in. - memset(_data, 0x0, _maxSize); - } - - /* - * Checks whether the frame has been imported completely - */ - inline bool isFull() - { - return _size >= (_size >= 7 ? fullSize() : _maxSize); - } - - /* - * Returns is the frame exteneded or not - */ - inline bool isExtended() const - { - return (_data[0] & 0xD3) == 0x10; - } - - /* - * Returns the source - * Assumes that enough data has been imported. - */ - inline uint16_t source() const - { - return isExtended() ? (_data[2] << 8) + _data[3] : (_data[1] << 8) + _data[2]; - } - - /* - * Returns the destination - * Assumes that enough data has been imported. - */ - inline uint16_t destination() const - { - return isExtended() ? (_data[4] << 8) + _data[5] : (_data[3] << 8) + _data[4]; - } - - /* - * Returns the payload size (with checksum) - * Assumes that enough data has been imported. - */ - inline uint8_t payloadSize() - { - return isExtended() ? _data[6] : _data[5] & 0b1111; - } - - /* - * Returns the header size - */ - inline uint8_t headerSize() - { - return isExtended() ? 9 : 8; - } - - /* - * Returns the frame size based on header and payload size. - * Assumes that enough data has been imported. - */ - inline uint16_t fullSize() - { - return headerSize() + payloadSize(); - } - - /* - * Returns if the destination is a group address - * Assumes that enough data has been imported. - */ - inline bool isGroupAddress() const - { - return isExtended() ? (_data[1] >> 7) & 0b1 : (_data[5] >> 7) & 0b1; - } - - /* - * Calculates the size of a CemiFrame. A CemiFrame has 2 additional bytes at the beginning. - * An additional byte is added to a standard frame, as this still has to be converted into an extendend. - */ - uint16_t cemiSize() - { - return fullSize() + (isExtended() ? 2 : 3) - 1; // -1 without CRC - } - - /** - * Creates a buffer and converts the TpFrame into a CemiFrame. - * Important: After processing (i.e. also after using the CemiFrame), the reference must be released manually. - */ - uint8_t* cemiData() - { - uint8_t* cemiBuffer = new uint8_t[cemiSize()]; - - // Das CEMI erwartet die Daten im Extended format inkl. zwei zusätzlicher Bytes am Anfang. - cemiBuffer[0] = 0x29; - cemiBuffer[1] = 0x0; - cemiBuffer[2] = _data[0]; - - if (isExtended()) + } + + /* + * Create a TpFrame with a reserved space. + * Used for incoming parsing. + */ + TpFrame(uint16_t maxSize = 263) + : _maxSize(maxSize) + { + _data = new uint8_t[_maxSize]; + _size = 0; + } + + /* + * Free the data area + */ + ~TpFrame() + { + delete[] _data; + } + + /* + * Add a byte at end. + * Used for incoming parsing. + */ + inline void addByte(uint8_t byte) + { + if (!isFull()) + { + _data[_size] = byte; + _size++; + } + + // Read meta data for flags + if (_size == 1) + presetFlags(); + } + + /* + * Current frame size. This may differ from the actual size as long as the frame is not complete. + */ + inline uint16_t size() const + { + return _size; + } + + /* + * Returns the assigned flags + */ + inline uint16_t flags() const + { + return _flags; + } + + /* + * Adds one or more flags + */ + inline void addFlags(uint8_t flags) + { + _flags |= flags; + } + + /* + * Returns a pointer to the data + */ + inline const uint8_t* data() const { - memcpy(cemiBuffer + 2, _data, fullSize() - 1); // -1 without CRC + return _data; } - else + + /* + * Returns the byte corresponding to the specified position + */ + inline uint8_t data(uint16_t pos) + { + return _data[pos]; + } + + /* + * Resets the internal values to refill the frame. + */ + inline void reset() { - cemiBuffer[3] = _data[5] & 0xF0; - memcpy(cemiBuffer + 4, _data + 1, 4); - cemiBuffer[8] = _data[5] & 0x0F; - memcpy(cemiBuffer + 9, _data + 6, cemiBuffer[8] + 2 - 1); // -1 without CRC + _size = 0; + _flags = 0; + // It is important to fill the _data with zeros so that the length is 0 as long as the value has not yet been read in. + memset(_data, 0x0, _maxSize); } - return cemiBuffer; - } - - /* - * Checks whether the frame is complete and valid. - */ - inline bool isValid() - { - if (!isComplete()) - return false; - - uint8_t sum = 0; - const uint16_t s = fullSize() - 1; - - for (uint16_t i = 0; i < s; i++) - sum ^= _data[i]; - - return _data[s] == (uint8_t)~sum; - } - - /* - * Checks whether the frame is long enough to match the length specified in the frame - */ - inline bool isComplete() - { - return _size == fullSize(); - } - - inline bool isRepeated() - { - return !(_data[0] & 0b100000); - } - void printIt() const; -}; \ No newline at end of file + /* + * Checks whether the frame has been imported completely + */ + inline bool isFull() + { + return _size >= (_size >= 7 ? fullSize() : _maxSize); + } + + /* + * Returns is the frame exteneded or not + */ + inline bool isExtended() const + { + return (_data[0] & 0xD3) == 0x10; + } + + /* + * Returns the source + * Assumes that enough data has been imported. + */ + inline uint16_t source() const + { + return isExtended() ? (_data[2] << 8) + _data[3] : (_data[1] << 8) + _data[2]; + } + + /* + * Returns the destination + * Assumes that enough data has been imported. + */ + inline uint16_t destination() const + { + return isExtended() ? (_data[4] << 8) + _data[5] : (_data[3] << 8) + _data[4]; + } + + /* + * Returns the payload size (with checksum) + * Assumes that enough data has been imported. + */ + inline uint8_t payloadSize() + { + return isExtended() ? _data[6] : _data[5] & 0b1111; + } + + /* + * Returns the header size + */ + inline uint8_t headerSize() + { + return isExtended() ? 9 : 8; + } + + /* + * Returns the frame size based on header and payload size. + * Assumes that enough data has been imported. + */ + inline uint16_t fullSize() + { + return headerSize() + payloadSize(); + } + + /* + * Returns if the destination is a group address + * Assumes that enough data has been imported. + */ + inline bool isGroupAddress() const + { + return isExtended() ? (_data[1] >> 7) & 0b1 : (_data[5] >> 7) & 0b1; + } + + /* + * Calculates the size of a CemiFrame. A CemiFrame has 2 additional bytes at the beginning. + * An additional byte is added to a standard frame, as this still has to be converted into an extendend. + */ + uint16_t cemiSize() + { + return fullSize() + (isExtended() ? 2 : 3) - 1; // -1 without CRC + } + + /** + * Creates a buffer and converts the TpFrame into a CemiFrame. + * Important: After processing (i.e. also after using the CemiFrame), the reference must be released manually. + */ + uint8_t* cemiData() + { + uint8_t* cemiBuffer = new uint8_t[cemiSize()]; + + // Das CEMI erwartet die Daten im Extended format inkl. zwei zusätzlicher Bytes am Anfang. + cemiBuffer[0] = 0x29; + cemiBuffer[1] = 0x0; + cemiBuffer[2] = _data[0]; + + if (isExtended()) + { + memcpy(cemiBuffer + 2, _data, fullSize() - 1); // -1 without CRC + } + else + { + cemiBuffer[3] = _data[5] & 0xF0; + memcpy(cemiBuffer + 4, _data + 1, 4); + cemiBuffer[8] = _data[5] & 0x0F; + memcpy(cemiBuffer + 9, _data + 6, cemiBuffer[8] + 2 - 1); // -1 without CRC + } + + return cemiBuffer; + } + + /* + * Checks whether the frame is complete and valid. + */ + inline bool isValid() + { + if (!isComplete()) + return false; + + uint8_t sum = 0; + const uint16_t s = fullSize() - 1; + + for (uint16_t i = 0; i < s; i++) + sum ^= _data[i]; + + return _data[s] == (uint8_t)~sum; + } + + /* + * Checks whether the frame is long enough to match the length specified in the frame + */ + inline bool isComplete() + { + return _size == fullSize(); + } + + inline bool isRepeated() + { + return !(_data[0] & 0b100000); + } + void printIt() const; + }; +} \ No newline at end of file diff --git a/src/knx/tp/tpuart_data_link_layer.cpp b/src/knx/tp/tpuart_data_link_layer.cpp index 02542c2a..4a426578 100644 --- a/src/knx/tp/tpuart_data_link_layer.cpp +++ b/src/knx/tp/tpuart_data_link_layer.cpp @@ -107,1111 +107,1114 @@ #define ACR0_FLAG_TRIGEN 0x08 #define ACR0_FLAG_V20VCLIMIT 0x04 -enum +namespace Knx { - TX_IDLE, - TX_FRAME -}; - -enum -{ - // In this state, the system waits for new control commands. - RX_IDLE, - - // In this state, all bytes are regarded as bytes for a frame. - RX_FRAME, - - // In this state, all bytes are discarded - RX_INVALID, - - // Monitoring is still waiting for an ACk - RX_AWAITING_ACK -}; - -/* - * Processes all bytes. - */ -void __isr __time_critical_func(TpUartDataLinkLayer::processRx)(bool isr) -{ - if (!isrLock()) - return; - - /* - * Some platforms support the detection of whether the hardware buffer has overflowed. - * Theoretically, you could now discard the buffer, but then a valid frame may be lost. - * Therefore, only one piece of information is output later in the loop and byte processing "tries" to respond to it. - */ - if (_platform.overflowUart()) - _rxOverflow = true; + enum + { + TX_IDLE, + TX_FRAME + }; - // process data - while (_platform.uartAvailable()) + enum { - processRxByte(); - } + // In this state, the system waits for new control commands. + RX_IDLE, - isrUnlock(); -} + // In this state, all bytes are regarded as bytes for a frame. + RX_FRAME, -/* - * Processes 1 incoming byte (if available) - */ -void TpUartDataLinkLayer::processRxByte() -{ - int byte = _platform.readUart(); + // In this state, all bytes are discarded + RX_INVALID, - // RxBuffer empty - if (byte < 0) - return; + // Monitoring is still waiting for an ACk + RX_AWAITING_ACK + }; /* - * If I am in RX_INVALID mode - * and the last byte was processed more than 2ms ago (i.e. pause >2ms) - * and there are no more bytes in the buffer, - * then I can discard the INVALID state. + * Processes all bytes. */ - if (_rxState == RX_INVALID && (millis() - _rxLastTime) > 2 && !_platform.uartAvailable()) + void __isr __time_critical_func(TpUartDataLinkLayer::processRx)(bool isr) { - processRxFrameComplete(); - _rxState = RX_IDLE; - } + if (!isrLock()) + return; - if (_rxState == RX_INVALID) - { /* - * As soon as a frame has been processed invalidly or an unknown command arrives, the status changes to RX_INVALID. - * From now on I must assume that there has been a transmission error and the current bytes are invalid. - * The same applies if a HW overflow is detected. - * - * The time of the last frame is 3ms past and there is no more data in the buffer. (Is checked by me) - * - If the marker mode is active and a U_FRAME_END_IND has been detected correctly. (Checked here) - * - * Otherwise this section does nothing and thus discards the invalid bytes + * Some platforms support the detection of whether the hardware buffer has overflowed. + * Theoretically, you could now discard the buffer, but then a valid frame may be lost. + * Therefore, only one piece of information is output later in the loop and byte processing "tries" to respond to it. */ - if (markerMode()) + if (_platform.overflowUart()) + _rxOverflow = true; + + // process data + while (_platform.uartAvailable()) { - if (!_rxMarker && byte == U_FRAME_END_IND) - { - _rxMarker = true; - } - else if (_rxMarker && byte == U_FRAME_END_IND) - { - // double byte found so reset marker - no frame end - _rxMarker = false; - } - else if (_rxMarker) - { - // frame end found. -> RX_IDLE - _rxMarker = false; - _rxState = RX_IDLE; - } + processRxByte(); } + + isrUnlock(); } - else if (_rxState == RX_FRAME) - { - processRxFrameByte(byte); - } - else if ((byte & L_DATA_MASK) == L_DATA_STANDARD_IND || (byte & L_DATA_MASK) == L_DATA_EXTENDED_IND) - { - /* - * Process a previous frame if still available. This should normally only occur in the bus monitor because an ACK is also being waited for here - */ - processRxFrameComplete(); - _rxFrame->addByte(byte); - // Provoke invalid frames for tests - // if (millis() % 20 == 0) - // _rxFrame->addByte(0x1); + /* + * Processes 1 incoming byte (if available) + */ + void TpUartDataLinkLayer::processRxByte() + { + int byte = _platform.readUart(); - _rxMarker = false; - _rxState = RX_FRAME; + // RxBuffer empty + if (byte < 0) + return; /* - * Here an ack is set inital without Addressed. This is used if an Ack is still set from the previous frame, - * is set back. This happens if processing is delayed too much (e.g. because no DMA/IRQ is used). - * The ACK can be sent as often as required because it is only stored in the BCU and is only used / sent when required. - * - * Of course, you can only do this if you are not sending yourself, as you do not ACK your own frames. The BCU may ignore this, - * but I wanted to be on the safe side here. + * If I am in RX_INVALID mode + * and the last byte was processed more than 2ms ago (i.e. pause >2ms) + * and there are no more bytes in the buffer, + * then I can discard the INVALID state. */ - if (_txState == TX_IDLE) + if (_rxState == RX_INVALID && (millis() - _rxLastTime) > 2 && !_platform.uartAvailable()) { - _platform.writeUart(U_ACK_REQ); + processRxFrameComplete(); + _rxState = RX_IDLE; } - } - else - { - // The commands are evaluated here, if this has already happened. - if (byte == U_RESET_IND) + if (_rxState == RX_INVALID) { - // println("U_RESET_IND"); - } - else if ((byte & U_STATE_MASK) == U_STATE_IND) - { - _tpState |= (byte ^ U_STATE_MASK); -#ifndef NCN5120 /* - * Filter "Protocol errors" because this is set on other BCUs such as the Siements when the timing is not correct. - * Unfortunately, perfect timing is not possible, so this error must be ignored. Also has no known effects. + * As soon as a frame has been processed invalidly or an unknown command arrives, the status changes to RX_INVALID. + * From now on I must assume that there has been a transmission error and the current bytes are invalid. + * The same applies if a HW overflow is detected. + * + * The time of the last frame is 3ms past and there is no more data in the buffer. (Is checked by me) + * - If the marker mode is active and a U_FRAME_END_IND has been detected correctly. (Checked here) + * + * Otherwise this section does nothing and thus discards the invalid bytes */ - _tpState &= 0b11101000; -#endif - } - else if ((byte & U_CONFIGURE_MASK) == U_CONFIGURE_IND) - { - // println("U_CONFIGURE_IND"); + if (markerMode()) + { + if (!_rxMarker && byte == U_FRAME_END_IND) + { + _rxMarker = true; + } + else if (_rxMarker && byte == U_FRAME_END_IND) + { + // double byte found so reset marker - no frame end + _rxMarker = false; + } + else if (_rxMarker) + { + // frame end found. -> RX_IDLE + _rxMarker = false; + _rxState = RX_IDLE; + } + } } - else if (byte == U_STOP_MODE_IND) + else if (_rxState == RX_FRAME) { - // println("U_STOP_MODE_IND"); + processRxFrameByte(byte); } - else if ((byte & L_ACKN_MASK) == L_ACKN_IND) + else if ((byte & L_DATA_MASK) == L_DATA_STANDARD_IND || (byte & L_DATA_MASK) == L_DATA_EXTENDED_IND) { /* - * If a frame has not yet been closed and an Ack comes in. - * then set the ACK. + * Process a previous frame if still available. This should normally only occur in the bus monitor because an ACK is also being waited for here */ - if (_rxFrame->size() > 0) - { - if (!(byte & L_ACKN_BUSY_MASK)) - _rxFrame->addFlags(TP_FRAME_FLAG_ACK_BUSY); + processRxFrameComplete(); + _rxFrame->addByte(byte); - if (!(byte & L_ACKN_NACK_MASK)) - _rxFrame->addFlags(TP_FRAME_FLAG_ACK_NACK); + // Provoke invalid frames for tests + // if (millis() % 20 == 0) + // _rxFrame->addByte(0x1); - _rxFrame->addFlags(TP_FRAME_FLAG_ACK); - processRxFrameComplete(); - } + _rxMarker = false; + _rxState = RX_FRAME; - // println("L_ACKN_IND"); + /* + * Here an ack is set inital without Addressed. This is used if an Ack is still set from the previous frame, + * is set back. This happens if processing is delayed too much (e.g. because no DMA/IRQ is used). + * The ACK can be sent as often as required because it is only stored in the BCU and is only used / sent when required. + * + * Of course, you can only do this if you are not sending yourself, as you do not ACK your own frames. The BCU may ignore this, + * but I wanted to be on the safe side here. + */ + if (_txState == TX_IDLE) + { + _platform.writeUart(U_ACK_REQ); + } } - else if ((byte & L_DATA_CON_MASK) == L_DATA_CON) + else { - if (_txState == TX_FRAME) + // The commands are evaluated here, if this has already happened. + + if (byte == U_RESET_IND) + { + // println("U_RESET_IND"); + } + else if ((byte & U_STATE_MASK) == U_STATE_IND) + { + _tpState |= (byte ^ U_STATE_MASK); +#ifndef NCN5120 + /* + * Filter "Protocol errors" because this is set on other BCUs such as the Siements when the timing is not correct. + * Unfortunately, perfect timing is not possible, so this error must be ignored. Also has no known effects. + */ + _tpState &= 0b11101000; +#endif + } + else if ((byte & U_CONFIGURE_MASK) == U_CONFIGURE_IND) + { + // println("U_CONFIGURE_IND"); + } + else if (byte == U_STOP_MODE_IND) + { + // println("U_STOP_MODE_IND"); + } + else if ((byte & L_ACKN_MASK) == L_ACKN_IND) + { + /* + * If a frame has not yet been closed and an Ack comes in. + * then set the ACK. + */ + if (_rxFrame->size() > 0) + { + if (!(byte & L_ACKN_BUSY_MASK)) + _rxFrame->addFlags(TP_FRAME_FLAG_ACK_BUSY); + + if (!(byte & L_ACKN_NACK_MASK)) + _rxFrame->addFlags(TP_FRAME_FLAG_ACK_NACK); + + _rxFrame->addFlags(TP_FRAME_FLAG_ACK); + processRxFrameComplete(); + } + + // println("L_ACKN_IND"); + } + else if ((byte & L_DATA_CON_MASK) == L_DATA_CON) + { + if (_txState == TX_FRAME) + { + const bool success = ((byte ^ L_DATA_CON_MASK) >> 7); + processTxFrameComplete(success); + } + else + { + // This byte was not expected because nothing was sent. + _rxUnkownControlCounter++; + _rxState = RX_INVALID; + // println("L_DATA_CON"); + } + } + else if (byte == L_POLL_DATA_IND) + { + // println("L_POLL_DATA_IND"); + } + else if ((byte & U_FRAME_STATE_MASK) == U_FRAME_STATE_IND) { - const bool success = ((byte ^ L_DATA_CON_MASK) >> 7); - processTxFrameComplete(success); + // println("U_FRAME_STATE_IND"); } else { - // This byte was not expected because nothing was sent. _rxUnkownControlCounter++; + // print("Unknown Controlbyte: "); + // println(byte, HEX); _rxState = RX_INVALID; - // println("L_DATA_CON"); } } - else if (byte == L_POLL_DATA_IND) - { - // println("L_POLL_DATA_IND"); - } - else if ((byte & U_FRAME_STATE_MASK) == U_FRAME_STATE_IND) - { - // println("U_FRAME_STATE_IND"); - } - else - { - _rxUnkownControlCounter++; - // print("Unknown Controlbyte: "); - // println(byte, HEX); - _rxState = RX_INVALID; - } - } - _rxLastTime = millis(); -} - -/* - * Process incoming byte of a frame - */ -void TpUartDataLinkLayer::processRxFrameByte(uint8_t byte) -{ - /* - * If the maker is active, the first U_FRAME_END_IND must be ignored and a subsequent byte must be waited for. - * The subsequent byte is therefore decisive for how this byte is to be evaluated. - */ - if (markerMode() && (byte == U_FRAME_END_IND && !_rxMarker)) - { - _rxMarker = true; + _rxLastTime = millis(); } /* - * If the previous byte was a U_FRAME_END_IND and the new byte is a U_FRAME_STATE_IND, - * then the reception is cleanly completed and the frame can be processed. + * Process incoming byte of a frame */ - else if (_rxMarker && (byte & U_FRAME_STATE_MASK) == U_FRAME_STATE_IND) + void TpUartDataLinkLayer::processRxFrameByte(uint8_t byte) { - _rxMarker = false; - processRxFrameComplete(); - /* - * Set the status to RX_IDLE, as the marker ensures, - * that the frame has been processed successfully. Subsequent bytes are therefore clean again Control commands, - * even if the frame was discarded due to an invalid checksum (which would mean RX_INVAID) + * If the maker is active, the first U_FRAME_END_IND must be ignored and a subsequent byte must be waited for. + * The subsequent byte is therefore decisive for how this byte is to be evaluated. */ - _rxState = RX_IDLE; - } + if (markerMode() && (byte == U_FRAME_END_IND && !_rxMarker)) + { + _rxMarker = true; + } - /* - * This is a hypothetical case in which the frames are sent without markers even though marker mode is active. - * Here the current frame is processed and RX_INVALID is set, as the current byte is not processed. - * This case can occur if the marker mode is not supported by the TPUart (NCN51xx feature) but has been activated. - */ - else if (markerMode() && _rxFrame->isFull()) - { - processRxFrameComplete(); /* - * RX_INVALID because theoretically the frame could have been processed as valid. - * However, since the current byte has already been "started" to be processed, it is missing in the processing chain - * and therefore the subsequent bytes cannot be used. + * If the previous byte was a U_FRAME_END_IND and the new byte is a U_FRAME_STATE_IND, + * then the reception is cleanly completed and the frame can be processed. */ - _rxState = RX_INVALID; - } + else if (_rxMarker && (byte & U_FRAME_STATE_MASK) == U_FRAME_STATE_IND) + { + _rxMarker = false; + processRxFrameComplete(); - /* - * If marker mode is active, the byte should be processed normally. - * If marker mode is active, a U_FRAME_END_IND byte may only be processed if the previous byte was also a U_FRAME_END_IND. - */ - else if (!markerMode() || byte != U_FRAME_END_IND || (byte == U_FRAME_END_IND && _rxMarker)) - { - // Reset the marker if active - _rxMarker = false; - // Accept the byte - _rxFrame->addByte(byte); + /* + * Set the status to RX_IDLE, as the marker ensures, + * that the frame has been processed successfully. Subsequent bytes are therefore clean again Control commands, + * even if the frame was discarded due to an invalid checksum (which would mean RX_INVAID) + */ + _rxState = RX_IDLE; + } - // If the bus monitor has been started, no processing takes place - i.e. no ACKing - if (!_monitoring) + /* + * This is a hypothetical case in which the frames are sent without markers even though marker mode is active. + * Here the current frame is processed and RX_INVALID is set, as the current byte is not processed. + * This case can occur if the marker mode is not supported by the TPUart (NCN51xx feature) but has been activated. + */ + else if (markerMode() && _rxFrame->isFull()) { - // If more than 7 bytes are available, you can check whether the frame is intended for "me". - if (_rxFrame->size() == 7) - { - // Check whether I am responsible for the frame - TPAckType ack = _cb.isAckRequired(_rxFrame->destination(), _rxFrame->isGroupAddress()); + processRxFrameComplete(); + /* + * RX_INVALID because theoretically the frame could have been processed as valid. + * However, since the current byte has already been "started" to be processed, it is missing in the processing chain + * and therefore the subsequent bytes cannot be used. + */ + _rxState = RX_INVALID; + } - if (_forceAck || ack) - { - /* - * Save the responsibility that this frame is to be processed further. - * Since there is no extra function apart from the isAckRequired, this is initially treated the same. - * A later differentiation (possibly for router mode) must then be looked at. - */ + /* + * If marker mode is active, the byte should be processed normally. + * If marker mode is active, a U_FRAME_END_IND byte may only be processed if the previous byte was also a U_FRAME_END_IND. + */ + else if (!markerMode() || byte != U_FRAME_END_IND || (byte == U_FRAME_END_IND && _rxMarker)) + { + // Reset the marker if active + _rxMarker = false; + // Accept the byte + _rxFrame->addByte(byte); - _rxFrame->addFlags(TP_FRAME_FLAG_ADDRESSED); + // If the bus monitor has been started, no processing takes place - i.e. no ACKing + if (!_monitoring) + { + // If more than 7 bytes are available, you can check whether the frame is intended for "me". + if (_rxFrame->size() == 7) + { + // Check whether I am responsible for the frame + TPAckType ack = _cb.isAckRequired(_rxFrame->destination(), _rxFrame->isGroupAddress()); - // Of course, this is only allowed if I am not sending myself, as you cannot ACK your own frames - if (_txState == TX_IDLE) + if (_forceAck || ack) { - // Save that Acking should take place - _rxFrame->addFlags(TP_FRAME_FLAG_ACK); - - // and in the TPUart so that it can send the ACK - _platform.writeUart(U_ACK_REQ | ack); + /* + * Save the responsibility that this frame is to be processed further. + * Since there is no extra function apart from the isAckRequired, this is initially treated the same. + * A later differentiation (possibly for router mode) must then be looked at. + */ + + _rxFrame->addFlags(TP_FRAME_FLAG_ADDRESSED); + + // Of course, this is only allowed if I am not sending myself, as you cannot ACK your own frames + if (_txState == TX_IDLE) + { + // Save that Acking should take place + _rxFrame->addFlags(TP_FRAME_FLAG_ACK); + + // and in the TPUart so that it can send the ACK + _platform.writeUart(U_ACK_REQ | ack); + } } } - } #ifdef USE_TP_RX_QUEUE - // Now check whether the RxQueue still has space for Frame + Size (2) + Flags(1) - if (_rxFrame->size() == 8 && (_rxFrame->flags() & TP_FRAME_FLAG_ADDRESSED)) - { - if (availableInRxQueue() < (_rxFrame->size() + 3)) + // Now check whether the RxQueue still has space for Frame + Size (2) + Flags(1) + if (_rxFrame->size() == 8 && (_rxFrame->flags() & TP_FRAME_FLAG_ADDRESSED)) { - // Only if I am not sending myself - if (_txState == TX_IDLE) + if (availableInRxQueue() < (_rxFrame->size() + 3)) { - _platform.writeUart(U_ACK_REQ | U_ACK_REQ_ADRESSED | U_ACK_REQ_BUSY); + // Only if I am not sending myself + if (_txState == TX_IDLE) + { + _platform.writeUart(U_ACK_REQ | U_ACK_REQ_ADRESSED | U_ACK_REQ_BUSY); + } } } - } #endif + } + } + + /* + * If no marker mode is active, the frame must be checked to see if it is complete. + * isFull checks here whether the maxSize or the length specification of the frame has been exceeded! + * In both cases, the frame must be processed. + */ + if (!markerMode() && (_rxFrame->isFull())) + { + processRxFrameComplete(); } } /* - * If no marker mode is active, the frame must be checked to see if it is complete. - * isFull checks here whether the maxSize or the length specification of the frame has been exceeded! - * In both cases, the frame must be processed. + * Processes the current frame and checks whether it is complete and valid (checksum). + * If a frame is complete and valid, it is placed in the queue if it is intended for "me" and the mode is RX_IDLE again. + * Otherwise the frame is discarded as invalid and the status is RX_INVALID, as it is not guaranteed that subsequent bytes are control codes again. + * Exception in marker mode, here the status RX_INVALID is changed directly back to RX_IDLE at another point because + * it is then ensured that the frame has been broken at TP level. */ - if (!markerMode() && (_rxFrame->isFull())) + void TpUartDataLinkLayer::processRxFrameComplete() { - processRxFrameComplete(); - } -} - -/* - * Processes the current frame and checks whether it is complete and valid (checksum). - * If a frame is complete and valid, it is placed in the queue if it is intended for "me" and the mode is RX_IDLE again. - * Otherwise the frame is discarded as invalid and the status is RX_INVALID, as it is not guaranteed that subsequent bytes are control codes again. - * Exception in marker mode, here the status RX_INVALID is changed directly back to RX_IDLE at another point because - * it is then ensured that the frame has been broken at TP level. - */ -void TpUartDataLinkLayer::processRxFrameComplete() -{ - // If no frame is currently being edited, then cancel - if (!_rxFrame->size()) - return; + // If no frame is currently being edited, then cancel + if (!_rxFrame->size()) + return; - // Is the frame complete and valid - if (_rxFrame->isValid()) - { - // When a frame has been sent - if (_txState == TX_FRAME) + // Is the frame complete and valid + if (_rxFrame->isValid()) { - // check whether the receive corresponds to this: comparison of the source address and destination address and start byte without taking the retry bit into account - if (!((_rxFrame->data(0) ^ _txFrame->data(0)) & ~0x20) && _rxFrame->destination() == _txFrame->destination() && _rxFrame->source() == _txFrame->source()) + // When a frame has been sent + if (_txState == TX_FRAME) { - // and mark this accordingly - // println("MATCH"); - _rxFrame->addFlags(TP_FRAME_FLAG_ECHO); + // check whether the receive corresponds to this: comparison of the source address and destination address and start byte without taking the retry bit into account + if (!((_rxFrame->data(0) ^ _txFrame->data(0)) & ~0x20) && _rxFrame->destination() == _txFrame->destination() && _rxFrame->source() == _txFrame->source()) + { + // and mark this accordingly + // println("MATCH"); + _rxFrame->addFlags(TP_FRAME_FLAG_ECHO); + } + + // Now wait for the L_DATA_CON } - // Now wait for the L_DATA_CON - } + // if the frame is for me or i am in busmonitor mode then i want to process it further + if (_rxFrame->flags() & TP_FRAME_FLAG_ADDRESSED || _monitoring) + { + /* + * In bus monitor mode, you still have to wait for an Ack. + * Therefore, the status is changed here and jumps back before the real completion. + * As soon as another call is made (regardless of whether or not the frame has been acked), the frame is closed. + */ + if (_monitoring && _rxState != RX_AWAITING_ACK) + { + _rxState = RX_AWAITING_ACK; + return; + } - // if the frame is for me or i am in busmonitor mode then i want to process it further - if (_rxFrame->flags() & TP_FRAME_FLAG_ADDRESSED || _monitoring) - { - /* - * In bus monitor mode, you still have to wait for an Ack. - * Therefore, the status is changed here and jumps back before the real completion. - * As soon as another call is made (regardless of whether or not the frame has been acked), the frame is closed. - */ - if (_monitoring && _rxState != RX_AWAITING_ACK) + _rxProcessdFrameCounter++; + } + else { - _rxState = RX_AWAITING_ACK; - return; + // Otherwise, discard the package and release the memory -> as it is not packed into the queue + _rxIgnoredFrameCounter++; } - _rxProcessdFrameCounter++; + // And ready for control codes again + _rxState = RX_IDLE; } else { - // Otherwise, discard the package and release the memory -> as it is not packed into the queue - _rxIgnoredFrameCounter++; + /* + * If the frame is incomplete or invalid then switch to RX_INVALID mode as I cannot distinguish, + * whether it is a TPBus error or a UART error or a Timming error. + */ + _rxInvalidFrameCounter++; + _rxFrame->addFlags(TP_FRAME_FLAG_INVALID); + _rxState = RX_INVALID; // ignore bytes } - // And ready for control codes again - _rxState = RX_IDLE; - } - else - { - /* - * If the frame is incomplete or invalid then switch to RX_INVALID mode as I cannot distinguish, - * whether it is a TPBus error or a UART error or a Timming error. - */ - _rxInvalidFrameCounter++; - _rxFrame->addFlags(TP_FRAME_FLAG_INVALID); - _rxState = RX_INVALID; // ignore bytes - } - #ifdef USE_TP_RX_QUEUE - pushRxFrameQueue(); + pushRxFrameQueue(); #else - processRxFrame(_rxFrame); + processRxFrame(_rxFrame); #endif - // resets the current frame pointer - _rxFrame->reset(); -} + // resets the current frame pointer + _rxFrame->reset(); + } -void TpUartDataLinkLayer::clearTxFrame() -{ - if (_txFrame != nullptr) + void TpUartDataLinkLayer::clearTxFrame() { - delete _txFrame; - _txFrame = nullptr; + 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); - delete[] cemiData; - clearTxFrame(); - _txProcessdFrameCounter++; - _txState = TX_IDLE; -} - -/* - * Puts the frame to be sent into a queue, as the TpUart may not yet be ready to send. - */ -void TpUartDataLinkLayer::pushTxFrameQueue(TpFrame* tpFrame) -{ - knx_tx_queue_entry_t* entry = new knx_tx_queue_entry_t(tpFrame); - if (_txFrameQueue.back == nullptr) + void TpUartDataLinkLayer::clearTxFrameQueue() { - _txFrameQueue.front = _txFrameQueue.back = entry; } - else + + void TpUartDataLinkLayer::processTxFrameComplete(bool success) { - _txFrameQueue.back->next = entry; - _txFrameQueue.back = entry; + uint8_t* cemiData = _txFrame->cemiData(); + CemiFrame cemiFrame(cemiData, _txFrame->cemiSize()); + dataConReceived(cemiFrame, success); + delete[] cemiData; + clearTxFrame(); + _txProcessdFrameCounter++; + _txState = TX_IDLE; } - _txQueueCount++; -} + /* + * Puts the frame to be sent into a queue, as the TpUart may not yet be ready to send. + */ + void TpUartDataLinkLayer::pushTxFrameQueue(TpFrame* tpFrame) + { + knx_tx_queue_entry_t* entry = new knx_tx_queue_entry_t(tpFrame); -void TpUartDataLinkLayer::setRepetitions(uint8_t nack, uint8_t busy) -{ - _repetitions = (nack & 0b111) | ((busy & 0b111) << 4); -} + if (_txFrameQueue.back == nullptr) + { + _txFrameQueue.front = _txFrameQueue.back = entry; + } + else + { + _txFrameQueue.back->next = entry; + _txFrameQueue.back = entry; + } -// Alias -void TpUartDataLinkLayer::setFrameRepetition(uint8_t nack, uint8_t busy) -{ - setRepetitions(nack, busy); -} + _txQueueCount++; + } -bool TpUartDataLinkLayer::sendFrame(CemiFrame& cemiFrame) -{ - _txFrameCounter++; + void TpUartDataLinkLayer::setRepetitions(uint8_t nack, uint8_t busy) + { + _repetitions = (nack & 0b111) | ((busy & 0b111) << 4); + } + + // Alias + void TpUartDataLinkLayer::setFrameRepetition(uint8_t nack, uint8_t busy) + { + setRepetitions(nack, busy); + } - if (!_connected || _monitoring || _txQueueCount > MAX_TX_QUEUE) + bool TpUartDataLinkLayer::sendFrame(CemiFrame& cemiFrame) { - if (_txQueueCount > MAX_TX_QUEUE) + _txFrameCounter++; + + if (!_connected || _monitoring || _txQueueCount > MAX_TX_QUEUE) { - println("Ignore frame because transmit queue is full!"); + if (_txQueueCount > MAX_TX_QUEUE) + { + println("Ignore frame because transmit queue is full!"); + } + + dataConReceived(cemiFrame, false); + return false; } - dataConReceived(cemiFrame, false); - return false; + TpFrame* tpFrame = new TpFrame(cemiFrame); + // printHex(" TP>: ", tpFrame->data(), tpFrame->size()); + pushTxFrameQueue(tpFrame); + return true; } - TpFrame* tpFrame = new TpFrame(cemiFrame); - // printHex(" TP>: ", tpFrame->data(), tpFrame->size()); - pushTxFrameQueue(tpFrame); - return true; -} - -/* - * The status should be queried regularly to detect a disconnect of the TPUart and its status. - * In addition, the current config or mode should be transmitted regularly so that after a disconnect, - * the TPUart is in the correct state. - */ -void TpUartDataLinkLayer::requestState(bool force /* = false */) -{ - if (!force) + /* + * The status should be queried regularly to detect a disconnect of the TPUart and its status. + * In addition, the current config or mode should be transmitted regularly so that after a disconnect, + * the TPUart is in the correct state. + */ + void TpUartDataLinkLayer::requestState(bool force /* = false */) { - if (!(_rxState == RX_IDLE || _rxState == RX_INVALID)) - return; + if (!force) + { + if (!(_rxState == RX_IDLE || _rxState == RX_INVALID)) + return; - // Only 1x per second - if ((millis() - _lastStateRequest) < 1000) - return; - } + // Only 1x per second + if ((millis() - _lastStateRequest) < 1000) + return; + } - // println("requestState"); + // println("requestState"); - // Send configuration or mode - if (_monitoring) - _platform.writeUart(U_BUSMON_REQ); - else - requestConfig(); + // Send configuration or mode + if (_monitoring) + _platform.writeUart(U_BUSMON_REQ); + else + requestConfig(); - // Question status on - if monitoring inactive - if (!_monitoring) - _platform.writeUart(U_STATE_REQ); + // Question status on - if monitoring inactive + if (!_monitoring) + _platform.writeUart(U_STATE_REQ); - _lastStateRequest = millis(); -} + _lastStateRequest = millis(); + } -/* - * Sends the current config to the chip - */ -void TpUartDataLinkLayer::requestConfig() -{ - // println("requestConfig"); + /* + * Sends the current config to the chip + */ + void TpUartDataLinkLayer::requestConfig() + { + // println("requestConfig"); #ifdef NCN5120 - if (markerMode()) - _platform.writeUart(U_CONFIGURE_REQ | U_CONFIGURE_MARKER_REQ); + if (markerMode()) + _platform.writeUart(U_CONFIGURE_REQ | U_CONFIGURE_MARKER_REQ); #endif - // Deviating Config - if (_repetitions != 0b00110011) - { + // Deviating Config + if (_repetitions != 0b00110011) + { #ifdef NCN5120 - _platform.writeUart(U_SET_REPETITION_REQ); - _platform.writeUart(_repetitions); - _platform.writeUart(0x0); // dummy, see NCN5120 datasheet - _platform.writeUart(0x0); // dummy, see NCN5120 datasheet + _platform.writeUart(U_SET_REPETITION_REQ); + _platform.writeUart(_repetitions); + _platform.writeUart(0x0); // dummy, see NCN5120 datasheet + _platform.writeUart(0x0); // dummy, see NCN5120 datasheet #else - _platform.writeUart(U_MXRSTCNT); - _platform.writeUart(((_repetitions & 0xF0) << 1) | (_repetitions & 0x0F)); + _platform.writeUart(U_MXRSTCNT); + _platform.writeUart(((_repetitions & 0xF0) << 1) | (_repetitions & 0x0F)); #endif + } } -} -/* - * A simplified lock mechanism that only works on the same core. - * Perfect for ISR - */ -bool TpUartDataLinkLayer::isrLock(bool blocking /* = false */) -{ - if (blocking) - while (_rxProcessing) - ; - else if (_rxProcessing) - return false; - - _rxProcessing = true; - return true; -} + /* + * A simplified lock mechanism that only works on the same core. + * Perfect for ISR + */ + bool TpUartDataLinkLayer::isrLock(bool blocking /* = false */) + { + if (blocking) + while (_rxProcessing) + ; + else if (_rxProcessing) + return false; + + _rxProcessing = true; + return true; + } -void TpUartDataLinkLayer::isrUnlock() -{ - _rxProcessing = false; -} + void TpUartDataLinkLayer::isrUnlock() + { + _rxProcessing = false; + } -void TpUartDataLinkLayer::clearUartBuffer() -{ - // Clear rx queue - while (_platform.uartAvailable()) - _platform.readUart(); -} + void TpUartDataLinkLayer::clearUartBuffer() + { + // Clear rx queue + while (_platform.uartAvailable()) + _platform.readUart(); + } -void TpUartDataLinkLayer::connected(bool state /* = true */) -{ - if (state) - println("TP is connected"); - else - println("TP is disconnected"); + void TpUartDataLinkLayer::connected(bool state /* = true */) + { + if (state) + println("TP is connected"); + else + println("TP is disconnected"); - _connected = state; -} + _connected = state; + } -void TpUartDataLinkLayer::resetStats() -{ - _rxProcessdFrameCounter = 0; - _rxIgnoredFrameCounter = 0; - _rxInvalidFrameCounter = 0; - _rxInvalidFrameCounter = 0; - _rxUnkownControlCounter = 0; - _txFrameCounter = 0; - _txProcessdFrameCounter = 0; -} - -bool TpUartDataLinkLayer::reset() -{ - // println("Reset TP"); - if (!_initialized) + void TpUartDataLinkLayer::resetStats() { - _platform.setupUart(); - _initialized = true; + _rxProcessdFrameCounter = 0; + _rxIgnoredFrameCounter = 0; + _rxInvalidFrameCounter = 0; + _rxInvalidFrameCounter = 0; + _rxUnkownControlCounter = 0; + _txFrameCounter = 0; + _txProcessdFrameCounter = 0; } - // Wait for isr & block isr - isrLock(true); + bool TpUartDataLinkLayer::reset() + { + // println("Reset TP"); + if (!_initialized) + { + _platform.setupUart(); + _initialized = true; + } - // Reset - resetStats(); - clearTxFrame(); - clearTxFrameQueue(); + // Wait for isr & block isr + isrLock(true); - if (_rxFrame != nullptr) - { - _rxFrame->reset(); - } + // Reset + resetStats(); + clearTxFrame(); + clearTxFrameQueue(); + + if (_rxFrame != nullptr) + { + _rxFrame->reset(); + } - _rxState = RX_IDLE; - _connected = false; - _stopped = false; - _monitoring = false; - _rxLastTime = 0; + _rxState = RX_IDLE; + _connected = false; + _stopped = false; + _monitoring = false; + _rxLastTime = 0; - clearUartBuffer(); + clearUartBuffer(); - _platform.writeUart(U_RESET_REQ); - bool success = false; + _platform.writeUart(U_RESET_REQ); + bool success = false; - const uint32_t start = millis(); + const uint32_t start = millis(); - // During startup answer took up to 2ms and normal 1ms - do - { - const int byte = _platform.readUart(); + // During startup answer took up to 2ms and normal 1ms + do + { + const int byte = _platform.readUart(); + + if (byte == -1) + continue; // empty + + if (byte & U_RESET_IND) + { + success = true; + break; // next run for U_CONFIGURE_IND + } + } while (!((millis() - start) >= 10)); - if (byte == -1) - continue; // empty + connected(success); - if (byte & U_RESET_IND) + if (success) { - success = true; - break; // next run for U_CONFIGURE_IND + _lastStateRequest = 0; // Force + requestState(true); + _rxLastTime = millis(); } - } while (!((millis() - start) >= 10)); - connected(success); + isrUnlock(); + return success; + } - if (success) + void TpUartDataLinkLayer::forceAck(bool state) { - _lastStateRequest = 0; // Force - requestState(true); - _rxLastTime = millis(); + _forceAck = true; } - isrUnlock(); - return success; -} - -void TpUartDataLinkLayer::forceAck(bool state) -{ - _forceAck = true; -} - -void TpUartDataLinkLayer::stop(bool state) -{ - if (!_initialized) - return; - - if (state && !_stopped) - _platform.writeUart(U_STOP_MODE_REQ); - else if (!state && _stopped) - _platform.writeUart(U_EXIT_STOP_MODE_REQ); + void TpUartDataLinkLayer::stop(bool state) + { + if (!_initialized) + return; - _stopped = state; -} + if (state && !_stopped) + _platform.writeUart(U_STOP_MODE_REQ); + else if (!state && _stopped) + _platform.writeUart(U_EXIT_STOP_MODE_REQ); -void TpUartDataLinkLayer::requestBusy(bool state) -{ - if (state && !_busy) - _platform.writeUart(U_SET_BUSY_REQ); - else if (!state && _busy) - _platform.writeUart(U_QUIT_BUSY_REQ); + _stopped = state; + } - _busy = state; -} + void TpUartDataLinkLayer::requestBusy(bool state) + { + if (state && !_busy) + _platform.writeUart(U_SET_BUSY_REQ); + else if (!state && _busy) + _platform.writeUart(U_QUIT_BUSY_REQ); -void TpUartDataLinkLayer::monitor() -{ - if (!_initialized || _monitoring) - return; + _busy = state; + } - // println("busmonitor"); - _monitoring = true; - _platform.writeUart(U_BUSMON_REQ); - resetStats(); -} + void TpUartDataLinkLayer::monitor() + { + if (!_initialized || _monitoring) + return; -void TpUartDataLinkLayer::enabled(bool value) -{ - // After an unusual device restart, perform a reset, as the TPUart may still be in an incorrect state. - if (!_initialized) - reset(); + // println("busmonitor"); + _monitoring = true; + _platform.writeUart(U_BUSMON_REQ); + resetStats(); + } - stop(!value); -} + void TpUartDataLinkLayer::enabled(bool value) + { + // After an unusual device restart, perform a reset, as the TPUart may still be in an incorrect state. + if (!_initialized) + reset(); -bool TpUartDataLinkLayer::enabled() const -{ - return _initialized && _connected; -} + stop(!value); + } -/* - * If a TxFrame has been sent, a confirmation for the transmission is expected. - * However, if there was an invalid frame or bus disconnect, the confirmation is not received and the STack is stuck in the TX_FRAME. - * The wait must therefore be ended after a short waiting time. - */ -void TpUartDataLinkLayer::clearOutdatedTxFrame() -{ - if (_txState == TX_FRAME && (millis() - _txLastTime) > 1000) - processTxFrameComplete(false); -} + bool TpUartDataLinkLayer::enabled() const + { + return _initialized && _connected; + } -/* - * Here the outgoing frames are taken from the queue and sent. - * This only happens one at a time, as after each frame it is necessary to wait until the frame has come in again and the L_DATA_CON comes in. - * - */ -void TpUartDataLinkLayer::processTxQueue() -{ - if (_txState != TX_IDLE) - return; + /* + * If a TxFrame has been sent, a confirmation for the transmission is expected. + * However, if there was an invalid frame or bus disconnect, the confirmation is not received and the STack is stuck in the TX_FRAME. + * The wait must therefore be ended after a short waiting time. + */ + void TpUartDataLinkLayer::clearOutdatedTxFrame() + { + if (_txState == TX_FRAME && (millis() - _txLastTime) > 1000) + processTxFrameComplete(false); + } - if (_txFrameQueue.front != nullptr) + /* + * Here the outgoing frames are taken from the queue and sent. + * This only happens one at a time, as after each frame it is necessary to wait until the frame has come in again and the L_DATA_CON comes in. + * + */ + void TpUartDataLinkLayer::processTxQueue() { - knx_tx_queue_entry_t* entry = _txFrameQueue.front; - _txFrameQueue.front = entry->next; + if (_txState != TX_IDLE) + return; - if (_txFrameQueue.front == nullptr) + if (_txFrameQueue.front != nullptr) { - _txFrameQueue.back = nullptr; - } + knx_tx_queue_entry_t* entry = _txFrameQueue.front; + _txFrameQueue.front = entry->next; + + if (_txFrameQueue.front == nullptr) + { + _txFrameQueue.back = nullptr; + } - _txQueueCount--; + _txQueueCount--; - clearTxFrame(); + clearTxFrame(); - // use frame from queue and delete queue entry - _txFrame = entry->frame; - delete entry; + // use frame from queue and delete queue entry + _txFrame = entry->frame; + delete entry; - _txState = TX_FRAME; - _txLastTime = millis(); + _txState = TX_FRAME; + _txLastTime = millis(); #ifdef DEBUG_TP_FRAMES - print("Outbound: "); - _txFrame.printIt(); - println(); + print("Outbound: "); + _txFrame.printIt(); + println(); #endif - processTxFrameBytes(); + processTxFrameBytes(); + } } -} -/* - * Check whether I have not received any data for too long and set the status to not connected. - * In normal mode, the status is requested every second. A short time can therefore be selected here. - * In monitoring mode there are actual frames, so a longer time is used here. - * Nevertheless, there are suspected disconnects with larger data volumes, so the RxQueue is also taken into account. - */ -void TpUartDataLinkLayer::checkConnected() -{ - if (!isrLock()) - return; + /* + * Check whether I have not received any data for too long and set the status to not connected. + * In normal mode, the status is requested every second. A short time can therefore be selected here. + * In monitoring mode there are actual frames, so a longer time is used here. + * Nevertheless, there are suspected disconnects with larger data volumes, so the RxQueue is also taken into account. + */ + void TpUartDataLinkLayer::checkConnected() + { + if (!isrLock()) + return; - const uint32_t current = millis(); + const uint32_t current = millis(); - if (_connected) - { - // 5000 instead 3000 because siemens tpuart - const uint32_t timeout = _monitoring ? 10000 : 5000; + if (_connected) + { + // 5000 instead 3000 because siemens tpuart + const uint32_t timeout = _monitoring ? 10000 : 5000; - if ((current - _rxLastTime) > timeout) + if ((current - _rxLastTime) > timeout) + { + connected(false); + } + } + else { - connected(false); + if (_rxLastTime > 0 && (current - _rxLastTime) < 1000) + connected(); } - } - else - { - if (_rxLastTime > 0 && (current - _rxLastTime) < 1000) - connected(); - } - - isrUnlock(); -} -void TpUartDataLinkLayer::loop() -{ - if (!_initialized) - return; - - /* - * If an overflow has been detected, change to RX_INVALID. - * However, this only applies in the loop and not in ISR. But when using ISR and DMA, this should never happen. - */ - if (_rxOverflow) - { - println("TPUart overflow detected!"); - _rxOverflow = false; - _rxState = RX_INVALID; + isrUnlock(); } - if (_tpState) + void TpUartDataLinkLayer::loop() { - print("TPUart state error: "); - println(_tpState, 2); - _tpState = 0; - } + if (!_initialized) + return; + + /* + * If an overflow has been detected, change to RX_INVALID. + * However, this only applies in the loop and not in ISR. But when using ISR and DMA, this should never happen. + */ + if (_rxOverflow) + { + println("TPUart overflow detected!"); + _rxOverflow = false; + _rxState = RX_INVALID; + } + + if (_tpState) + { + print("TPUart state error: "); + println(_tpState, 2); + _tpState = 0; + } - processRx(); + processRx(); #ifdef USE_TP_RX_QUEUE - processRxQueue(); + processRxQueue(); #endif - requestState(); - clearOutdatedTxFrame(); - processTxQueue(); - checkConnected(); -} + requestState(); + clearOutdatedTxFrame(); + processTxQueue(); + checkConnected(); + } -void TpUartDataLinkLayer::rxFrameReceived(TpFrame* tpFrame) -{ - uint8_t* cemiData = tpFrame->cemiData(); - CemiFrame cemiFrame(cemiData, tpFrame->cemiSize()); - // printHex(" TP<: ", tpFrame->data(), tpFrame->size()); - // printHex(" CEMI<: ", cemiFrame.data(), cemiFrame.dataLength()); + void TpUartDataLinkLayer::rxFrameReceived(TpFrame* tpFrame) + { + uint8_t* cemiData = tpFrame->cemiData(); + CemiFrame cemiFrame(cemiData, tpFrame->cemiSize()); + // printHex(" TP<: ", tpFrame->data(), tpFrame->size()); + // printHex(" CEMI<: ", cemiFrame.data(), cemiFrame.dataLength()); #ifdef KNX_ACTIVITYCALLBACK - if (_dllcb) - _dllcb->activity((_netIndex << KNX_ACTIVITYCALLBACK_NET) | (KNX_ACTIVITYCALLBACK_DIR_RECV << KNX_ACTIVITYCALLBACK_DIR)); + if (_dllcb) + _dllcb->activity((_netIndex << KNX_ACTIVITYCALLBACK_NET) | (KNX_ACTIVITYCALLBACK_DIR_RECV << KNX_ACTIVITYCALLBACK_DIR)); #endif - frameReceived(cemiFrame); - delete[] cemiData; -} + frameReceived(cemiFrame); + delete[] cemiData; + } -DptMedium TpUartDataLinkLayer::mediumType() const -{ - return DptMedium::KNX_TP1; -} + DptMedium TpUartDataLinkLayer::mediumType() const + { + return DptMedium::KNX_TP1; + } -/* - * This can be used to switch the power supply to the V20V (VCC2) - */ + /* + * This can be used to switch the power supply to the V20V (VCC2) + */ #ifdef NCN5120 -void TpUartDataLinkLayer::powerControl(bool state) -{ - _platform.writeUart(U_INT_REG_WR_REQ_ACR0); + void TpUartDataLinkLayer::powerControl(bool state) + { + _platform.writeUart(U_INT_REG_WR_REQ_ACR0); - if (state) - _platform.writeUart(ACR0_FLAG_DC2EN | ACR0_FLAG_V20VEN | ACR0_FLAG_XCLKEN | ACR0_FLAG_V20VCLIMIT); - else - _platform.writeUart(ACR0_FLAG_XCLKEN | ACR0_FLAG_V20VCLIMIT); -} + if (state) + _platform.writeUart(ACR0_FLAG_DC2EN | ACR0_FLAG_V20VEN | ACR0_FLAG_XCLKEN | ACR0_FLAG_V20VCLIMIT); + else + _platform.writeUart(ACR0_FLAG_XCLKEN | ACR0_FLAG_V20VCLIMIT); + } #endif -bool TpUartDataLinkLayer::processTxFrameBytes() -{ - // println("processTxFrameBytes"); - - /* - * Each frame must be introduced with a U_L_DATA_START_REQ and each subsequent byte with a further position byte (6bit). - * Since the position byte consists of the U_L_DATA_START_REQ + position and we start with 0 anyway, a further distinction is not necessary. - * distinction is not necessary. - * - * However, the last byte (checksum) uses the U_L_DATA_END_REQ + position! - * In addition, there is another special feature for extended frames up to 263 bytes long, the 6 bits are no longer sufficient. - * Here a U_L_DATA_OFFSET_REQ + Position (3bit) must be prefixed. This means that 9 bits are available for the position. - */ - for (uint16_t i = 0; i < _txFrame->size(); i++) + bool TpUartDataLinkLayer::processTxFrameBytes() { - uint8_t offset = (i >> 6); - uint8_t position = (i & 0x3F); + // println("processTxFrameBytes"); - if (offset) + /* + * Each frame must be introduced with a U_L_DATA_START_REQ and each subsequent byte with a further position byte (6bit). + * Since the position byte consists of the U_L_DATA_START_REQ + position and we start with 0 anyway, a further distinction is not necessary. + * distinction is not necessary. + * + * However, the last byte (checksum) uses the U_L_DATA_END_REQ + position! + * In addition, there is another special feature for extended frames up to 263 bytes long, the 6 bits are no longer sufficient. + * Here a U_L_DATA_OFFSET_REQ + Position (3bit) must be prefixed. This means that 9 bits are available for the position. + */ + for (uint16_t i = 0; i < _txFrame->size(); i++) { - // position++; - _platform.writeUart(U_L_DATA_OFFSET_REQ | offset); - } + uint8_t offset = (i >> 6); + uint8_t position = (i & 0x3F); - if (i == (_txFrame->size() - 1)) // Last bytes (checksum) - _platform.writeUart(U_L_DATA_END_REQ | position); - else - _platform.writeUart(U_L_DATA_START_REQ | position); + if (offset) + { + // position++; + _platform.writeUart(U_L_DATA_OFFSET_REQ | offset); + } - _platform.writeUart(_txFrame->data(i)); - } + if (i == (_txFrame->size() - 1)) // Last bytes (checksum) + _platform.writeUart(U_L_DATA_END_REQ | position); + else + _platform.writeUart(U_L_DATA_START_REQ | position); + + _platform.writeUart(_txFrame->data(i)); + } #ifdef KNX_ACTIVITYCALLBACK - if (_dllcb) - _dllcb->activity((_netIndex << KNX_ACTIVITYCALLBACK_NET) | (KNX_ACTIVITYCALLBACK_DIR_SEND << KNX_ACTIVITYCALLBACK_DIR)); + if (_dllcb) + _dllcb->activity((_netIndex << KNX_ACTIVITYCALLBACK_NET) | (KNX_ACTIVITYCALLBACK_DIR_SEND << KNX_ACTIVITYCALLBACK_DIR)); #endif - return true; -} - -TpUartDataLinkLayer::TpUartDataLinkLayer(DeviceObject& devObj, - NetworkLayerEntity& netLayerEntity, - Platform& platform, - ITpUartCallBacks& cb, - DataLinkLayerCallbacks* dllcb) - : DataLinkLayer(devObj, netLayerEntity, platform), - _cb(cb), - _dllcb(dllcb) -{ - _rxFrame = new TpFrame(MAX_KNX_TELEGRAM_SIZE); -} + return true; + } -/* - * Returns the number of frames that could not be processed. - */ -uint32_t TpUartDataLinkLayer::getRxInvalidFrameCounter() -{ - return _rxInvalidFrameCounter; -} + TpUartDataLinkLayer::TpUartDataLinkLayer(DeviceObject& devObj, + NetworkLayerEntity& netLayerEntity, + Platform& platform, + ITpUartCallBacks& cb, + DataLinkLayerCallbacks* dllcb) + : DataLinkLayer(devObj, netLayerEntity, platform), + _cb(cb), + _dllcb(dllcb) + { + _rxFrame = new TpFrame(MAX_KNX_TELEGRAM_SIZE); + } -/* - * Returns the number of frames that are valid and intended for the device - */ -uint32_t TpUartDataLinkLayer::getRxProcessdFrameCounter() -{ - return _rxProcessdFrameCounter; -} + /* + * Returns the number of frames that could not be processed. + */ + uint32_t TpUartDataLinkLayer::getRxInvalidFrameCounter() + { + return _rxInvalidFrameCounter; + } -/* - * Returns the number of frames that are valid but not intended for the device - */ -uint32_t TpUartDataLinkLayer::getRxIgnoredFrameCounter() -{ - return _rxIgnoredFrameCounter; -} + /* + * Returns the number of frames that are valid and intended for the device + */ + uint32_t TpUartDataLinkLayer::getRxProcessdFrameCounter() + { + return _rxProcessdFrameCounter; + } -/* - * Returns the number of control bytes counted that were not recognized - */ -uint32_t TpUartDataLinkLayer::getRxUnknownControlCounter() -{ - return _rxUnkownControlCounter; -} + /* + * Returns the number of frames that are valid but not intended for the device + */ + uint32_t TpUartDataLinkLayer::getRxIgnoredFrameCounter() + { + return _rxIgnoredFrameCounter; + } -/* - * Returns the number of frames sent - */ -uint32_t TpUartDataLinkLayer::getTxFrameCounter() -{ - return _txFrameCounter; -} -/* - * Returns the number of frames sent - */ -uint32_t TpUartDataLinkLayer::getTxProcessedFrameCounter() -{ - return _txProcessdFrameCounter; -} + /* + * Returns the number of control bytes counted that were not recognized + */ + uint32_t TpUartDataLinkLayer::getRxUnknownControlCounter() + { + return _rxUnkownControlCounter; + } -bool TpUartDataLinkLayer::isConnected() -{ - return _connected; -} + /* + * Returns the number of frames sent + */ + uint32_t TpUartDataLinkLayer::getTxFrameCounter() + { + return _txFrameCounter; + } + /* + * Returns the number of frames sent + */ + uint32_t TpUartDataLinkLayer::getTxProcessedFrameCounter() + { + return _txProcessdFrameCounter; + } -bool TpUartDataLinkLayer::isStopped() -{ - return _stopped; -} + bool TpUartDataLinkLayer::isConnected() + { + return _connected; + } -bool TpUartDataLinkLayer::isBusy() -{ - return _busy; -} + bool TpUartDataLinkLayer::isStopped() + { + return _stopped; + } -bool TpUartDataLinkLayer::isMonitoring() -{ - return _monitoring; -} + bool TpUartDataLinkLayer::isBusy() + { + return _busy; + } -bool TpUartDataLinkLayer::markerMode() -{ - if (_monitoring) - return false; + bool TpUartDataLinkLayer::isMonitoring() + { + return _monitoring; + } + + bool TpUartDataLinkLayer::markerMode() + { + if (_monitoring) + return false; #ifdef NCN5120 - // return true; + // return true; #endif - return false; -} - -void TpUartDataLinkLayer::processRxFrame(TpFrame* tpFrame) -{ - if (_monitoring) - { - print("Monitor: "); - tpFrame->printIt(); - println(); - } - else if (tpFrame->flags() & TP_FRAME_FLAG_INVALID) - { - print("\x1B["); - print(31); - print("m"); - print("Invalid: "); - tpFrame->printIt(); - print("\x1B["); - print(0); - println("m"); + return false; } - else if (tpFrame->flags() & TP_FRAME_FLAG_ADDRESSED) + + void TpUartDataLinkLayer::processRxFrame(TpFrame* tpFrame) { + if (_monitoring) + { + print("Monitor: "); + tpFrame->printIt(); + println(); + } + else if (tpFrame->flags() & TP_FRAME_FLAG_INVALID) + { + print("\x1B["); + print(31); + print("m"); + print("Invalid: "); + tpFrame->printIt(); + print("\x1B["); + print(0); + println("m"); + } + else if (tpFrame->flags() & TP_FRAME_FLAG_ADDRESSED) + { #ifdef DEBUG_TP_FRAMES - print("Inbound: "); - tpFrame.printIt()); - println(); + print("Inbound: "); + tpFrame.printIt()); + println(); #endif - if (!(tpFrame->flags() & TP_FRAME_FLAG_ECHO)) - rxFrameReceived(tpFrame); + if (!(tpFrame->flags() & TP_FRAME_FLAG_ECHO)) + rxFrameReceived(tpFrame); + } } -} #ifdef USE_TP_RX_QUEUE -/* - * This method allows the processing of the incoming bytes to be handled additionally via an interrupt (ISR). - * The prerequisite is that the interrupt runs on the same core as the knx.loop! - * - * With an RP2040 where the ISR is also locked when a block is erased, - * processing can be caught up between the erases. This significantly minimizes the risk of frame losses. - */ -void __isr __time_critical_func(TpUartDataLinkLayer::processRxISR)() -{ - processRx(true); -} + /* + * This method allows the processing of the incoming bytes to be handled additionally via an interrupt (ISR). + * The prerequisite is that the interrupt runs on the same core as the knx.loop! + * + * With an RP2040 where the ISR is also locked when a block is erased, + * processing can be caught up between the erases. This significantly minimizes the risk of frame losses. + */ + void __isr __time_critical_func(TpUartDataLinkLayer::processRxISR)() + { + processRx(true); + } -/* - * Puts the received frame into a queue. This queue is necessary, - * because a frame can optionally be received via an ISR and processing must still take place normally in the knx.loop. - * In addition, this queue is statically preallocated, as no malloc etc. can be made in an ISR. - */ -void TpUartDataLinkLayer::pushRxFrameQueue() -{ - if (availableInRxQueue() < (_rxFrame->size() + 3)) - return; + /* + * Puts the received frame into a queue. This queue is necessary, + * because a frame can optionally be received via an ISR and processing must still take place normally in the knx.loop. + * In addition, this queue is statically preallocated, as no malloc etc. can be made in an ISR. + */ + void TpUartDataLinkLayer::pushRxFrameQueue() + { + if (availableInRxQueue() < (_rxFrame->size() + 3)) + return; - // Payloadsize (2 byte) - pushByteToRxQueue(_rxFrame->size() & 0xFF); - pushByteToRxQueue(_rxFrame->size() >> 8); - // Paylodflags (1 byte) - pushByteToRxQueue(_rxFrame->flags()); + // Payloadsize (2 byte) + pushByteToRxQueue(_rxFrame->size() & 0xFF); + pushByteToRxQueue(_rxFrame->size() >> 8); + // Paylodflags (1 byte) + pushByteToRxQueue(_rxFrame->flags()); - for (size_t i = 0; i < _rxFrame->size(); i++) - { - pushByteToRxQueue(_rxFrame->data(i)); + for (size_t i = 0; i < _rxFrame->size(); i++) + { + pushByteToRxQueue(_rxFrame->data(i)); + } + + asm volatile("" ::: "memory"); + _rxBufferCount++; } - asm volatile("" ::: "memory"); - _rxBufferCount++; -} + void TpUartDataLinkLayer::processRxQueue() + { + if (!isrLock()) + return; -void TpUartDataLinkLayer::processRxQueue() -{ - if (!isrLock()) - return; + while (_rxBufferCount) + { + const uint16_t size = pullByteFromRxQueue() + (pullByteFromRxQueue() << 8); + TpFrame tpFrame = TpFrame(size); + tpFrame.addFlags(pullByteFromRxQueue()); - while (_rxBufferCount) - { - const uint16_t size = pullByteFromRxQueue() + (pullByteFromRxQueue() << 8); - TpFrame tpFrame = TpFrame(size); - tpFrame.addFlags(pullByteFromRxQueue()); + for (uint16_t i = 0; i < size; i++) + tpFrame.addByte(pullByteFromRxQueue()); - for (uint16_t i = 0; i < size; i++) - tpFrame.addByte(pullByteFromRxQueue()); + processRxFrame(&tpFrame); + asm volatile("" ::: "memory"); + _rxBufferCount--; + } - processRxFrame(&tpFrame); - asm volatile("" ::: "memory"); - _rxBufferCount--; + isrUnlock(); } - isrUnlock(); -} - -void TpUartDataLinkLayer::pushByteToRxQueue(uint8_t byte) -{ - _rxBuffer[_rxBufferFront] = byte; - _rxBufferFront = (_rxBufferFront + 1) % (MAX_RX_QUEUE_BYTES); -} + void TpUartDataLinkLayer::pushByteToRxQueue(uint8_t byte) + { + _rxBuffer[_rxBufferFront] = byte; + _rxBufferFront = (_rxBufferFront + 1) % (MAX_RX_QUEUE_BYTES); + } -uint8_t TpUartDataLinkLayer::pullByteFromRxQueue() -{ - uint8_t byte = _rxBuffer[_rxBufferRear]; - _rxBufferRear = (_rxBufferRear + 1) % (MAX_RX_QUEUE_BYTES); - return byte; -} + uint8_t TpUartDataLinkLayer::pullByteFromRxQueue() + { + uint8_t byte = _rxBuffer[_rxBufferRear]; + _rxBufferRear = (_rxBufferRear + 1) % (MAX_RX_QUEUE_BYTES); + return byte; + } -uint16_t TpUartDataLinkLayer::availableInRxQueue() -{ - return ((_rxBufferFront == _rxBufferRear) ? (MAX_RX_QUEUE_BYTES) : ((((MAX_RX_QUEUE_BYTES) - _rxBufferFront) + _rxBufferRear) % (MAX_RX_QUEUE_BYTES))) - 1; -} -#endif \ No newline at end of file + uint16_t TpUartDataLinkLayer::availableInRxQueue() + { + return ((_rxBufferFront == _rxBufferRear) ? (MAX_RX_QUEUE_BYTES) : ((((MAX_RX_QUEUE_BYTES) - _rxBufferFront) + _rxBufferRear) % (MAX_RX_QUEUE_BYTES))) - 1; + } +#endif +} \ No newline at end of file diff --git a/src/knx/tp/tpuart_data_link_layer.h b/src/knx/tp/tpuart_data_link_layer.h index a2746a8e..4b24eed9 100644 --- a/src/knx/tp/tpuart_data_link_layer.h +++ b/src/knx/tp/tpuart_data_link_layer.h @@ -21,155 +21,158 @@ #define __isr #endif -class ITpUartCallBacks +namespace Knx { - public: - virtual ~ITpUartCallBacks() = default; - virtual TPAckType isAckRequired(uint16_t address, bool isGrpAddr) = 0; -}; - -class TpUartDataLinkLayer : public DataLinkLayer -{ - using DataLinkLayer::_deviceObject; - using DataLinkLayer::_platform; - - public: - TpUartDataLinkLayer(DeviceObject& devObj, NetworkLayerEntity& netLayerEntity, - Platform& platform, ITpUartCallBacks& cb, DataLinkLayerCallbacks* dllcb = nullptr); - - void loop(); - void enabled(bool value); - bool enabled() const; - DptMedium mediumType() const override; - bool reset(); - void monitor(); - void stop(bool state); - void requestBusy(bool state); - void forceAck(bool state); - void setRepetitions(uint8_t nack, uint8_t busy); - // Alias - void setFrameRepetition(uint8_t nack, uint8_t busy); - bool isConnected(); - bool isMonitoring(); - bool isStopped(); - bool isBusy(); - void resetStats(); + class ITpUartCallBacks + { + public: + virtual ~ITpUartCallBacks() = default; + virtual TPAckType isAckRequired(uint16_t address, bool isGrpAddr) = 0; + }; + + class TpUartDataLinkLayer : public DataLinkLayer + { + using DataLinkLayer::_deviceObject; + using DataLinkLayer::_platform; + + public: + TpUartDataLinkLayer(DeviceObject& devObj, NetworkLayerEntity& netLayerEntity, + Platform& platform, ITpUartCallBacks& cb, DataLinkLayerCallbacks* dllcb = nullptr); + + void loop(); + void enabled(bool value); + bool enabled() const; + DptMedium mediumType() const override; + bool reset(); + void monitor(); + void stop(bool state); + void requestBusy(bool state); + void forceAck(bool state); + void setRepetitions(uint8_t nack, uint8_t busy); + // Alias + void setFrameRepetition(uint8_t nack, uint8_t busy); + bool isConnected(); + bool isMonitoring(); + bool isStopped(); + bool isBusy(); + void resetStats(); #ifdef USE_TP_RX_QUEUE - void processRxISR(); + void processRxISR(); #endif #ifdef NCN5120 - void powerControl(bool state); + void powerControl(bool state); #endif - uint32_t getRxInvalidFrameCounter(); - uint32_t getRxProcessdFrameCounter(); - uint32_t getRxIgnoredFrameCounter(); - uint32_t getRxUnknownControlCounter(); - uint32_t getTxFrameCounter(); - uint32_t getTxProcessedFrameCounter(); - uint8_t getMode(); - - private: - // Frame - struct knx_tx_queue_entry_t - { - TpFrame* frame; - knx_tx_queue_entry_t* next = nullptr; - - knx_tx_queue_entry_t(TpFrame* tpFrame) - : frame(tpFrame) + uint32_t getRxInvalidFrameCounter(); + uint32_t getRxProcessdFrameCounter(); + uint32_t getRxIgnoredFrameCounter(); + uint32_t getRxUnknownControlCounter(); + uint32_t getTxFrameCounter(); + uint32_t getTxProcessedFrameCounter(); + uint8_t getMode(); + + private: + // Frame + struct knx_tx_queue_entry_t + { + TpFrame* frame; + knx_tx_queue_entry_t* next = nullptr; + + knx_tx_queue_entry_t(TpFrame* tpFrame) + : frame(tpFrame) + { + } + }; + + // TX Queue + struct knx_tx_queue_t { - } - }; - - // TX Queue - struct knx_tx_queue_t - { - knx_tx_queue_entry_t* front = nullptr; - knx_tx_queue_entry_t* back = nullptr; - } _txFrameQueue; - - TpFrame* _txFrame = nullptr; - TpFrame* _rxFrame = nullptr; - - volatile bool _stopped = false; - volatile bool _connected = false; - volatile bool _monitoring = false; - volatile bool _busy = false; - volatile bool _initialized = false; - - 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(); - - /* - * bits - * - * 5-7 Busy (Default 11 = 3) - * 0-3 Nack (Default 11 = 3) - */ - volatile uint8_t _repetitions = 0b00110011; - - // to prevent parallel rx processing by isr (when using) - volatile bool _rxProcessing = false; - - volatile uint32_t _lastStateRequest = 0; - - // void loadNextTxFrame(); - inline bool processTxFrameBytes(); - bool sendFrame(CemiFrame& frame); - void rxFrameReceived(TpFrame* frame); - void dataConBytesReceived(uint8_t* buffer, uint16_t length, bool success); - - void processRx(bool isr = false); - void checkConnected(); - void processRxByte(); - void processTxQueue(); - void clearTxFrameQueue(); - void processRxFrameComplete(); - inline void processRxFrame(TpFrame* tpFrame); - void pushTxFrameQueue(TpFrame* tpFrame); - void requestState(bool force = false); - void requestConfig(); - inline void processRxFrameByte(uint8_t byte); + knx_tx_queue_entry_t* front = nullptr; + knx_tx_queue_entry_t* back = nullptr; + } _txFrameQueue; + + TpFrame* _txFrame = nullptr; + TpFrame* _rxFrame = nullptr; + + volatile bool _stopped = false; + volatile bool _connected = false; + volatile bool _monitoring = false; + volatile bool _busy = false; + volatile bool _initialized = false; + + 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(); + + /* + * bits + * + * 5-7 Busy (Default 11 = 3) + * 0-3 Nack (Default 11 = 3) + */ + volatile uint8_t _repetitions = 0b00110011; + + // to prevent parallel rx processing by isr (when using) + volatile bool _rxProcessing = false; + + volatile uint32_t _lastStateRequest = 0; + + // void loadNextTxFrame(); + inline bool processTxFrameBytes(); + bool sendFrame(CemiFrame& frame); + void rxFrameReceived(TpFrame* frame); + void dataConBytesReceived(uint8_t* buffer, uint16_t length, bool success); + + void processRx(bool isr = false); + void checkConnected(); + void processRxByte(); + void processTxQueue(); + void clearTxFrameQueue(); + void processRxFrameComplete(); + inline void processRxFrame(TpFrame* tpFrame); + void pushTxFrameQueue(TpFrame* tpFrame); + void requestState(bool force = false); + void requestConfig(); + inline void processRxFrameByte(uint8_t byte); #ifdef USE_TP_RX_QUEUE - // Es muss ein Extended Frame rein passen + 1Byte je erlaubter ms Verzögerung - volatile uint8_t _rxBuffer[MAX_RX_QUEUE_BYTES] = {}; - volatile uint16_t _rxBufferFront = 0; - volatile uint16_t _rxBufferRear = 0; - volatile uint8_t _rxBufferCount = 0; - - void pushByteToRxQueue(uint8_t byte); - uint8_t pullByteFromRxQueue(); - uint16_t availableInRxQueue(); - void pushRxFrameQueue(); - void processRxQueue(); + // Es muss ein Extended Frame rein passen + 1Byte je erlaubter ms Verzögerung + volatile uint8_t _rxBuffer[MAX_RX_QUEUE_BYTES] = {}; + volatile uint16_t _rxBufferFront = 0; + volatile uint16_t _rxBufferRear = 0; + volatile uint8_t _rxBufferCount = 0; + + void pushByteToRxQueue(uint8_t byte); + uint8_t pullByteFromRxQueue(); + uint16_t availableInRxQueue(); + void pushRxFrameQueue(); + void processRxQueue(); #endif - inline bool isrLock(bool blocking = false); - inline void isrUnlock(); - inline void clearUartBuffer(); - inline void connected(bool state = true); - void clearTxFrame(); - void clearOutdatedTxFrame(); - void processTxFrameComplete(bool success); - - ITpUartCallBacks& _cb; - DataLinkLayerCallbacks* _dllcb; -}; + inline bool isrLock(bool blocking = false); + inline void isrUnlock(); + inline void clearUartBuffer(); + inline void connected(bool state = true); + void clearTxFrame(); + void clearOutdatedTxFrame(); + void processTxFrameComplete(bool success); + + ITpUartCallBacks& _cb; + DataLinkLayerCallbacks* _dllcb; + }; +} \ No newline at end of file diff --git a/src/knx/transport_layer/tpdu.cpp b/src/knx/transport_layer/tpdu.cpp index f5f0c986..4b13a6e5 100644 --- a/src/knx/transport_layer/tpdu.cpp +++ b/src/knx/transport_layer/tpdu.cpp @@ -3,137 +3,141 @@ #include "../datalink_layer/cemi_frame.h" #include "../bits.h" -TPDU::TPDU(uint8_t* data, CemiFrame& frame): _data(data), _frame(frame) +namespace Knx { -} + TPDU::TPDU(uint8_t* data, CemiFrame& frame): _data(data), _frame(frame) + { + } -TpduType TPDU::type() const -{ - if (control()) + TpduType TPDU::type() const { - if (numbered()) + if (control()) { - if ((_data[0] & 1) == 0) - return Ack; + if (numbered()) + { + if ((_data[0] & 1) == 0) + return Ack; + else + return Nack; + } + else if ((_data[0] & 1) == 0) + return Connect; else - return Nack; + return Disconnect; } - else if ((_data[0] & 1) == 0) - return Connect; else - return Disconnect; - } - else - { - if (_frame.addressType() == GroupAddress) { - if (_frame.destinationAddress() == 0) - return DataBroadcast; + if (_frame.addressType() == GroupAddress) + { + if (_frame.destinationAddress() == 0) + return DataBroadcast; + else + return DataGroup; + } + else if (numbered()) + return DataConnected; else - return DataGroup; + return DataInduvidual; } - else if (numbered()) - return DataConnected; - else - return DataInduvidual; } -} -void TPDU::type(TpduType type) -{ - switch (type) + void TPDU::type(TpduType type) { - case DataBroadcast: - case DataGroup: - case DataInduvidual: - _data[0] &= 0x3; - break; - - case DataConnected: - _data[0] &= 0xC3; - _data[0] |= 0x40; - break; - - case Connect: - _data[0] = 0x80; - break; - - case Disconnect: - _data[0] = 0x81; - break; - - case Ack: - _data[0] &= ~0xC3; - _data[0] |= 0xC2; - break; - - case Nack: - _data[0] |= 0xC3; - break; + switch (type) + { + case DataBroadcast: + case DataGroup: + case DataInduvidual: + _data[0] &= 0x3; + break; + + case DataConnected: + _data[0] &= 0xC3; + _data[0] |= 0x40; + break; + + case Connect: + _data[0] = 0x80; + break; + + case Disconnect: + _data[0] = 0x81; + break; + + case Ack: + _data[0] &= ~0xC3; + _data[0] |= 0xC2; + break; + + case Nack: + _data[0] |= 0xC3; + break; + } } -} -bool TPDU::numbered() const -{ - return (_data[0] & 0x40) > 0; -} + bool TPDU::numbered() const + { + return (_data[0] & 0x40) > 0; + } -void TPDU::numbered(bool value) -{ - if (value) - _data[0] |= 0x40; - else - _data[0] &= ~0x40; -} + void TPDU::numbered(bool value) + { + if (value) + _data[0] |= 0x40; + else + _data[0] &= ~0x40; + } -bool TPDU::control() const -{ - return (_data[0] & 0x80) > 0; -} + bool TPDU::control() const + { + return (_data[0] & 0x80) > 0; + } -void TPDU::control(bool value) -{ - if (value) - _data[0] |= 0x80; - else - _data[0] &= ~0x80; -} + void TPDU::control(bool value) + { + if (value) + _data[0] |= 0x80; + else + _data[0] &= ~0x80; + } -uint8_t TPDU::sequenceNumber() const -{ - return ((_data[0] >> 2) & 0xF); -} + uint8_t TPDU::sequenceNumber() const + { + return ((_data[0] >> 2) & 0xF); + } -void TPDU::sequenceNumber(uint8_t value) -{ - _data[0] &= ~(0xF << 2); - _data[0] |= ((value & 0xF) << 2); -} + void TPDU::sequenceNumber(uint8_t value) + { + _data[0] &= ~(0xF << 2); + _data[0] |= ((value & 0xF) << 2); + } -APDU& TPDU::apdu() -{ - return _frame.apdu(); -} + APDU& TPDU::apdu() + { + return _frame.apdu(); + } -CemiFrame& TPDU::frame() -{ - return _frame; -} + CemiFrame& TPDU::frame() + { + return _frame; + } -void TPDU::printIt() const -{ + void TPDU::printIt() const + { #ifndef KNX_NO_PRINT - print("TPDU: "); - print(enum_name(type())); - print(" "); + print("TPDU: "); + print(enum_name(type())); + print(" "); - if (control()) - print("control "); + if (control()) + print("control "); + + if (numbered()) + { + print("numbered sequence: "); + print(sequenceNumber()); + } - if (numbered()) - { - print("numbered sequence: "); - print(sequenceNumber()); - } #endif + } } \ No newline at end of file diff --git a/src/knx/transport_layer/tpdu.h b/src/knx/transport_layer/tpdu.h index 79182d6a..77376739 100644 --- a/src/knx/transport_layer/tpdu.h +++ b/src/knx/transport_layer/tpdu.h @@ -5,35 +5,38 @@ #include -class CemiFrame; -class APDU; - -class TPDU : public IPrintable +namespace Knx { - friend class CemiFrame; + class CemiFrame; + class APDU; + + class TPDU : public IPrintable + { + friend class CemiFrame; - public: - TpduType type() const; - void type(TpduType type); + public: + TpduType type() const; + void type(TpduType type); - bool numbered() const; - void numbered(bool value); + bool numbered() const; + void numbered(bool value); - bool control() const; - void control(bool value); + bool control() const; + void control(bool value); - uint8_t sequenceNumber() const; - void sequenceNumber(uint8_t value); + uint8_t sequenceNumber() const; + void sequenceNumber(uint8_t value); - APDU& apdu(); + APDU& apdu(); - CemiFrame& frame(); - void printIt() const; + CemiFrame& frame(); + void printIt() const; - protected: - TPDU(uint8_t* data, CemiFrame& frame); + protected: + TPDU(uint8_t* data, CemiFrame& frame); - private: - uint8_t* _data = 0; - CemiFrame& _frame; -}; + private: + uint8_t* _data = 0; + CemiFrame& _frame; + }; +} \ No newline at end of file diff --git a/src/knx/transport_layer/transport_layer.cpp b/src/knx/transport_layer/transport_layer.cpp index a622d1bc..c524ba30 100644 --- a/src/knx/transport_layer/transport_layer.cpp +++ b/src/knx/transport_layer/transport_layer.cpp @@ -10,289 +10,215 @@ #define LOGGER Logger::logger("TransportLayer") -TransportLayer::TransportLayer(ApplicationLayer& layer): _savedFrame(0), - _savedFrameConnecting(0), _applicationLayer(layer) +namespace Knx { - _currentState = Closed; -} + TransportLayer::TransportLayer(ApplicationLayer& layer): _savedFrame(0), + _savedFrameConnecting(0), _applicationLayer(layer) + { + _currentState = Closed; + } -void TransportLayer::networkLayer(NetworkLayer& layer) -{ - _networkLayer = &layer; -} + void TransportLayer::networkLayer(NetworkLayer& layer) + { + _networkLayer = &layer; + } -void TransportLayer::groupAddressTable(AddressTableObject& addrTable) -{ - _groupAddressTable = &addrTable; -} + void TransportLayer::groupAddressTable(AddressTableObject& addrTable) + { + _groupAddressTable = &addrTable; + } -void TransportLayer::dataIndividualIndication(uint16_t destination, HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu) -{ - LOGGER.info("dataIndividualIndication ", tpdu); + void TransportLayer::dataIndividualIndication(uint16_t destination, HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu) + { + LOGGER.info("dataIndividualIndication ", tpdu); - uint8_t sequenceNo = tpdu.sequenceNumber(); + uint8_t sequenceNo = tpdu.sequenceNumber(); - switch (tpdu.type()) - { - case DataInduvidual: - _applicationLayer.dataIndividualIndication(hopType, priority, source, tpdu.apdu()); - return; + switch (tpdu.type()) + { + case DataInduvidual: + _applicationLayer.dataIndividualIndication(hopType, priority, source, tpdu.apdu()); + return; - case DataConnected: - if (source == _connectionAddress) - { - if (sequenceNo == _seqNoRecv) + case DataConnected: + if (source == _connectionAddress) { - //E4 - switch (_currentState) + if (sequenceNo == _seqNoRecv) { - case Closed: - //A0 nothing - break; + //E4 + switch (_currentState) + { + case Closed: + //A0 nothing + break; - case OpenIdle: - case OpenWait: - A2(source, priority, tpdu.apdu()); - break; + case OpenIdle: + case OpenWait: + A2(source, priority, tpdu.apdu()); + break; - case Connecting: - _currentState = Closed; - A6(destination); - break; + case Connecting: + _currentState = Closed; + A6(destination); + break; + } } - } - else if (sequenceNo == ((_seqNoRecv - 1) & 0xF)) - { - //E5 - switch (_currentState) + else if (sequenceNo == ((_seqNoRecv - 1) & 0xF)) { - case Closed: - //A0 - break; + //E5 + switch (_currentState) + { + case Closed: + //A0 + break; - case OpenIdle: - case OpenWait: - case Connecting: - A3(source, priority, tpdu); - break; + case OpenIdle: + case OpenWait: + case Connecting: + A3(source, priority, tpdu); + break; + } + } + else + { + //E6 + switch (_currentState) + { + case Closed: + //A0 + break; + + case OpenIdle: + case OpenWait: + A4(source, priority, tpdu); + break; + + case Connecting: + A6(destination); + break; + } } } else { - //E6 + //E7 switch (_currentState) { case Closed: - //A0 - break; - case OpenIdle: case OpenWait: - A4(source, priority, tpdu); + //A0 break; case Connecting: - A6(destination); + A10(source); break; } } - } - else - { - //E7 - switch (_currentState) - { - case Closed: - case OpenIdle: - case OpenWait: - //A0 - break; - - case Connecting: - A10(source); - break; - } - } - - break; - - case Connect: - if (source == _connectionAddress) - { - //E0 - switch (_currentState) - { - case Closed: - _currentState = OpenIdle; - A1(source); - break; - - case OpenWait: - case OpenIdle: - case Connecting: - //A0: do nothing - break; - } - } - else - { - //E1 - switch (_currentState) - { - case Closed: - _currentState = OpenIdle; - A1(source); - break; - - case OpenIdle: - case OpenWait: - case Connecting: - A10(source); - break; - } - } - - break; - case Disconnect: - if (source == _connectionAddress) - { - //E2 - switch (_currentState) - { - case Closed: - //A0 do nothing - break; - - case OpenIdle: - case OpenWait: - case Connecting: - _currentState = Closed; - A5(source); - break; - - default: - break; - } - } - else - { - //E3 - //A0: do nothing - } - - break; + break; - case Ack: - if (source == _connectionAddress) - { - if (sequenceNo == _seqNoSend) + case Connect: + if (source == _connectionAddress) { - //E8 + //E0 switch (_currentState) { case Closed: - case OpenIdle: - //A0 - break; - - case OpenWait: _currentState = OpenIdle; - A8(); + A1(source); break; + case OpenWait: + case OpenIdle: case Connecting: - _currentState = Closed; - A6(source); + //A0: do nothing break; } } else { - //E9 + //E1 switch (_currentState) { case Closed: - case OpenIdle: - //A0 + _currentState = OpenIdle; + A1(source); break; + case OpenIdle: case OpenWait: case Connecting: - _currentState = Closed; - A6(source); + A10(source); break; } } - } - else - { - //E10 - switch (_currentState) - { - case Connecting: - A10(source); - break; - - default: /* do nothing */ - break; - } - } - break; + break; - case Nack: - if (source == _connectionAddress) - { - if (sequenceNo != _seqNoSend) + case Disconnect: + if (source == _connectionAddress) { - //E11 + //E2 switch (_currentState) { case Closed: - case OpenIdle: - case OpenWait: - //A0 + //A0 do nothing break; + case OpenIdle: + case OpenWait: case Connecting: _currentState = Closed; - A6(source); + A5(source); + break; + + default: break; } } else { - if (_repCount < _maxRepCount) + //E3 + //A0: do nothing + } + + break; + + case Ack: + if (source == _connectionAddress) + { + if (sequenceNo == _seqNoSend) { - //E12 + //E8 switch (_currentState) { case Closed: + case OpenIdle: //A0 break; + case OpenWait: + _currentState = OpenIdle; + A8(); + break; + case Connecting: - case OpenIdle: _currentState = Closed; A6(source); break; - - case OpenWait: - A9(); - break; } } else { - //E13 + //E9 switch (_currentState) { case Closed: + case OpenIdle: //A0 break; - case OpenIdle: case OpenWait: case Connecting: _currentState = Closed; @@ -301,510 +227,587 @@ void TransportLayer::dataIndividualIndication(uint16_t destination, HopCountType } } } - } - else - { - //E14 - switch (_currentState) + else { - case Closed: - case OpenIdle: - case OpenWait: - //A0 - break; - - case Connecting: - A10(source); - break; - - default: - break; - } - } - - break; - - default: - break; - } -} - -void TransportLayer::dataIndividualConfirm(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu, bool status) -{ - LOGGER.info("dataIndividualConfirm ", tpdu); - TpduType type = tpdu.type(); + //E10 + switch (_currentState) + { + case Connecting: + A10(source); + break; - switch (type) - { - case DataInduvidual: - _applicationLayer.dataIndividualConfirm(ack, hopType, priority, destination, tpdu.apdu(), status); - break; + default: /* do nothing */ + break; + } + } - case DataConnected: - //E22 - //A0: do nothing - break; + break; - case Connect: - if (status) - { - //E19 - switch (_currentState) + case Nack: + if (source == _connectionAddress) { - case Closed: - case OpenIdle: - case OpenWait: - //A0: do nothing - break; - - case Connecting: - _currentState = OpenIdle; - A13(destination); - break; + if (sequenceNo != _seqNoSend) + { + //E11 + switch (_currentState) + { + case Closed: + case OpenIdle: + case OpenWait: + //A0 + break; + + case Connecting: + _currentState = Closed; + A6(source); + break; + } + } + else + { + if (_repCount < _maxRepCount) + { + //E12 + switch (_currentState) + { + case Closed: + //A0 + break; + + case Connecting: + case OpenIdle: + _currentState = Closed; + A6(source); + break; + + case OpenWait: + A9(); + break; + } + } + else + { + //E13 + switch (_currentState) + { + case Closed: + //A0 + break; + + case OpenIdle: + case OpenWait: + case Connecting: + _currentState = Closed; + A6(source); + break; + } + } + } } - } - else - { - //E20 - switch (_currentState) + else { - case Closed: - case OpenIdle: - case OpenWait: - //A0: do nothing - break; - - case Connecting: - A5(destination); - break; - } - } - - break; + //E14 + switch (_currentState) + { + case Closed: + case OpenIdle: + case OpenWait: + //A0 + break; - case Disconnect: - //E21 - //A0: do nothing - break; + case Connecting: + A10(source); + break; - case Ack: - //E23 - //A0: do nothing - break; + default: + break; + } + } - case Nack: - //E24 - //A0: do nothing - break; + break; - default: - break; - /* DataGroup and DataBroadcast should not appear here. If they do ignore them. */ + default: + break; + } } -} -void TransportLayer::dataGroupIndication(uint16_t destination, HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu) -{ - LOGGER.info("dataGroupIndication ", tpdu); + void TransportLayer::dataIndividualConfirm(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu, bool status) + { + LOGGER.info("dataIndividualConfirm ", tpdu); + TpduType type = tpdu.type(); - if (_groupAddressTable == nullptr) - return; + switch (type) + { + case DataInduvidual: + _applicationLayer.dataIndividualConfirm(ack, hopType, priority, destination, tpdu.apdu(), status); + break; - uint16_t tsap = _groupAddressTable->getTsap(destination); + case DataConnected: + //E22 + //A0: do nothing + break; - if (tsap == 0) - { - LOGGER.info("dataGroupIndication telegram is not for us"); - return; - } + case Connect: + if (status) + { + //E19 + switch (_currentState) + { + case Closed: + case OpenIdle: + case OpenWait: + //A0: do nothing + break; - _applicationLayer.dataGroupIndication(hopType, priority, tsap, tpdu.apdu()); -} + case Connecting: + _currentState = OpenIdle; + A13(destination); + break; + } + } + else + { + //E20 + switch (_currentState) + { + case Closed: + case OpenIdle: + case OpenWait: + //A0: do nothing + break; -void TransportLayer::dataGroupConfirm(AckType ack, uint16_t source, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu, bool status) -{ - LOGGER.info("dataGroupConfirm ", tpdu); - _applicationLayer.dataGroupConfirm(ack, hopType, priority, destination, tpdu.apdu(), status); -} + case Connecting: + A5(destination); + break; + } + } -void TransportLayer::dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu) -{ - LOGGER.info("dataBroadcastIndication ", tpdu); - _applicationLayer.dataBroadcastIndication(hopType, priority, source, tpdu.apdu()); -} + break; -void TransportLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu, bool status) -{ - LOGGER.info("dataBroadcastConfirm ", tpdu); - _applicationLayer.dataBroadcastConfirm(ack, hopType, priority, tpdu.apdu(), status); -} + case Disconnect: + //E21 + //A0: do nothing + break; -void TransportLayer::dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu) -{ - LOGGER.info("dataSystemBroadcastIndication ", tpdu); - _applicationLayer.dataSystemBroadcastIndication(hopType, priority, source, tpdu.apdu()); -} + case Ack: + //E23 + //A0: do nothing + break; -void TransportLayer::dataSystemBroadcastConfirm(AckType ack, HopCountType hopType, TPDU& tpdu, Priority priority, bool status) -{ - LOGGER.info("dataSystemBroadcastConfirm ", tpdu); - _applicationLayer.dataSystemBroadcastConfirm(hopType, priority, tpdu.apdu(), status); -} + case Nack: + //E24 + //A0: do nothing + break; -void TransportLayer::dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) -{ - if (_groupAddressTable == nullptr) - return; + default: + break; + /* DataGroup and DataBroadcast should not appear here. If they do ignore them. */ + } + } + + void TransportLayer::dataGroupIndication(uint16_t destination, HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu) + { + LOGGER.info("dataGroupIndication ", tpdu); - uint16_t groupAdress = _groupAddressTable->getGroupAddress(tsap); - TPDU& tpdu = apdu.frame().tpdu(); - LOGGER.info("dataGroupRequest ", tpdu); - _networkLayer->dataGroupRequest(ack, groupAdress, hopType, priority, tpdu); -} + if (_groupAddressTable == nullptr) + return; -void TransportLayer::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu) -{ - TPDU& tpdu = apdu.frame().tpdu(); - LOGGER.info("dataBroadcastRequest ", tpdu); - _networkLayer->dataBroadcastRequest(ack, hopType, priority, tpdu); -} + uint16_t tsap = _groupAddressTable->getTsap(destination); -void TransportLayer::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu) -{ - TPDU& tpdu = apdu.frame().tpdu(); - LOGGER.info("dataSystemBroadcastRequest ", tpdu); - return _networkLayer->dataSystemBroadcastRequest(ack, hopType, priority, tpdu); -} + if (tsap == 0) + { + LOGGER.info("dataGroupIndication telegram is not for us"); + return; + } -void TransportLayer::dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu) -{ - TPDU& tpdu = apdu.frame().tpdu(); - LOGGER.info("dataIndividualRequest ", tpdu); - _networkLayer->dataIndividualRequest(ack, destination, hopType, priority, tpdu); -} + _applicationLayer.dataGroupIndication(hopType, priority, tsap, tpdu.apdu()); + } -void TransportLayer::connectRequest(uint16_t destination, Priority priority) -{ - //E25 - switch (_currentState) + void TransportLayer::dataGroupConfirm(AckType ack, uint16_t source, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu, bool status) { - case Closed: - _currentState = Connecting; - A12(destination, priority); - break; + LOGGER.info("dataGroupConfirm ", tpdu); + _applicationLayer.dataGroupConfirm(ack, hopType, priority, destination, tpdu.apdu(), status); + } - case OpenIdle: - case OpenWait: - case Connecting: - _currentState = Closed; - A6(destination); - break; + void TransportLayer::dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu) + { + LOGGER.info("dataBroadcastIndication ", tpdu); + _applicationLayer.dataBroadcastIndication(hopType, priority, source, tpdu.apdu()); } -} -void TransportLayer::disconnectRequest(uint16_t tsap, Priority priority) -{ - //E26 - switch (_currentState) + void TransportLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu, bool status) { - case Closed: - A15(priority, tsap); - break; + LOGGER.info("dataBroadcastConfirm ", tpdu); + _applicationLayer.dataBroadcastConfirm(ack, hopType, priority, tpdu.apdu(), status); + } - case OpenIdle: - case OpenWait: - case Connecting: - _currentState = Closed; - A14(tsap, priority); - break; + void TransportLayer::dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu) + { + LOGGER.info("dataSystemBroadcastIndication ", tpdu); + _applicationLayer.dataSystemBroadcastIndication(hopType, priority, source, tpdu.apdu()); } -} -void TransportLayer::dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu) -{ - //print.print("-> TL "); - //apdu.printPDU(); - //E15 - switch (_currentState) + void TransportLayer::dataSystemBroadcastConfirm(AckType ack, HopCountType hopType, TPDU& tpdu, Priority priority, bool status) { - case Closed: - //A0 - break; + LOGGER.info("dataSystemBroadcastConfirm ", tpdu); + _applicationLayer.dataSystemBroadcastConfirm(hopType, priority, tpdu.apdu(), status); + } - case OpenIdle: - _currentState = OpenWait; - A7(priority, apdu); - break; + void TransportLayer::dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) + { + if (_groupAddressTable == nullptr) + return; - case OpenWait: - case Connecting: - A11(tsap, priority, apdu); - break; + uint16_t groupAdress = _groupAddressTable->getGroupAddress(tsap); + TPDU& tpdu = apdu.frame().tpdu(); + LOGGER.info("dataGroupRequest ", tpdu); + _networkLayer->dataGroupRequest(ack, groupAdress, hopType, priority, tpdu); + } - default: - break; + void TransportLayer::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu) + { + TPDU& tpdu = apdu.frame().tpdu(); + LOGGER.info("dataBroadcastRequest ", tpdu); + _networkLayer->dataBroadcastRequest(ack, hopType, priority, tpdu); } -} -void TransportLayer::connectionTimeoutIndication() -{ - //E16 - switch (_currentState) + void TransportLayer::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu) { - case Closed: - //A0: do nothing - break; + TPDU& tpdu = apdu.frame().tpdu(); + LOGGER.info("dataSystemBroadcastRequest ", tpdu); + return _networkLayer->dataSystemBroadcastRequest(ack, hopType, priority, tpdu); + } - case OpenIdle: - case OpenWait: - case Connecting: - _currentState = Closed; - A6(_connectionAddress); - break; + void TransportLayer::dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu) + { + TPDU& tpdu = apdu.frame().tpdu(); + LOGGER.info("dataIndividualRequest ", tpdu); + _networkLayer->dataIndividualRequest(ack, destination, hopType, priority, tpdu); } -} -void TransportLayer::ackTimeoutIndication() -{ - if (_repCount < _maxRepCount) + void TransportLayer::connectRequest(uint16_t destination, Priority priority) { - //E17 + //E25 switch (_currentState) { case Closed: + _currentState = Connecting; + A12(destination, priority); + break; + case OpenIdle: + case OpenWait: case Connecting: - //A0: do nothing + _currentState = Closed; + A6(destination); break; + } + } + void TransportLayer::disconnectRequest(uint16_t tsap, Priority priority) + { + //E26 + switch (_currentState) + { + case Closed: + A15(priority, tsap); + break; + + case OpenIdle: case OpenWait: - A9(); + case Connecting: + _currentState = Closed; + A14(tsap, priority); break; } } - else + + void TransportLayer::dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu) { - //E18 + //print.print("-> TL "); + //apdu.printPDU(); + //E15 switch (_currentState) { case Closed: + //A0 + break; + case OpenIdle: + _currentState = OpenWait; + A7(priority, apdu); + break; + + case OpenWait: case Connecting: + A11(tsap, priority, apdu); + break; + + default: + break; + } + } + + void TransportLayer::connectionTimeoutIndication() + { + //E16 + switch (_currentState) + { + case Closed: //A0: do nothing break; + case OpenIdle: case OpenWait: + case Connecting: _currentState = Closed; A6(_connectionAddress); break; } } -} -// Note: we should probably also add the TSAP as argument if would support multiple concurrent connections -uint8_t TransportLayer::getTpciSeqNum() -{ - // Return seqNum that would be used for sending next frame - // together with the TPDU type. - return ((_seqNoSend & 0xF) << 2); -} + void TransportLayer::ackTimeoutIndication() + { + if (_repCount < _maxRepCount) + { + //E17 + switch (_currentState) + { + case Closed: + case OpenIdle: + case Connecting: + //A0: do nothing + break; + + case OpenWait: + A9(); + break; + } + } + else + { + //E18 + switch (_currentState) + { + case Closed: + case OpenIdle: + case Connecting: + //A0: do nothing + break; + + case OpenWait: + _currentState = Closed; + A6(_connectionAddress); + break; + } + } + } -// Note: we should probably also add the TSAP as argument if would support multiple concurrent connections -uint16_t TransportLayer::getConnectionAddress() -{ - return _connectionAddress; -} + // Note: we should probably also add the TSAP as argument if would support multiple concurrent connections + uint8_t TransportLayer::getTpciSeqNum() + { + // Return seqNum that would be used for sending next frame + // together with the TPDU type. + return ((_seqNoSend & 0xF) << 2); + } -void TransportLayer::loop() -{ - uint32_t milliseconds = millis(); + // Note: we should probably also add the TSAP as argument if would support multiple concurrent connections + uint16_t TransportLayer::getConnectionAddress() + { + return _connectionAddress; + } - if (_connectionTimeoutEnabled - && (milliseconds - _connectionTimeoutStartMillis) > _connectionTimeoutMillis) - connectionTimeoutIndication(); + void TransportLayer::loop() + { + uint32_t milliseconds = millis(); - if (_ackTimeoutEnabled - && (milliseconds - _ackTimeoutStartMillis) > _ackTimeoutMillis) - ackTimeoutIndication(); + if (_connectionTimeoutEnabled + && (milliseconds - _connectionTimeoutStartMillis) > _connectionTimeoutMillis) + connectionTimeoutIndication(); - if (_savedConnectingValid) + if (_ackTimeoutEnabled + && (milliseconds - _ackTimeoutStartMillis) > _ackTimeoutMillis) + ackTimeoutIndication(); + + if (_savedConnectingValid) + { + //retry saved event + _savedConnectingValid = false; + dataConnectedRequest(_savedTsapConnecting, _savedPriorityConnecting, _savedFrameConnecting.apdu()); + } + } + + void TransportLayer::sendControlTelegram(TpduType pduType, uint8_t seqNo) { - //retry saved event - _savedConnectingValid = false; - dataConnectedRequest(_savedTsapConnecting, _savedPriorityConnecting, _savedFrameConnecting.apdu()); + CemiFrame frame(0); + TPDU& tpdu = frame.tpdu(); + tpdu.type(pduType); + tpdu.sequenceNumber(seqNo); + LOGGER.info("sendControlTelegram ", tpdu); + _networkLayer->dataIndividualRequest(AckRequested, _connectionAddress, NetworkLayerParameter, + SystemPriority, tpdu); } -} -void TransportLayer::sendControlTelegram(TpduType pduType, uint8_t seqNo) -{ - CemiFrame frame(0); - TPDU& tpdu = frame.tpdu(); - tpdu.type(pduType); - tpdu.sequenceNumber(seqNo); - LOGGER.info("sendControlTelegram ", tpdu); - _networkLayer->dataIndividualRequest(AckRequested, _connectionAddress, NetworkLayerParameter, - SystemPriority, tpdu); -} - -void TransportLayer::A0() -{ - /* do nothing */ -} + void TransportLayer::A0() + { + /* do nothing */ + } -void TransportLayer::A1(uint16_t source) -{ - _connectionAddress = source; - _applicationLayer.connectIndication(source); - _seqNoSend = 0; - _seqNoRecv = 0; - enableConnectionTimeout(); -} - -void incSeqNr(uint8_t& seqNr) -{ - seqNr += 1; + void TransportLayer::A1(uint16_t source) + { + _connectionAddress = source; + _applicationLayer.connectIndication(source); + _seqNoSend = 0; + _seqNoRecv = 0; + enableConnectionTimeout(); + } - if (seqNr > 0xf) - seqNr = 0; -} + void incSeqNr(uint8_t& seqNr) + { + seqNr += 1; -void TransportLayer::A2(uint16_t source, Priority priority, APDU& apdu) -{ - sendControlTelegram(Ack, _seqNoRecv); - incSeqNr(_seqNoRecv); - _applicationLayer.dataConnectedIndication(priority, source, apdu); - enableConnectionTimeout(); -} + if (seqNr > 0xf) + seqNr = 0; + } -void TransportLayer::A3(uint16_t source, Priority priority, TPDU& recTpdu) -{ - sendControlTelegram(Ack, recTpdu.sequenceNumber()); - enableConnectionTimeout(); -} + void TransportLayer::A2(uint16_t source, Priority priority, APDU& apdu) + { + sendControlTelegram(Ack, _seqNoRecv); + incSeqNr(_seqNoRecv); + _applicationLayer.dataConnectedIndication(priority, source, apdu); + enableConnectionTimeout(); + } -void TransportLayer::A4(uint16_t source, Priority priority, TPDU& recTpdu) -{ - sendControlTelegram(Nack, recTpdu.sequenceNumber()); - enableConnectionTimeout(); -} + void TransportLayer::A3(uint16_t source, Priority priority, TPDU& recTpdu) + { + sendControlTelegram(Ack, recTpdu.sequenceNumber()); + enableConnectionTimeout(); + } -void TransportLayer::A5(uint16_t tsap) -{ - _applicationLayer.disconnectIndication(tsap); - disableConnectionTimeout(); - disableAckTimeout(); -} + void TransportLayer::A4(uint16_t source, Priority priority, TPDU& recTpdu) + { + sendControlTelegram(Nack, recTpdu.sequenceNumber()); + enableConnectionTimeout(); + } -void TransportLayer::A6(uint16_t tsap) -{ - sendControlTelegram(Disconnect, 0); - _applicationLayer.disconnectIndication(tsap); - disableConnectionTimeout(); - disableAckTimeout(); -} + void TransportLayer::A5(uint16_t tsap) + { + _applicationLayer.disconnectIndication(tsap); + disableConnectionTimeout(); + disableAckTimeout(); + } -void TransportLayer::A7(Priority priority, APDU& apdu) -{ - _savedPriority = priority; - TPDU& tpdu = apdu.frame().tpdu(); - tpdu.type(DataConnected); - tpdu.sequenceNumber(_seqNoSend); - _savedFrame = apdu.frame(); - _networkLayer->dataIndividualRequest(AckRequested, _connectionAddress, NetworkLayerParameter, priority, tpdu); - _repCount = 0; - enableAckTimeout(); - enableConnectionTimeout(); -} - -void TransportLayer::A8() -{ - disableAckTimeout(); - incSeqNr(_seqNoSend); - _applicationLayer.dataConnectedConfirm(0); - enableConnectionTimeout(); -} + void TransportLayer::A6(uint16_t tsap) + { + sendControlTelegram(Disconnect, 0); + _applicationLayer.disconnectIndication(tsap); + disableConnectionTimeout(); + disableAckTimeout(); + } -void TransportLayer::A9() -{ - TPDU& tpdu = _savedFrame.tpdu(); - // tpdu is still initialized from last send - _networkLayer->dataIndividualRequest(AckRequested, _connectionAddress, NetworkLayerParameter, _savedPriority, tpdu); - _repCount += 1; - enableAckTimeout(); - enableConnectionTimeout(); -} - -void TransportLayer::A10(uint16_t source) -{ - CemiFrame frame(0); - TPDU& tpdu = frame.tpdu(); - tpdu.type(Disconnect); - tpdu.sequenceNumber(0); - _networkLayer->dataIndividualRequest(AckRequested, source, NetworkLayerParameter, SystemPriority, tpdu); -} - -void TransportLayer::A11(uint16_t tsap, Priority priority, APDU& apdu) -{ - _savedTsapConnecting = tsap; - _savedPriorityConnecting = priority; - _savedFrameConnecting = apdu.frame(); - _savedConnectingValid = true; -} + void TransportLayer::A7(Priority priority, APDU& apdu) + { + _savedPriority = priority; + TPDU& tpdu = apdu.frame().tpdu(); + tpdu.type(DataConnected); + tpdu.sequenceNumber(_seqNoSend); + _savedFrame = apdu.frame(); + _networkLayer->dataIndividualRequest(AckRequested, _connectionAddress, NetworkLayerParameter, priority, tpdu); + _repCount = 0; + enableAckTimeout(); + enableConnectionTimeout(); + } -void TransportLayer::A12(uint16_t destination, Priority priority) -{ - _connectionAddress = destination; - CemiFrame frame(0); - TPDU& tpdu = frame.tpdu(); - tpdu.type(Connect); - _networkLayer->dataIndividualRequest(AckRequested, destination, NetworkLayerParameter, priority, tpdu); - _seqNoRecv = 0; - _seqNoSend = 0; - enableConnectionTimeout(); -} - -void TransportLayer::A13(uint16_t destination) -{ - _applicationLayer.connectConfirm(destination, 0, true); -} + void TransportLayer::A8() + { + disableAckTimeout(); + incSeqNr(_seqNoSend); + _applicationLayer.dataConnectedConfirm(0); + enableConnectionTimeout(); + } -void TransportLayer::A14(uint16_t tsap, Priority priority) -{ - CemiFrame frame(0); - TPDU& tpdu = frame.tpdu(); - tpdu.type(Disconnect); - tpdu.sequenceNumber(0); - _networkLayer->dataIndividualRequest(AckRequested, _connectionAddress, NetworkLayerParameter, SystemPriority, tpdu); - _applicationLayer.disconnectConfirm(priority, tsap, true); - disableConnectionTimeout(); - disableAckTimeout(); -} - -void TransportLayer::A15(Priority priority, uint16_t tsap) -{ - _applicationLayer.disconnectConfirm(priority, tsap, true); - disableConnectionTimeout(); - disableAckTimeout(); -} + void TransportLayer::A9() + { + TPDU& tpdu = _savedFrame.tpdu(); + // tpdu is still initialized from last send + _networkLayer->dataIndividualRequest(AckRequested, _connectionAddress, NetworkLayerParameter, _savedPriority, tpdu); + _repCount += 1; + enableAckTimeout(); + enableConnectionTimeout(); + } -void TransportLayer::enableConnectionTimeout() -{ - _connectionTimeoutStartMillis = millis(); - _connectionTimeoutEnabled = true; -} + void TransportLayer::A10(uint16_t source) + { + CemiFrame frame(0); + TPDU& tpdu = frame.tpdu(); + tpdu.type(Disconnect); + tpdu.sequenceNumber(0); + _networkLayer->dataIndividualRequest(AckRequested, source, NetworkLayerParameter, SystemPriority, tpdu); + } -void TransportLayer::disableConnectionTimeout() -{ - _connectionTimeoutEnabled = false; -} + void TransportLayer::A11(uint16_t tsap, Priority priority, APDU& apdu) + { + _savedTsapConnecting = tsap; + _savedPriorityConnecting = priority; + _savedFrameConnecting = apdu.frame(); + _savedConnectingValid = true; + } -void TransportLayer::enableAckTimeout() -{ - _ackTimeoutStartMillis = millis(); - _ackTimeoutEnabled = true; -} + void TransportLayer::A12(uint16_t destination, Priority priority) + { + _connectionAddress = destination; + CemiFrame frame(0); + TPDU& tpdu = frame.tpdu(); + tpdu.type(Connect); + _networkLayer->dataIndividualRequest(AckRequested, destination, NetworkLayerParameter, priority, tpdu); + _seqNoRecv = 0; + _seqNoSend = 0; + enableConnectionTimeout(); + } -void TransportLayer::disableAckTimeout() -{ - _ackTimeoutEnabled = false; -} + void TransportLayer::A13(uint16_t destination) + { + _applicationLayer.connectConfirm(destination, 0, true); + } + + void TransportLayer::A14(uint16_t tsap, Priority priority) + { + CemiFrame frame(0); + TPDU& tpdu = frame.tpdu(); + tpdu.type(Disconnect); + tpdu.sequenceNumber(0); + _networkLayer->dataIndividualRequest(AckRequested, _connectionAddress, NetworkLayerParameter, SystemPriority, tpdu); + _applicationLayer.disconnectConfirm(priority, tsap, true); + disableConnectionTimeout(); + disableAckTimeout(); + } + + void TransportLayer::A15(Priority priority, uint16_t tsap) + { + _applicationLayer.disconnectConfirm(priority, tsap, true); + disableConnectionTimeout(); + disableAckTimeout(); + } + + void TransportLayer::enableConnectionTimeout() + { + _connectionTimeoutStartMillis = millis(); + _connectionTimeoutEnabled = true; + } + + void TransportLayer::disableConnectionTimeout() + { + _connectionTimeoutEnabled = false; + } + + void TransportLayer::enableAckTimeout() + { + _ackTimeoutStartMillis = millis(); + _ackTimeoutEnabled = true; + } + + void TransportLayer::disableAckTimeout() + { + _ackTimeoutEnabled = false; + } +} \ No newline at end of file diff --git a/src/knx/transport_layer/transport_layer.h b/src/knx/transport_layer/transport_layer.h index 94dcc6f1..7fb107eb 100644 --- a/src/knx/transport_layer/transport_layer.h +++ b/src/knx/transport_layer/transport_layer.h @@ -7,116 +7,119 @@ #include -class ApplicationLayer; -class APDU; -class NetworkLayer; -class Platform; +namespace Knx +{ + class ApplicationLayer; + class APDU; + class NetworkLayer; + class Platform; -enum StateType { Closed, OpenIdle, OpenWait, Connecting }; + enum StateType { Closed, OpenIdle, OpenWait, Connecting }; -class TransportLayer -{ - public: - TransportLayer(ApplicationLayer& layer); - void networkLayer(NetworkLayer& layer); - void groupAddressTable(AddressTableObject& addrTable); + class TransportLayer + { + public: + TransportLayer(ApplicationLayer& layer); + void networkLayer(NetworkLayer& layer); + void groupAddressTable(AddressTableObject& addrTable); - #pragma region from network layer - void dataIndividualIndication(uint16_t destination, HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu); - void dataIndividualConfirm(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu, bool status); - void dataGroupIndication(uint16_t destination, HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu); - void dataGroupConfirm(AckType ack, uint16_t source, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu, bool status); - void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu); - void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu, bool status); - void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu); - void dataSystemBroadcastConfirm(AckType ack, HopCountType hopType, TPDU& tpdu, Priority priority, bool status); - #pragma endregion + #pragma region from network layer + void dataIndividualIndication(uint16_t destination, HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu); + void dataIndividualConfirm(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu, bool status); + void dataGroupIndication(uint16_t destination, HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu); + void dataGroupConfirm(AckType ack, uint16_t source, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu, bool status); + void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu); + void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu, bool status); + void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu); + void dataSystemBroadcastConfirm(AckType ack, HopCountType hopType, TPDU& tpdu, Priority priority, bool status); + #pragma endregion - #pragma region from application layer - /** - * Request to send an APDU that via multicast. See 3.2 of @cite knx:3/3/4. - * See also ApplicationLayer::dataGroupConfirm and ApplicationLayer::dataGroupIndication. - * This method is called by the ApplicationLayer. - * - * @param tsap used the find the correct GroupObject with the help of the AssociationTableObject. - * See 3.1.1 of @cite knx:3/3/7 - * - * @param apdu The submitted APDU. - * - * @param priority The ::Priority of the request. - * - * @param hopType Should routing be endless or should the NetworkLayer::hopCount be used? See also ::HopCountType. - * - * @param ack Did we want a DataLinkLayer acknowledgement? See ::AckType. - */ - void dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu); - void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu); - void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu); - void dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu); + #pragma region from application layer + /** + * Request to send an APDU that via multicast. See 3.2 of @cite knx:3/3/4. + * See also ApplicationLayer::dataGroupConfirm and ApplicationLayer::dataGroupIndication. + * This method is called by the ApplicationLayer. + * + * @param tsap used the find the correct GroupObject with the help of the AssociationTableObject. + * See 3.1.1 of @cite knx:3/3/7 + * + * @param apdu The submitted APDU. + * + * @param priority The ::Priority of the request. + * + * @param hopType Should routing be endless or should the NetworkLayer::hopCount be used? See also ::HopCountType. + * + * @param ack Did we want a DataLinkLayer acknowledgement? See ::AckType. + */ + void dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu); + void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu); + void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu); + void dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu); - void connectRequest(uint16_t destination, Priority priority); - void disconnectRequest(uint16_t tsap, Priority priority); - // apdu must be valid until it was confirmed - void dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu); + void connectRequest(uint16_t destination, Priority priority); + void disconnectRequest(uint16_t tsap, Priority priority); + // apdu must be valid until it was confirmed + void dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu); - uint8_t getTpciSeqNum(); - uint16_t getConnectionAddress(); - #pragma endregion + uint8_t getTpciSeqNum(); + uint16_t getConnectionAddress(); + #pragma endregion - #pragma region other - void connectionTimeoutIndication(); - void ackTimeoutIndication(); - void loop(); - #pragma endregion + #pragma region other + void connectionTimeoutIndication(); + void ackTimeoutIndication(); + void loop(); + #pragma endregion - private: - #pragma region States - Priority _savedPriority = LowPriority; - CemiFrame _savedFrame; - Priority _savedPriorityConnecting; - CemiFrame _savedFrameConnecting; - uint16_t _savedTsapConnecting; - bool _savedConnectingValid = false; - enum StateEvent - { - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, - E15, E16, E17, E18, E19, E20, E21, E22, E23, E24, E25, E26, E27 - }; - StateType _currentState = Closed; - void sendControlTelegram(TpduType pduType, uint8_t seqNo); - void A0(); - void A1(uint16_t source); - void A2(uint16_t source, Priority priority, APDU& apdu); - void A3(uint16_t source, Priority priority, TPDU& recTpdu); - void A4(uint16_t source, Priority priority, TPDU& recTpdu); - void A5(uint16_t source); - void A6(uint16_t source); - void A7(Priority priority, APDU& apdu); - void A8(); - void A9(); - void A10(uint16_t source); - void A11(uint16_t tsap, Priority priority, APDU& apdu); - void A12(uint16_t destination, Priority priority); - void A13(uint16_t destination); - void A14(uint16_t destination, Priority priority); - void A15(Priority priority, uint16_t tsap); - void enableConnectionTimeout(); - void disableConnectionTimeout(); - void enableAckTimeout(); - void disableAckTimeout(); - uint16_t _connectionAddress = 0; - uint8_t _seqNoSend = 0; - uint8_t _seqNoRecv = 0; - bool _connectionTimeoutEnabled = false; - uint32_t _connectionTimeoutStartMillis = 0; - uint16_t _connectionTimeoutMillis = 6000; - bool _ackTimeoutEnabled = false; - uint32_t _ackTimeoutStartMillis = 0; - uint16_t _ackTimeoutMillis = 3000; - uint8_t _repCount = 0; - uint8_t _maxRepCount = 3; - #pragma endregion - ApplicationLayer& _applicationLayer; - AddressTableObject* _groupAddressTable; - NetworkLayer* _networkLayer; -}; + private: + #pragma region States + Priority _savedPriority = LowPriority; + CemiFrame _savedFrame; + Priority _savedPriorityConnecting; + CemiFrame _savedFrameConnecting; + uint16_t _savedTsapConnecting; + bool _savedConnectingValid = false; + enum StateEvent + { + E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, + E15, E16, E17, E18, E19, E20, E21, E22, E23, E24, E25, E26, E27 + }; + StateType _currentState = Closed; + void sendControlTelegram(TpduType pduType, uint8_t seqNo); + void A0(); + void A1(uint16_t source); + void A2(uint16_t source, Priority priority, APDU& apdu); + void A3(uint16_t source, Priority priority, TPDU& recTpdu); + void A4(uint16_t source, Priority priority, TPDU& recTpdu); + void A5(uint16_t source); + void A6(uint16_t source); + void A7(Priority priority, APDU& apdu); + void A8(); + void A9(); + void A10(uint16_t source); + void A11(uint16_t tsap, Priority priority, APDU& apdu); + void A12(uint16_t destination, Priority priority); + void A13(uint16_t destination); + void A14(uint16_t destination, Priority priority); + void A15(Priority priority, uint16_t tsap); + void enableConnectionTimeout(); + void disableConnectionTimeout(); + void enableAckTimeout(); + void disableAckTimeout(); + uint16_t _connectionAddress = 0; + uint8_t _seqNoSend = 0; + uint8_t _seqNoRecv = 0; + bool _connectionTimeoutEnabled = false; + uint32_t _connectionTimeoutStartMillis = 0; + uint16_t _connectionTimeoutMillis = 6000; + bool _ackTimeoutEnabled = false; + uint32_t _ackTimeoutStartMillis = 0; + uint16_t _ackTimeoutMillis = 3000; + uint8_t _repCount = 0; + uint8_t _maxRepCount = 3; + #pragma endregion + ApplicationLayer& _applicationLayer; + AddressTableObject* _groupAddressTable; + NetworkLayer* _networkLayer; + }; +} \ No newline at end of file diff --git a/src/knx/util/aes.c b/src/knx/util/aes.c index 07d4ba9f..475d9450 100644 --- a/src/knx/util/aes.c +++ b/src/knx/util/aes.c @@ -63,8 +63,6 @@ NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0) #endif - - /*****************************************************************************/ /* Private variables: */ /*****************************************************************************/ diff --git a/src/knx/util/logger.cpp b/src/knx/util/logger.cpp index 18b98f1e..817502d6 100644 --- a/src/knx/util/logger.cpp +++ b/src/knx/util/logger.cpp @@ -2,170 +2,175 @@ #include "../bits.h" -Map Logger::_loggers; -Logger Logger::_logger; - -Logger& Logger::logger(const char* name) +namespace Knx { - _logger.name(name); - return _logger; -} + Map Logger::_loggers; + Logger Logger::_logger; -void Logger::logLevel(const char* name, LogType level) -{ - _loggers.insertOrAssign(name, level); -} + Logger& Logger::logger(const char* name) + { + _logger.name(name); + return _logger; + } -void Logger::info(const char* message, ...) -{ + void Logger::logLevel(const char* name, LogType level) + { + _loggers.insertOrAssign(name, level); + } + + void Logger::info(const char* message, ...) + { #ifndef KNX_NO_PRINT - va_list objects; - va_start( objects, message); - log(LogType::Info, message, objects); - va_end(objects); + va_list objects; + va_start( objects, message); + log(LogType::Info, message, objects); + va_end(objects); #endif -} + } -void Logger::warning(const char* message, ...) -{ + void Logger::warning(const char* message, ...) + { #ifndef KNX_NO_PRINT - va_list objects; - va_start( objects, message); - log(LogType::Warning, message, objects); - va_end(objects); + va_list objects; + va_start( objects, message); + log(LogType::Warning, message, objects); + va_end(objects); #endif -} + } -void Logger::error(const char* message, ...) -{ + void Logger::error(const char* message, ...) + { #ifndef KNX_NO_PRINT - va_list objects; - va_start( objects, message); - log(LogType::Error, message, objects); - va_end(objects); + va_list objects; + va_start( objects, message); + log(LogType::Error, message, objects); + va_end(objects); #endif -} + } -void Logger::critical(const char* message, ...) -{ + void Logger::critical(const char* message, ...) + { #ifndef KNX_NO_PRINT - va_list objects; - va_start( objects, message); - log(LogType::Critical, message, objects); - va_end(objects); + va_list objects; + va_start( objects, message); + log(LogType::Critical, message, objects); + va_end(objects); #endif -} + } -void Logger::exception(const char* message, ...) -{ + void Logger::exception(const char* message, ...) + { #ifndef KNX_NO_PRINT - va_list objects; - va_start( objects, message); - log(LogType::Exception, message, objects); - va_end(objects); + va_list objects; + va_start( objects, message); + log(LogType::Exception, message, objects); + va_end(objects); #endif -} + } -bool Logger::log(LogType type) -{ + bool Logger::log(LogType type) + { #ifndef KNX_NO_PRINT - /*LogType* level = _loggers.get(_name); + /*LogType* level = _loggers.get(_name); - if (level == nullptr) - { - print("Logger "); - print(_name); - print(" is disabled. Use Logger::logLevel(\""); - print(_name); - println("\", Logger::Info) to enable."); - _loggers.insertOrAssign(_name, Info); - return false; - } + if (level == nullptr) + { + print("Logger "); + print(_name); + print(" is disabled. Use Logger::logLevel(\""); + print(_name); + println("\", Logger::Info) to enable."); + _loggers.insertOrAssign(_name, Info); + return false; + } - if (*level > type) - return false; -*/ - print(millis()); - print(" "); - print(_name); - print("\t"); - print(enum_name(type)); - print(" "); - return true; + if (*level > type) + return false; + */ + print(millis()); + print(" "); + print(_name); + print("\t"); + print(enum_name(type)); + print(" "); + return true; #else - return false; + return false; #endif -} + } -void Logger::log(LogType type, const char* format, va_list args) -{ + void Logger::log(LogType type, const char* format, va_list args) + { #ifndef KNX_NO_PRINT - if (!log(type)) - return; - while (*format) - { - if (*format == '%') - { - format++; + if (!log(type)) + return; - if (*format == 'd') - { - print(va_arg(args, int)); - } - if (*format == 'x') - { - print(va_arg(args, int), HEX); - } - else if (*format == 's') - { - print(va_arg(args, char*)); - } - else if (*format == 'f') + while (*format) + { + if (*format == '%') { - print(va_arg(args, double)); + format++; + + if (*format == 'd') + { + print(va_arg(args, int)); + } + + if (*format == 'x') + { + print(va_arg(args, int), HEX); + } + else if (*format == 's') + { + print(va_arg(args, char*)); + } + else if (*format == 'f') + { + print(va_arg(args, double)); + } + else if (*format == 'B') + { + printHex("", va_arg(args, uint8_t*), va_arg(args, size_t), false); + } } - else if (*format == 'B') + else { - printHex("", va_arg(args, uint8_t*), va_arg(args, size_t), false); + print(*format); } - } - else - { - print(*format); - } - format++; - } + format++; + } - va_end(args); - println(); + va_end(args); + println(); #endif -} + } #ifndef KNX_NO_PRINT -const char* Logger::enum_name(LogType type) -{ - switch (type) + const char* Logger::enum_name(LogType type) { - case LogType::Info: - return "INFO"; + switch (type) + { + case LogType::Info: + return "INFO"; - case LogType::Warning: - return "WARN"; + case LogType::Warning: + return "WARN"; - case LogType::Error: - return "ERR "; + case LogType::Error: + return "ERR "; - case LogType::Critical: - return "CRIT"; + case LogType::Critical: + return "CRIT"; - case LogType::Exception: - return "EXCE"; + case LogType::Exception: + return "EXCE"; - case LogType::Disabled: - return "DISA"; - } + case LogType::Disabled: + return "DISA"; + } - return ""; -} + return ""; + } #endif +} \ No newline at end of file diff --git a/src/knx/util/logger.h b/src/knx/util/logger.h index acd63b66..d9cbea78 100644 --- a/src/knx/util/logger.h +++ b/src/knx/util/logger.h @@ -3,12 +3,14 @@ #include #include "simple_map.h" -class IPrintable +namespace Knx { - public: - virtual void printIt() const = 0; - virtual ~IPrintable() = default; -}; + class IPrintable + { + public: + virtual void printIt() const = 0; + virtual ~IPrintable() = default; + }; #ifndef KNX_NO_PRINT void println(); @@ -17,73 +19,74 @@ class IPrintable #define print(...) do {} while(0) #define println(...) do {} while(0) #endif -class Logger -{ - public: - enum LogType { Info, Warning, Error, Critical, Exception, Disabled}; - static Logger& logger(const char* name); - static void logLevel(const char* name, LogType level); - void info(const char* message, IPrintable& object) - { - if (!log(LogType::Info)) - return; + class Logger + { + public: + enum LogType { Info, Warning, Error, Critical, Exception, Disabled}; + static Logger& logger(const char* name); + static void logLevel(const char* name, LogType level); + void info(const char* message, IPrintable& object) + { + if (!log(LogType::Info)) + return; - print(message); - object.printIt(); - println(); - } - void info(const char* message, ...); - void warning(const char* message, IPrintable& object) - { - if (!log(LogType::Warning)) - return; + print(message); + object.printIt(); + println(); + } + void info(const char* message, ...); + void warning(const char* message, IPrintable& object) + { + if (!log(LogType::Warning)) + return; - print(message); - object.printIt(); - println(); - } - void warning(const char* message, ...); - void error(const char* message, IPrintable& object) - { - if (!log(LogType::Error)) - return; + print(message); + object.printIt(); + println(); + } + void warning(const char* message, ...); + void error(const char* message, IPrintable& object) + { + if (!log(LogType::Error)) + return; - print(message); - object.printIt(); - println(); - } - void error(const char* message, ...); - void critical(const char* message, IPrintable& object) - { - if (!log(LogType::Critical)) - return; + print(message); + object.printIt(); + println(); + } + void error(const char* message, ...); + void critical(const char* message, IPrintable& object) + { + if (!log(LogType::Critical)) + return; - print(message); - object.printIt(); - println(); - } - void critical(const char* message, ...); - void exception(const char* message, IPrintable& object) - { - if (!log(LogType::Exception)) - return; + print(message); + object.printIt(); + println(); + } + void critical(const char* message, ...); + void exception(const char* message, IPrintable& object) + { + if (!log(LogType::Exception)) + return; - print(message); - object.printIt(); - println(); - } - void exception(const char* message, ...); - protected: - Logger() {} - bool log(LogType type); - void log(LogType type, const char* format, va_list args); - void name(const char* value) - { - _name = value; - } - private: - const char* enum_name(LogType type); - const char* _name = ""; - static Map _loggers; - static Logger _logger; -}; \ No newline at end of file + print(message); + object.printIt(); + println(); + } + void exception(const char* message, ...); + protected: + Logger() {} + bool log(LogType type); + void log(LogType type, const char* format, va_list args); + void name(const char* value) + { + _name = value; + } + private: + const char* enum_name(LogType type); + const char* _name = ""; + static Map _loggers; + static Logger _logger; + }; +} \ No newline at end of file diff --git a/src/knx/util/memory.cpp b/src/knx/util/memory.cpp index 80dbb88d..734da1c0 100644 --- a/src/knx/util/memory.cpp +++ b/src/knx/util/memory.cpp @@ -6,514 +6,518 @@ #define LOGGER Logger::logger("Memory") -Memory::Memory(Platform& platform, DeviceObject& deviceObject) - : _platform(platform), _deviceObject(deviceObject) -{} - -Memory::~Memory() -{} - -void Memory::readMemory() +namespace Knx { - LOGGER.info("restoring persistant Memory"); + Memory::Memory(Platform& platform, DeviceObject& deviceObject) + : _platform(platform), _deviceObject(deviceObject) + {} - uint8_t* flashStart = _platform.getNonVolatileMemoryStart(); - size_t flashSize = _platform.getNonVolatileMemorySize(); + Memory::~Memory() + {} - if (flashStart == nullptr) + void Memory::readMemory() { - LOGGER.error("no user flash available;"); - return; - } + LOGGER.info("restoring persistant Memory"); - LOGGER.info("content %B", flashStart, _metadataSize); + uint8_t* flashStart = _platform.getNonVolatileMemoryStart(); + size_t flashSize = _platform.getNonVolatileMemorySize(); - uint16_t metadataBlockSize = alignToPageSize(_metadataSize); + if (flashStart == nullptr) + { + LOGGER.error("no user flash available;"); + return; + } - _freeList = new MemoryBlock(flashStart + metadataBlockSize, flashSize - metadataBlockSize); + LOGGER.info("content %B", flashStart, _metadataSize); - uint16_t apiVersion = 0; - const uint8_t* buffer = popWord(apiVersion, flashStart); + uint16_t metadataBlockSize = alignToPageSize(_metadataSize); - uint16_t manufacturerId = 0; - buffer = popWord(manufacturerId, buffer); + _freeList = new MemoryBlock(flashStart + metadataBlockSize, flashSize - metadataBlockSize); - uint8_t hardwareType[LEN_HARDWARE_TYPE] = {0}; - buffer = popByteArray(hardwareType, LEN_HARDWARE_TYPE, buffer); + uint16_t apiVersion = 0; + const uint8_t* buffer = popWord(apiVersion, flashStart); - uint16_t version = 0; - buffer = popWord(version, buffer); + uint16_t manufacturerId = 0; + buffer = popWord(manufacturerId, buffer); - VersionCheckResult versionCheck = FlashAllInvalid; + uint8_t hardwareType[LEN_HARDWARE_TYPE] = {0}; + buffer = popByteArray(hardwareType, LEN_HARDWARE_TYPE, buffer); - // first check correct format of deviceObject-API - if (_deviceObject.apiVersion == apiVersion) - { - if (_versionCheckCallback != 0) - { - versionCheck = _versionCheckCallback(manufacturerId, hardwareType, version); - // callback should provide infomation about version check failure reasons - } - else if (_deviceObject.manufacturerId() == manufacturerId && - memcmp(_deviceObject.hardwareType(), hardwareType, LEN_HARDWARE_TYPE) == 0) + uint16_t version = 0; + buffer = popWord(version, buffer); + + VersionCheckResult versionCheck = FlashAllInvalid; + + // first check correct format of deviceObject-API + if (_deviceObject.apiVersion == apiVersion) { - if (_deviceObject.version() == version) + if (_versionCheckCallback != 0) + { + versionCheck = _versionCheckCallback(manufacturerId, hardwareType, version); + // callback should provide infomation about version check failure reasons + } + else if (_deviceObject.manufacturerId() == manufacturerId && + memcmp(_deviceObject.hardwareType(), hardwareType, LEN_HARDWARE_TYPE) == 0) { - versionCheck = FlashValid; + if (_deviceObject.version() == version) + { + versionCheck = FlashValid; + } + else + { + versionCheck = FlashTablesInvalid; + } } else { - versionCheck = FlashTablesInvalid; + LOGGER.warning("manufacturerId or hardwareType are different"); + LOGGER.warning("expexted manufacturerId: %x , stored manufacturerId: %x", + _deviceObject.manufacturerId(), manufacturerId); + LOGGER.warning("expexted hardwareType: %B, stored hardwareType: %B", + _deviceObject.hardwareType(), LEN_HARDWARE_TYPE, + hardwareType, LEN_HARDWARE_TYPE); } } else { - LOGGER.warning("manufacturerId or hardwareType are different"); - LOGGER.warning("expexted manufacturerId: %x , stored manufacturerId: %x", - _deviceObject.manufacturerId(), manufacturerId); - LOGGER.warning("expexted hardwareType: %B, stored hardwareType: %B", - _deviceObject.hardwareType(), LEN_HARDWARE_TYPE, - hardwareType, LEN_HARDWARE_TYPE); + LOGGER.warning("DataObject api changed, any data stored in flash is invalid."); + LOGGER.warning("expexted DataObject api version: %x, stored api version: %x", _deviceObject.apiVersion, apiVersion); } - } - else - { - LOGGER.warning("DataObject api changed, any data stored in flash is invalid."); - LOGGER.warning("expexted DataObject api version: %x, stored api version: %x", _deviceObject.apiVersion, apiVersion); - } - if (versionCheck == FlashAllInvalid) - { - LOGGER.warning("You need to reprogram PA and application with ETS!"); - return; - } + if (versionCheck == FlashAllInvalid) + { + LOGGER.warning("You need to reprogram PA and application with ETS!"); + return; + } - LOGGER.info("saverestores %d", _saveCount); + LOGGER.info("saverestores %d", _saveCount); - for (int i = 0; i < _saveCount; i++) - { - LOGGER.info("Offset %d", buffer - flashStart); - buffer = _saveRestores[i]->restore(buffer); - } + for (int i = 0; i < _saveCount; i++) + { + LOGGER.info("Offset %d", buffer - flashStart); + buffer = _saveRestores[i]->restore(buffer); + } - LOGGER.info("restored saveRestores"); + LOGGER.info("restored saveRestores"); - if (versionCheck == FlashTablesInvalid) - { - LOGGER.warning("TableObjects are referring to an older firmware version and are not loaded"); - return; - } + if (versionCheck == FlashTablesInvalid) + { + LOGGER.warning("TableObjects are referring to an older firmware version and are not loaded"); + return; + } - LOGGER.info("tableObjs %d", _tableObjCount); + LOGGER.info("tableObjs %d", _tableObjCount); - for (int i = 0; i < _tableObjCount; i++) - { - ptrdiff_t offset = (buffer - flashStart); - buffer = _tableObjects[i]->restore(buffer); - uint16_t memorySize = 0; - buffer = popWord(memorySize, buffer); - LOGGER.info("Offset %d, Size %d", offset, memorySize); - if (memorySize == 0) - continue; - - // this works because TableObject saves a relative addr and restores it itself - addNewUsedBlock(_tableObjects[i]->_data, memorySize); - } + for (int i = 0; i < _tableObjCount; i++) + { + ptrdiff_t offset = (buffer - flashStart); + buffer = _tableObjects[i]->restore(buffer); + uint16_t memorySize = 0; + buffer = popWord(memorySize, buffer); + LOGGER.info("Offset %d, Size %d", offset, memorySize); - LOGGER.info("restored Tableobjects"); -} + if (memorySize == 0) + continue; -void Memory::writeMemory() -{ - LOGGER.info("writing persistang memory"); - // first get the necessary size of the writeBuffer - uint16_t writeBufferSize = _metadataSize; + // this works because TableObject saves a relative addr and restores it itself + addNewUsedBlock(_tableObjects[i]->_data, memorySize); + } - for (int i = 0; i < _saveCount; i++) - writeBufferSize = MAX(writeBufferSize, _saveRestores[i]->saveSize()); + LOGGER.info("restored Tableobjects"); + } - for (int i = 0; i < _tableObjCount; i++) - writeBufferSize = MAX(writeBufferSize, _tableObjects[i]->saveSize() + 2 /*for memory pos*/); + void Memory::writeMemory() + { + LOGGER.info("writing persistang memory"); + // first get the necessary size of the writeBuffer + uint16_t writeBufferSize = _metadataSize; - uint8_t buffer[writeBufferSize]; - uint32_t flashPos = 0; - uint8_t* bufferPos = buffer; + for (int i = 0; i < _saveCount; i++) + writeBufferSize = MAX(writeBufferSize, _saveRestores[i]->saveSize()); - bufferPos = pushWord(_deviceObject.apiVersion, bufferPos); - bufferPos = pushWord(_deviceObject.manufacturerId(), bufferPos); - bufferPos = pushByteArray(_deviceObject.hardwareType(), LEN_HARDWARE_TYPE, bufferPos); - bufferPos = pushWord(_deviceObject.version(), bufferPos); + for (int i = 0; i < _tableObjCount; i++) + writeBufferSize = MAX(writeBufferSize, _tableObjects[i]->saveSize() + 2 /*for memory pos*/); - flashPos = _platform.writeNonVolatileMemory(flashPos, buffer, bufferPos - buffer); + uint8_t buffer[writeBufferSize]; + uint32_t flashPos = 0; + uint8_t* bufferPos = buffer; - LOGGER.info("write saveRestores %d", _saveCount); + bufferPos = pushWord(_deviceObject.apiVersion, bufferPos); + bufferPos = pushWord(_deviceObject.manufacturerId(), bufferPos); + bufferPos = pushByteArray(_deviceObject.hardwareType(), LEN_HARDWARE_TYPE, bufferPos); + bufferPos = pushWord(_deviceObject.version(), bufferPos); - for (int i = 0; i < _saveCount; i++) - { - bufferPos = _saveRestores[i]->save(buffer); flashPos = _platform.writeNonVolatileMemory(flashPos, buffer, bufferPos - buffer); - } - LOGGER.info("save tableobjs %d", _tableObjCount); + LOGGER.info("write saveRestores %d", _saveCount); - for (int i = 0; i < _tableObjCount; i++) - { - bufferPos = _tableObjects[i]->save(buffer); + for (int i = 0; i < _saveCount; i++) + { + bufferPos = _saveRestores[i]->save(buffer); + flashPos = _platform.writeNonVolatileMemory(flashPos, buffer, bufferPos - buffer); + } + + LOGGER.info("save tableobjs %d", _tableObjCount); - //save to size of the memoryblock for tableobject too, so that we can rebuild the usedList and freeList - if (_tableObjects[i]->_data != nullptr) + for (int i = 0; i < _tableObjCount; i++) { - MemoryBlock* block = findBlockInList(_usedList, _tableObjects[i]->_data); + bufferPos = _tableObjects[i]->save(buffer); - if (block == nullptr) + //save to size of the memoryblock for tableobject too, so that we can rebuild the usedList and freeList + if (_tableObjects[i]->_data != nullptr) { - LOGGER.error("_data of TableObject not in _usedList"); - _platform.fatalError(); + MemoryBlock* block = findBlockInList(_usedList, _tableObjects[i]->_data); + + if (block == nullptr) + { + LOGGER.error("_data of TableObject not in _usedList"); + _platform.fatalError(); + } + + bufferPos = pushWord(block->size, bufferPos); } + else + bufferPos = pushWord(0, bufferPos); - bufferPos = pushWord(block->size, bufferPos); + flashPos = _platform.writeNonVolatileMemory(flashPos, buffer, bufferPos - buffer); } - else - bufferPos = pushWord(0, bufferPos); - flashPos = _platform.writeNonVolatileMemory(flashPos, buffer, bufferPos - buffer); + _platform.commitNonVolatileMemory(); } - _platform.commitNonVolatileMemory(); -} + void Memory::saveMemory() + { + _platform.commitNonVolatileMemory(); + } -void Memory::saveMemory() -{ - _platform.commitNonVolatileMemory(); -} + void Memory::addSaveRestore(SaveRestore* obj) + { + if (_saveCount >= MAXSAVE - 1) + return; -void Memory::addSaveRestore(SaveRestore* obj) -{ - if (_saveCount >= MAXSAVE - 1) - return; + _saveRestores[_saveCount] = obj; + _saveCount += 1; + _metadataSize += obj->saveSize(); + } - _saveRestores[_saveCount] = obj; - _saveCount += 1; - _metadataSize += obj->saveSize(); -} + void Memory::addSaveRestore(TableObject* obj) + { + if (_tableObjCount >= MAXTABLEOBJ) + return; -void Memory::addSaveRestore(TableObject* obj) -{ - if (_tableObjCount >= MAXTABLEOBJ) - return; + _tableObjects[_tableObjCount] = obj; + _tableObjCount += 1; + _metadataSize += obj->saveSize(); + _metadataSize += 2; // for size + } - _tableObjects[_tableObjCount] = obj; - _tableObjCount += 1; - _metadataSize += obj->saveSize(); - _metadataSize += 2; // for size -} + uint8_t* Memory::allocMemory(size_t size) + { + // always allocate aligned to pagesize + size = alignToPageSize(size); -uint8_t* Memory::allocMemory(size_t size) -{ - // always allocate aligned to pagesize - size = alignToPageSize(size); + MemoryBlock* freeBlock = _freeList; + MemoryBlock* blockToUse = nullptr; + + // find the smallest possible block that is big enough + while (freeBlock) + { + if (freeBlock->size >= size) + { + if (blockToUse != nullptr && (blockToUse->size - size) > (freeBlock->size - size)) + blockToUse = freeBlock; + else if (blockToUse == nullptr) + blockToUse = freeBlock; + } - MemoryBlock* freeBlock = _freeList; - MemoryBlock* blockToUse = nullptr; + freeBlock = freeBlock->next; + } - // find the smallest possible block that is big enough - while (freeBlock) - { - if (freeBlock->size >= size) + if (!blockToUse) { - if (blockToUse != nullptr && (blockToUse->size - size) > (freeBlock->size - size)) - blockToUse = freeBlock; - else if (blockToUse == nullptr) - blockToUse = freeBlock; + LOGGER.error("No available non volatile memory!"); + _platform.fatalError(); } - freeBlock = freeBlock->next; - } + if (blockToUse->size == size) + { + // use whole block + removeFromFreeList(blockToUse); + addToUsedList(blockToUse); + return blockToUse->address; + } + else + { + // split block + MemoryBlock* newBlock = new MemoryBlock(blockToUse->address, size); + addToUsedList(newBlock); - if (!blockToUse) - { - LOGGER.error("No available non volatile memory!"); - _platform.fatalError(); - } + blockToUse->address += size; + blockToUse->size -= size; - if (blockToUse->size == size) - { - // use whole block - removeFromFreeList(blockToUse); - addToUsedList(blockToUse); - return blockToUse->address; + return newBlock->address; + } } - else - { - // split block - MemoryBlock* newBlock = new MemoryBlock(blockToUse->address, size); - addToUsedList(newBlock); - blockToUse->address += size; - blockToUse->size -= size; - return newBlock->address; - } -} + void Memory::freeMemory(uint8_t* ptr) + { + MemoryBlock* block = _usedList; + MemoryBlock* found = nullptr; + while (block) + { + if (block->address == ptr) + { + found = block; + break; + } -void Memory::freeMemory(uint8_t* ptr) -{ - MemoryBlock* block = _usedList; - MemoryBlock* found = nullptr; + block = block->next; + } - while (block) - { - if (block->address == ptr) + if (!found) { - found = block; - break; + LOGGER.error("freeMemory for not used pointer called"); + _platform.fatalError(); } - block = block->next; + removeFromUsedList(block); + addToFreeList(block); } - if (!found) + void Memory::writeMemory(uint32_t relativeAddress, size_t size, uint8_t* data) { - LOGGER.error("freeMemory for not used pointer called"); - _platform.fatalError(); + _platform.writeNonVolatileMemory(relativeAddress, data, size); } - removeFromUsedList(block); - addToFreeList(block); -} - -void Memory::writeMemory(uint32_t relativeAddress, size_t size, uint8_t* data) -{ - _platform.writeNonVolatileMemory(relativeAddress, data, size); -} - -void Memory::readMemory(uint32_t relativeAddress, size_t size, uint8_t* data) -{ - _platform.readNonVolatileMemory(relativeAddress, data, size); -} - - -uint8_t* Memory::toAbsolute(uint32_t relativeAddress) -{ - return _platform.getNonVolatileMemoryStart() + (ptrdiff_t)relativeAddress; -} - + void Memory::readMemory(uint32_t relativeAddress, size_t size, uint8_t* data) + { + _platform.readNonVolatileMemory(relativeAddress, data, size); + } -uint32_t Memory::toRelative(uint8_t* absoluteAddress) -{ - return absoluteAddress - _platform.getNonVolatileMemoryStart(); -} -MemoryBlock* Memory::removeFromList(MemoryBlock* head, MemoryBlock* item) -{ - if (head == item) + uint8_t* Memory::toAbsolute(uint32_t relativeAddress) { - MemoryBlock* newHead = head->next; - head->next = nullptr; - return newHead; + return _platform.getNonVolatileMemoryStart() + (ptrdiff_t)relativeAddress; } - if (!head || !item) + + uint32_t Memory::toRelative(uint8_t* absoluteAddress) { - LOGGER.critical("invalid parameters of Memory::removeFromList"); - _platform.fatalError(); + return absoluteAddress - _platform.getNonVolatileMemoryStart(); } - bool found = false; - MemoryBlock* block = head; - - while (block) + MemoryBlock* Memory::removeFromList(MemoryBlock* head, MemoryBlock* item) { - if (block->next == item) + if (head == item) { - found = true; - block->next = item->next; - break; + MemoryBlock* newHead = head->next; + head->next = nullptr; + return newHead; } - block = block->next; - } + if (!head || !item) + { + LOGGER.critical("invalid parameters of Memory::removeFromList"); + _platform.fatalError(); + } - if (!found) - { - LOGGER.critical("tried to remove block from list not in it"); - _platform.fatalError(); - } + bool found = false; + MemoryBlock* block = head; + + while (block) + { + if (block->next == item) + { + found = true; + block->next = item->next; + break; + } - item->next = nullptr; - return head; -} + block = block->next; + } -void Memory::removeFromFreeList(MemoryBlock* block) -{ - _freeList = removeFromList(_freeList, block); -} + if (!found) + { + LOGGER.critical("tried to remove block from list not in it"); + _platform.fatalError(); + } + item->next = nullptr; + return head; + } -void Memory::removeFromUsedList(MemoryBlock* block) -{ - _usedList = removeFromList(_usedList, block); -} + void Memory::removeFromFreeList(MemoryBlock* block) + { + _freeList = removeFromList(_freeList, block); + } -void Memory::addToUsedList(MemoryBlock* block) -{ - block->next = _usedList; - _usedList = block; -} + void Memory::removeFromUsedList(MemoryBlock* block) + { + _usedList = removeFromList(_usedList, block); + } -void Memory::addToFreeList(MemoryBlock* block) -{ - if (_freeList == nullptr) + void Memory::addToUsedList(MemoryBlock* block) { - _freeList = block; - return; + block->next = _usedList; + _usedList = block; } - // first insert free block in list - MemoryBlock* current = _freeList; - while (current) + void Memory::addToFreeList(MemoryBlock* block) { - if (current->address <= block->address && (current->next == nullptr || block->address < current->next->address)) + if (_freeList == nullptr) { - //add after current - block->next = current->next; - current->next = block; - break; + _freeList = block; + return; } - else if (current->address > block->address) + + // first insert free block in list + MemoryBlock* current = _freeList; + + while (current) { - //add before current - block->next = current; + if (current->address <= block->address && (current->next == nullptr || block->address < current->next->address)) + { + //add after current + block->next = current->next; + current->next = block; + break; + } + else if (current->address > block->address) + { + //add before current + block->next = current; + + if (current == _freeList) + _freeList = block; + + // swap current and block for merge + MemoryBlock* tmp = current; + current = block; + block = tmp; - if (current == _freeList) - _freeList = block; + break; + } - // swap current and block for merge - MemoryBlock* tmp = current; - current = block; - block = tmp; + current = current->next; + } - break; + // now check if we can merge the blocks + // first current an block + if ((current->address + current->size) == block->address) + { + current->size += block->size; + current->next = block->next; + delete block; + // check further if now current can be merged with current->next + block = current; } - current = current->next; + // if block is the last one, we are done + if (block->next == nullptr) + return; + + // now check block and block->next + if ((block->address + block->size) == block->next->address) + { + block->size += block->next->size; + block->next = block->next->next; + delete block->next; + } } - // now check if we can merge the blocks - // first current an block - if ((current->address + current->size) == block->address) + uint16_t Memory::alignToPageSize(size_t size) { - current->size += block->size; - current->next = block->next; - delete block; - // check further if now current can be merged with current->next - block = current; + size_t pageSize = 4; //_platform.flashPageSize(); // align to 32bit for now, as aligning to flash-page-size causes side effects in programming + // pagesize should be a multiply of two + return (size + pageSize - 1) & (-1 * pageSize); } - // if block is the last one, we are done - if (block->next == nullptr) - return; - - // now check block and block->next - if ((block->address + block->size) == block->next->address) + MemoryBlock* Memory::findBlockInList(MemoryBlock* head, uint8_t* address) { - block->size += block->next->size; - block->next = block->next->next; - delete block->next; - } -} + while (head != nullptr) + { + if (head->address == address) + return head; -uint16_t Memory::alignToPageSize(size_t size) -{ - size_t pageSize = 4; //_platform.flashPageSize(); // align to 32bit for now, as aligning to flash-page-size causes side effects in programming - // pagesize should be a multiply of two - return (size + pageSize - 1) & (-1 * pageSize); -} + head = head->next; + } -MemoryBlock* Memory::findBlockInList(MemoryBlock* head, uint8_t* address) -{ - while (head != nullptr) + return nullptr; + } + + void Memory::addNewUsedBlock(uint8_t* address, size_t size) { - if (head->address == address) - return head; + MemoryBlock* smallerFreeBlock = _freeList; - head = head->next; - } + // find block in freeList where the new used block is contained in + while (smallerFreeBlock) + { + if (smallerFreeBlock->next == nullptr || + (smallerFreeBlock->next != nullptr && smallerFreeBlock->next->address > address)) + break; - return nullptr; -} + smallerFreeBlock = smallerFreeBlock->next; + } -void Memory::addNewUsedBlock(uint8_t* address, size_t size) -{ - MemoryBlock* smallerFreeBlock = _freeList; + if (smallerFreeBlock == nullptr) + { + LOGGER.critical("addNewUsedBlock: no smallerBlock found"); + _platform.fatalError(); + } - // find block in freeList where the new used block is contained in - while (smallerFreeBlock) - { - if (smallerFreeBlock->next == nullptr || - (smallerFreeBlock->next != nullptr && smallerFreeBlock->next->address > address)) - break; + if ((smallerFreeBlock->address + smallerFreeBlock->size) < (address + size)) + { + LOGGER.critical("addNewUsedBlock: found block can't contain new block"); + _platform.fatalError(); + } - smallerFreeBlock = smallerFreeBlock->next; - } + if (smallerFreeBlock->address == address && smallerFreeBlock->size == size) + { + // we take thow whole block + removeFromFreeList(smallerFreeBlock); + addToUsedList(smallerFreeBlock); + return; + } - if (smallerFreeBlock == nullptr) - { - LOGGER.critical("addNewUsedBlock: no smallerBlock found"); - _platform.fatalError(); - } + if (smallerFreeBlock->address == address) + { + // we take a front part of the block + smallerFreeBlock->address += size; + smallerFreeBlock->size -= size; + } + else + { + // we take a middle or end part of the block + uint8_t* oldEndAddr = smallerFreeBlock->address + smallerFreeBlock->size; + smallerFreeBlock->size = (address - smallerFreeBlock->address); - if ((smallerFreeBlock->address + smallerFreeBlock->size) < (address + size)) - { - LOGGER.critical("addNewUsedBlock: found block can't contain new block"); - _platform.fatalError(); - } + if (address + size < oldEndAddr) + { + // we take the middle part of the block, so we need a new free block for the end part + MemoryBlock* newFreeBlock = new MemoryBlock(); + newFreeBlock->next = smallerFreeBlock->next; + newFreeBlock->address = address + size; + newFreeBlock->size = oldEndAddr - newFreeBlock->address; + smallerFreeBlock->next = newFreeBlock; + } + } - if (smallerFreeBlock->address == address && smallerFreeBlock->size == size) - { - // we take thow whole block - removeFromFreeList(smallerFreeBlock); - addToUsedList(smallerFreeBlock); - return; + MemoryBlock* newUsedBlock = new MemoryBlock(address, size); + addToUsedList(newUsedBlock); } - if (smallerFreeBlock->address == address) + void Memory::versionCheckCallback(VersionCheckCallback func) { - // we take a front part of the block - smallerFreeBlock->address += size; - smallerFreeBlock->size -= size; + _versionCheckCallback = func; } - else - { - // we take a middle or end part of the block - uint8_t* oldEndAddr = smallerFreeBlock->address + smallerFreeBlock->size; - smallerFreeBlock->size = (address - smallerFreeBlock->address); - if (address + size < oldEndAddr) - { - // we take the middle part of the block, so we need a new free block for the end part - MemoryBlock* newFreeBlock = new MemoryBlock(); - newFreeBlock->next = smallerFreeBlock->next; - newFreeBlock->address = address + size; - newFreeBlock->size = oldEndAddr - newFreeBlock->address; - smallerFreeBlock->next = newFreeBlock; - } + VersionCheckCallback Memory::versionCheckCallback() + { + return _versionCheckCallback; } - - MemoryBlock* newUsedBlock = new MemoryBlock(address, size); - addToUsedList(newUsedBlock); -} - -void Memory::versionCheckCallback(VersionCheckCallback func) -{ - _versionCheckCallback = func; -} - -VersionCheckCallback Memory::versionCheckCallback() -{ - return _versionCheckCallback; -} +} \ No newline at end of file diff --git a/src/knx/util/memory.h b/src/knx/util/memory.h index 1ebe4e04..5d32bfc5 100644 --- a/src/knx/util/memory.h +++ b/src/knx/util/memory.h @@ -13,72 +13,75 @@ #define KNX_FLASH_SIZE 1024 #endif -class MemoryBlock +namespace Knx { - public: - MemoryBlock() {}; - MemoryBlock(uint8_t* address, size_t size) - : address(address), size(size) {} - uint8_t* address = nullptr; - size_t size = 0; - MemoryBlock* next = nullptr; -}; + class MemoryBlock + { + public: + MemoryBlock() {}; + MemoryBlock(uint8_t* address, size_t size) + : address(address), size(size) {} + uint8_t* address = nullptr; + size_t size = 0; + MemoryBlock* next = nullptr; + }; -enum VersionCheckResult -{ - FlashAllInvalid = 0, //!< All flash content is not valid for this firmware, we delete it - FlashTablesInvalid = 1,//!< All table objects are invalid for this firmware, device object and saveRestores are OK - FlashValid = 2 //!< Flash content is valid and will be used -}; + enum VersionCheckResult + { + FlashAllInvalid = 0, //!< All flash content is not valid for this firmware, we delete it + FlashTablesInvalid = 1,//!< All table objects are invalid for this firmware, device object and saveRestores are OK + FlashValid = 2 //!< Flash content is valid and will be used + }; -typedef VersionCheckResult (*VersionCheckCallback)(uint16_t manufacturerId, uint8_t* hardwareType, uint16_t version); + typedef VersionCheckResult (*VersionCheckCallback)(uint16_t manufacturerId, uint8_t* hardwareType, uint16_t version); -class Memory -{ - friend class TableObject; + class Memory + { + friend class TableObject; - public: - Memory(Platform& platform, DeviceObject& deviceObject); - virtual ~Memory(); - void readMemory(); - void writeMemory(); - void saveMemory(); - void addSaveRestore(SaveRestore* obj); - void addSaveRestore(TableObject* obj); + public: + Memory(Platform& platform, DeviceObject& deviceObject); + virtual ~Memory(); + void readMemory(); + void writeMemory(); + void saveMemory(); + void addSaveRestore(SaveRestore* obj); + void addSaveRestore(TableObject* obj); - uint8_t* allocMemory(size_t size); - void freeMemory(uint8_t* ptr); - void writeMemory(uint32_t relativeAddress, size_t size, uint8_t* data); - void readMemory(uint32_t relativeAddress, size_t size, uint8_t* data); - uint8_t* toAbsolute(uint32_t relativeAddress); - uint32_t toRelative(uint8_t* absoluteAddress); + uint8_t* allocMemory(size_t size); + void freeMemory(uint8_t* ptr); + void writeMemory(uint32_t relativeAddress, size_t size, uint8_t* data); + void readMemory(uint32_t relativeAddress, size_t size, uint8_t* data); + uint8_t* toAbsolute(uint32_t relativeAddress); + uint32_t toRelative(uint8_t* absoluteAddress); - void versionCheckCallback(VersionCheckCallback func); - VersionCheckCallback versionCheckCallback(); + void versionCheckCallback(VersionCheckCallback func); + VersionCheckCallback versionCheckCallback(); - private: - void removeFromFreeList(MemoryBlock* block); - void addToUsedList(MemoryBlock* block); - void removeFromUsedList(MemoryBlock* block); - void addToFreeList(MemoryBlock* block); - uint16_t alignToPageSize(size_t size); - MemoryBlock* removeFromList(MemoryBlock* head, MemoryBlock* item); - MemoryBlock* findBlockInList(MemoryBlock* head, uint8_t* address); - void addNewUsedBlock(uint8_t* address, size_t size); + private: + void removeFromFreeList(MemoryBlock* block); + void addToUsedList(MemoryBlock* block); + void removeFromUsedList(MemoryBlock* block); + void addToFreeList(MemoryBlock* block); + uint16_t alignToPageSize(size_t size); + MemoryBlock* removeFromList(MemoryBlock* head, MemoryBlock* item); + MemoryBlock* findBlockInList(MemoryBlock* head, uint8_t* address); + void addNewUsedBlock(uint8_t* address, size_t size); - void readEraseBlockToBuffer(uint32_t blockNum); - uint8_t* eraseBlockStart(uint32_t blockNum); - uint8_t* eraseBlockEnd(uint32_t blockNum); - void saveBufferdEraseBlock(); + void readEraseBlockToBuffer(uint32_t blockNum); + uint8_t* eraseBlockStart(uint32_t blockNum); + uint8_t* eraseBlockEnd(uint32_t blockNum); + void saveBufferdEraseBlock(); - VersionCheckCallback _versionCheckCallback = 0; - Platform& _platform; - DeviceObject& _deviceObject; - SaveRestore* _saveRestores[MAXSAVE] = {0}; - TableObject* _tableObjects[MAXTABLEOBJ] = {0}; - uint8_t _saveCount = 0; - uint8_t _tableObjCount = 0; - MemoryBlock* _freeList = nullptr; - MemoryBlock* _usedList = nullptr; - uint16_t _metadataSize = 6 + LEN_HARDWARE_TYPE; // accounting for 3x pushWord and pushByteArray of length LEN_HARDWARE_TYPE -}; + VersionCheckCallback _versionCheckCallback = 0; + Platform& _platform; + DeviceObject& _deviceObject; + SaveRestore* _saveRestores[MAXSAVE] = {0}; + TableObject* _tableObjects[MAXTABLEOBJ] = {0}; + uint8_t _saveCount = 0; + uint8_t _tableObjCount = 0; + MemoryBlock* _freeList = nullptr; + MemoryBlock* _usedList = nullptr; + uint16_t _metadataSize = 6 + LEN_HARDWARE_TYPE; // accounting for 3x pushWord and pushByteArray of length LEN_HARDWARE_TYPE + }; +} \ No newline at end of file diff --git a/src/knx/util/save_restore.h b/src/knx/util/save_restore.h index 12d07174..7482d08b 100644 --- a/src/knx/util/save_restore.h +++ b/src/knx/util/save_restore.h @@ -1,43 +1,47 @@ #pragma once #include -/** - * Interface for classes that can save and restore data from a buffer. - */ -class SaveRestore + +namespace Knx { - public: - /** - * This method is called when the object should save its state to the buffer. - * - * @param buffer The buffer the object should save its state to. - * - * @return The buffer plus the size of the object state. The next object will use this value as - * the start of its buffer. - */ - virtual uint8_t* save(uint8_t* buffer) - { - return buffer; - } + /** + * Interface for classes that can save and restore data from a buffer. + */ + class SaveRestore + { + public: + /** + * This method is called when the object should save its state to the buffer. + * + * @param buffer The buffer the object should save its state to. + * + * @return The buffer plus the size of the object state. The next object will use this value as + * the start of its buffer. + */ + virtual uint8_t* save(uint8_t* buffer) + { + return buffer; + } - /** - * This method is called when the object should restore its state from the buffer. - * - * @param buffer The buffer the object should restore its state from. - * - * @return The buffer plus the size of the object state. The next object will use this value as - * the start of its buffer. - */ - virtual const uint8_t* restore(const uint8_t* buffer) - { - return buffer; - } + /** + * This method is called when the object should restore its state from the buffer. + * + * @param buffer The buffer the object should restore its state from. + * + * @return The buffer plus the size of the object state. The next object will use this value as + * the start of its buffer. + */ + virtual const uint8_t* restore(const uint8_t* buffer) + { + return buffer; + } - /** - * @return The maximum number of bytes the object needs to save its state. - */ - virtual uint16_t saveSize() - { - return 0; - } -}; \ No newline at end of file + /** + * @return The maximum number of bytes the object needs to save its state. + */ + virtual uint16_t saveSize() + { + return 0; + } + }; +} \ No newline at end of file diff --git a/src/knx/util/simple_map.h b/src/knx/util/simple_map.h index 658ba662..c767af27 100644 --- a/src/knx/util/simple_map.h +++ b/src/knx/util/simple_map.h @@ -2,135 +2,139 @@ #include -// Provides a simple unordered map which is based on two arrays of different data types, namely K and V. -// One array is used for the keys, the other array is used for the values. -// Tracking of free/occupied slots in the arrays is realized by a bitmask of size uint64_t. -// As a result the maximum size of the map is 64 entries. -// If a non-primitive data type is required for the key by using a "class" or "struct", -// then the operator== has to be provided by that class/struct: -// bool operator ==(const K&) const { return true/false; } - -template -class Map + +namespace Knx { - public: - Map() - { - static_assert (SIZE <= 64, "Map is too big! Max. 64 elements."); - } - - void clear() - { - _validEntries = 0; - } - - bool empty() - { - return (_validEntries == 0); - } - - uint8_t size() - { - uint8_t size = 0; - - for (uint8_t i = 0; i < SIZE; i++) + // Provides a simple unordered map which is based on two arrays of different data types, namely K and V. + // One array is used for the keys, the other array is used for the values. + // Tracking of free/occupied slots in the arrays is realized by a bitmask of size uint64_t. + // As a result the maximum size of the map is 64 entries. + // If a non-primitive data type is required for the key by using a "class" or "struct", + // then the operator== has to be provided by that class/struct: + // bool operator ==(const K&) const { return true/false; } + + template + class Map + { + public: + Map() { - size += (((_validEntries >> i) & 0x01) == 0x01) ? 1 : 0; + static_assert (SIZE <= 64, "Map is too big! Max. 64 elements."); } - return size; - } + void clear() + { + _validEntries = 0; + } - bool insert(K key, V value) - { - uint8_t index = getNextFreeIndex(); + bool empty() + { + return (_validEntries == 0); + } - if (index != noFreeEntryFoundIndex) + uint8_t size() { - keys[index] = key; - values[index] = value; + uint8_t size = 0; - _validEntries |= 1 << index; - return true; + for (uint8_t i = 0; i < SIZE; i++) + { + size += (((_validEntries >> i) & 0x01) == 0x01) ? 1 : 0; + } + + return size; } - // No free space - return false; - } + bool insert(K key, V value) + { + uint8_t index = getNextFreeIndex(); + + if (index != noFreeEntryFoundIndex) + { + keys[index] = key; + values[index] = value; + + _validEntries |= 1 << index; + return true; + } - bool insertOrAssign(K key, V value) - { - // Try to find the key - for (uint8_t i = 0; i < SIZE; i++) + // No free space + return false; + } + + bool insertOrAssign(K key, V value) { - // Check if this array slot is occupied - if ((_validEntries >> i) & 0x01) + // Try to find the key + for (uint8_t i = 0; i < SIZE; i++) { - // Key found? - if (keys[i] == key) + // Check if this array slot is occupied + if ((_validEntries >> i) & 0x01) { - values[i] = value; - return true; + // Key found? + if (keys[i] == key) + { + values[i] = value; + return true; + } } } - } - // Key does not exist, add it if enough space - return insert(key, value); - } + // Key does not exist, add it if enough space + return insert(key, value); + } - bool erase(K key) - { - for (uint8_t i = 0; i < SIZE; i++) + bool erase(K key) { - if ((_validEntries >> i) & 0x01) + for (uint8_t i = 0; i < SIZE; i++) { - if (keys[i] == key) + if ((_validEntries >> i) & 0x01) { - _validEntries &= ~(1 << i); - return true; + if (keys[i] == key) + { + _validEntries &= ~(1 << i); + return true; + } } } - } - return false; - } + return false; + } - V* get(K key) - { - // Try to find the key - for (uint8_t i = 0; i < SIZE; i++) + V* get(K key) { - // Check if this array slot is occupied - if ((_validEntries >> i) & 0x01) + // Try to find the key + for (uint8_t i = 0; i < SIZE; i++) { - // Key found? - if (keys[i] == key) + // Check if this array slot is occupied + if ((_validEntries >> i) & 0x01) { - return &values[i]; + // Key found? + if (keys[i] == key) + { + return &values[i]; + } } } - } - return nullptr; - } + return nullptr; + } - private: - uint8_t getNextFreeIndex() - { - for (uint8_t i = 0; i < SIZE; i++) + private: + uint8_t getNextFreeIndex() { - if (((_validEntries >> i) & 0x01) == 0) + for (uint8_t i = 0; i < SIZE; i++) { - return i; + if (((_validEntries >> i) & 0x01) == 0) + { + return i; + } } - } - return noFreeEntryFoundIndex; - } + return noFreeEntryFoundIndex; + } - uint64_t _validEntries{0}; - K keys[SIZE]; - V values[SIZE]; - static constexpr uint8_t noFreeEntryFoundIndex = 255; -}; + uint64_t _validEntries{0}; + K keys[SIZE]; + V values[SIZE]; + static constexpr uint8_t noFreeEntryFoundIndex = 255; + }; +} \ No newline at end of file