From 1ba39e207f45aab1044225e2e626a3389523575a Mon Sep 17 00:00:00 2001 From: Thomas Kunze Date: Fri, 9 Aug 2024 22:20:19 +0200 Subject: [PATCH] astyle everything --- src/arduino_platform.cpp | 31 +- src/arduino_platform.h | 48 +- src/cc1310_platform.cpp | 165 ++-- src/cc1310_platform.h | 18 +- src/esp32_platform.cpp | 48 +- src/esp32_platform.h | 82 +- src/esp_platform.cpp | 36 +- src/esp_platform.h | 64 +- src/knx/address_table_object.cpp | 20 +- src/knx/address_table_object.h | 88 +- src/knx/aes.c | 669 ++++++++------- src/knx/aes.h | 48 +- src/knx/aes.hpp | 2 +- src/knx/apdu.cpp | 8 +- src/knx/apdu.h | 74 +- src/knx/application_layer.cpp | 350 +++++--- src/knx/application_layer.h | 393 ++++----- src/knx/application_program_object.cpp | 25 +- src/knx/application_program_object.h | 20 +- src/knx/association_table_object.cpp | 33 +- src/knx/association_table_object.h | 28 +- src/knx/bau.cpp | 186 ++--- src/knx/bau.h | 328 ++++---- src/knx/bau07B0.cpp | 35 +- src/knx/bau07B0.h | 32 +- src/knx/bau091A.cpp | 60 +- src/knx/bau091A.h | 42 +- src/knx/bau27B0.cpp | 48 +- src/knx/bau27B0.h | 48 +- src/knx/bau2920.cpp | 27 +- src/knx/bau2920.h | 44 +- src/knx/bau57B0.cpp | 26 +- src/knx/bau57B0.h | 32 +- src/knx/bau_systemB.cpp | 233 ++++-- src/knx/bau_systemB.h | 214 ++--- src/knx/bau_systemB_coupler.cpp | 6 +- src/knx/bau_systemB_coupler.h | 28 +- src/knx/bau_systemB_device.cpp | 45 +- src/knx/bau_systemB_device.h | 56 +- src/knx/bits.cpp | 59 +- src/knx/bits.h | 154 ++-- src/knx/callback_property.h | 57 +- src/knx/cemi_frame.cpp | 55 +- src/knx/cemi_frame.h | 124 +-- src/knx/cemi_server.cpp | 74 +- src/knx/cemi_server.h | 62 +- src/knx/cemi_server_object.cpp | 29 +- src/knx/cemi_server_object.h | 8 +- src/knx/config.h | 148 ++-- src/knx/data_link_layer.cpp | 96 ++- src/knx/data_link_layer.h | 76 +- src/knx/data_property.cpp | 10 +- src/knx/data_property.h | 34 +- src/knx/datapoint_types.cpp | 3 +- src/knx/device_object.cpp | 110 +-- src/knx/device_object.h | 74 +- src/knx/dpt.h | 18 +- src/knx/dptconvert.cpp | 323 ++++++- src/knx/function_property.h | 74 +- src/knx/group_object.cpp | 29 +- src/knx/group_object.h | 440 +++++----- src/knx/group_object_table_object.cpp | 13 +- src/knx/group_object_table_object.h | 34 +- src/knx/interface_object.cpp | 22 +- src/knx/interface_object.h | 282 +++---- src/knx/ip_data_link_layer.cpp | 546 +++++++----- src/knx/ip_data_link_layer.h | 66 +- .../ip_host_protocol_address_information.h | 24 +- src/knx/ip_parameter_object.cpp | 162 ++-- src/knx/ip_parameter_object.h | 10 +- src/knx/knx_ip_ch.h | 26 +- src/knx/knx_ip_config_dib.cpp | 16 +- src/knx/knx_ip_config_dib.h | 32 +- src/knx/knx_ip_config_request.h | 14 +- src/knx/knx_ip_connect_request.cpp | 2 +- src/knx/knx_ip_connect_request.h | 18 +- src/knx/knx_ip_connect_response.cpp | 2 +- src/knx/knx_ip_connect_response.h | 48 +- src/knx/knx_ip_crd.h | 22 +- src/knx/knx_ip_cri.h | 32 +- src/knx/knx_ip_description_request.h | 10 +- src/knx/knx_ip_description_response.cpp | 22 +- src/knx/knx_ip_description_response.h | 14 +- src/knx/knx_ip_device_information_dib.h | 36 +- src/knx/knx_ip_dib.h | 18 +- src/knx/knx_ip_disconnect_request.h | 16 +- src/knx/knx_ip_disconnect_response.cpp | 2 +- src/knx/knx_ip_disconnect_response.h | 6 +- .../knx_ip_extended_device_information_dib.h | 16 +- src/knx/knx_ip_frame.h | 34 +- src/knx/knx_ip_knx_addresses_dib.h | 14 +- src/knx/knx_ip_routing_indication.cpp | 4 +- src/knx/knx_ip_routing_indication.h | 12 +- src/knx/knx_ip_search_request.h | 10 +- src/knx/knx_ip_search_request_extended.cpp | 26 +- src/knx/knx_ip_search_request_extended.h | 26 +- src/knx/knx_ip_search_response.cpp | 22 +- src/knx/knx_ip_search_response.h | 18 +- src/knx/knx_ip_search_response_extended.cpp | 66 +- src/knx/knx_ip_search_response_extended.h | 30 +- src/knx/knx_ip_state_request.h | 12 +- src/knx/knx_ip_state_response.cpp | 20 +- src/knx/knx_ip_state_response.h | 6 +- src/knx/knx_ip_supported_service_dib.cpp | 1 + src/knx/knx_ip_supported_service_dib.h | 8 +- src/knx/knx_ip_tunnel_connection.h | 26 +- src/knx/knx_ip_tunneling_ack.cpp | 4 +- src/knx/knx_ip_tunneling_ack.h | 12 +- src/knx/knx_ip_tunneling_info_dib.cpp | 4 +- src/knx/knx_ip_tunneling_info_dib.h | 14 +- src/knx/knx_ip_tunneling_request.cpp | 4 +- src/knx/knx_ip_tunneling_request.h | 16 +- src/knx/knx_types.h | 18 +- src/knx/knx_value.cpp | 67 +- src/knx/knx_value.h | 170 ++-- src/knx/memory.cpp | 64 +- src/knx/memory.h | 96 +-- src/knx/network_layer.cpp | 5 +- src/knx/network_layer.h | 64 +- src/knx/network_layer_coupler.cpp | 151 ++-- src/knx/network_layer_coupler.h | 120 +-- src/knx/network_layer_device.cpp | 6 +- src/knx/network_layer_device.h | 60 +- src/knx/network_layer_entity.cpp | 4 +- src/knx/network_layer_entity.h | 64 +- src/knx/npdu.h | 28 +- src/knx/platform.cpp | 140 ++-- src/knx/platform.h | 248 +++--- src/knx/property.cpp | 28 +- src/knx/property.h | 62 +- src/knx/rf_data_link_layer.cpp | 99 ++- src/knx/rf_data_link_layer.h | 74 +- src/knx/rf_medium_object.cpp | 52 +- src/knx/rf_medium_object.h | 14 +- src/knx/rf_physical_layer.h | 18 +- src/knx/rf_physical_layer_cc1101.cpp | 476 ++++++----- src/knx/rf_physical_layer_cc1101.h | 118 +-- src/knx/rf_physical_layer_cc1310.cpp | 104 ++- src/knx/rf_physical_layer_cc1310.h | 16 +- src/knx/router_object.cpp | 86 +- src/knx/router_object.h | 48 +- src/knx/save_restore.h | 70 +- src/knx/secure_application_layer.cpp | 147 +++- src/knx/secure_application_layer.h | 221 ++--- src/knx/security_interface_object.cpp | 268 +++--- src/knx/security_interface_object.h | 72 +- src/knx/service_families.h | 8 +- src/knx/simple_map.h | 167 ++-- src/knx/table_object.cpp | 133 +-- src/knx/table_object.h | 140 ++-- src/knx/tp_frame.h | 522 ++++++------ src/knx/tpdu.cpp | 67 +- src/knx/tpdu.h | 36 +- src/knx/tpuart_data_link_layer.cpp | 67 +- src/knx/tpuart_data_link_layer.h | 274 +++--- src/knx/transport_layer.cpp | 711 ++++++++-------- src/knx/transport_layer.h | 200 ++--- src/knx/usb_tunnel_interface.cpp | 729 ++++++++-------- src/knx/usb_tunnel_interface.h | 134 +-- src/knx_facade.cpp | 171 ++-- src/knx_facade.h | 789 +++++++++--------- src/linux_platform.cpp | 99 ++- src/linux_platform.h | 126 +-- src/rp2040_arduino_platform.cpp | 40 +- src/rp2040_arduino_platform.h | 204 ++--- src/samd_platform.cpp | 64 +- src/samd_platform.h | 72 +- src/stm32_platform.cpp | 11 +- src/stm32_platform.h | 30 +- 169 files changed, 8619 insertions(+), 7150 deletions(-) diff --git a/src/arduino_platform.cpp b/src/arduino_platform.cpp index d23d4c24..25cc725a 100644 --- a/src/arduino_platform.cpp +++ b/src/arduino_platform.cpp @@ -3,11 +3,11 @@ #include #ifndef KNX_NO_SPI -#include + #include #endif #ifndef KNX_NO_PRINT -Stream* ArduinoPlatform::SerialDebug = &KNX_DEBUG_SERIAL; + Stream* ArduinoPlatform::SerialDebug = &KNX_DEBUG_SERIAL; #endif ArduinoPlatform::ArduinoPlatform() : _knxSerial(nullptr) @@ -29,6 +29,7 @@ void ArduinoPlatform::fatalError() digitalWrite(KNX_LED, HIGH); else digitalWrite(KNX_LED, LOW); + #endif } } @@ -37,6 +38,7 @@ void ArduinoPlatform::knxUart( HardwareSerial* serial ) { if (_knxSerial) closeUart(); + _knxSerial = serial; setupUart(); } @@ -49,7 +51,8 @@ HardwareSerial* ArduinoPlatform::knxUart() void ArduinoPlatform::setupUart() { _knxSerial->begin(19200, SERIAL_8E1); - while (!_knxSerial) + + while (!_knxSerial) ; } @@ -73,7 +76,7 @@ size_t ArduinoPlatform::writeUart(const uint8_t data) } -size_t ArduinoPlatform::writeUart(const uint8_t *buffer, size_t size) +size_t ArduinoPlatform::writeUart(const uint8_t* buffer, size_t size) { //printHex("write(buffer, size); @@ -89,16 +92,18 @@ int ArduinoPlatform::readUart() } -size_t ArduinoPlatform::readBytesUart(uint8_t *buffer, size_t length) +size_t ArduinoPlatform::readBytesUart(uint8_t* buffer, size_t length) { 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; } @@ -121,7 +126,7 @@ void ArduinoPlatform::closeSpi() SPI.end(); } -int ArduinoPlatform::readWriteSpi(uint8_t *data, size_t len) +int ArduinoPlatform::readWriteSpi(uint8_t* data, size_t len) { SPI.transfer(data, len); return 0; @@ -130,20 +135,22 @@ int ArduinoPlatform::readWriteSpi(uint8_t *data, size_t len) #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'; uint64_t n = value; - do { - char c = n % base; - n /= base; - *--str = c < 10 ? c + '0' : c + 'A' - 10; + do + { + char c = n % base; + n /= base; + + *--str = c < 10 ? c + '0' : c + 'A' - 10; } while (n > 0); - print(str); + print(str); } void print(const char* s) diff --git a/src/arduino_platform.h b/src/arduino_platform.h index 9118920f..3b441017 100644 --- a/src/arduino_platform.h +++ b/src/arduino_platform.h @@ -3,40 +3,40 @@ #include "Arduino.h" #ifndef KNX_DEBUG_SERIAL -#define KNX_DEBUG_SERIAL Serial + #define KNX_DEBUG_SERIAL Serial #endif class ArduinoPlatform : public Platform { - public: - ArduinoPlatform(); - ArduinoPlatform(HardwareSerial* knxSerial); + 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; }; diff --git a/src/cc1310_platform.cpp b/src/cc1310_platform.cpp index 2994b54e..32669271 100644 --- a/src/cc1310_platform.cpp +++ b/src/cc1310_platform.cpp @@ -41,9 +41,9 @@ static void setupClock() { ClockP_Params clkParams; ClockP_Params_init(&clkParams); - clkParams.period = 1000/ClockP_tickPeriod; + clkParams.period = 1000 / ClockP_tickPeriod; clkParams.startFlag = true; - ClockP_construct(&clk0Struct, (ClockP_Fxn)clk0Fxn, 1000/ClockP_tickPeriod, &clkParams); + ClockP_construct(&clk0Struct, (ClockP_Fxn)clk0Fxn, 1000 / ClockP_tickPeriod, &clkParams); clk0Handle = ClockP_handle(&clk0Struct); } @@ -58,27 +58,29 @@ static void setupGPIO() 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) + 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) {} - } - } + } +} static void setupNVS() { NVS_Params nvsParams; NVS_Params_init(&nvsParams); nvsHandle = NVS_open(Board_NVSINTERNAL, &nvsParams); - if (nvsHandle == NULL) + + if (nvsHandle == NULL) { println("NVS_open() failed."); return; @@ -86,16 +88,20 @@ static void setupNVS() NVS_Attrs attrs; NVS_getAttrs(nvsHandle, &attrs); - print("NVS flash size: "); println((int)attrs.regionSize); - print("NVS flash sector size: "); println((int)attrs.sectorSize); + 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("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); + print("Error erasing NVS, result: "); + println(result); } else { @@ -140,54 +146,57 @@ size_t write(uint8_t c) #if defined(PRINT_UART) uint8_t buffer[1] = {c}; return UART_write(uart, buffer, sizeof(buffer)); -#elif defined (PRINT_RTT) +#elif defined (PRINT_RTT) 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 write(const uint8_t* buffer, size_t size) { size_t n = 0; - while (size--) + + while (size--) { - if (write(*buffer++)) + if (write(*buffer++)) { n++; } - else + else { break; } } + 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); -#elif defined (PRINT_RTT) +#elif defined (PRINT_RTT) return SEGGER_RTT_Write(0, buffer, size); #else - return size; + return size; #endif } #endif -size_t write(const char *buffer, size_t size) +size_t write(const char* buffer, size_t size) { - return write((const uint8_t *)buffer, size); + return write((const uint8_t*)buffer, size); } void print(const char* s) { - if (s == NULL) + if (s == NULL) { return; } + write(s, strlen(s)); } void print(char c) @@ -196,42 +205,45 @@ void print(char c) } 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; - do { - char c = n % base; - n /= base; - *--str = c < 10 ? c + '0' : c + 'A' - 10; + do + { + char c = n % base; + n /= base; + + *--str = c < 10 ? c + '0' : c + 'A' - 10; } while (n > 0); - print(str); + print(str); } void print(long long num, int base) { - if (base == 0) + if (base == 0) { write(num); return; } - else if (base == 10) + else if (base == 10) { - if (num < 0) + if (num < 0) { print('-'); num = -num; printUint64(num, 10); return; } + printUint64(num, 10); return; - } - else + } + else { printUint64(num, base); return; @@ -240,14 +252,14 @@ void print(long long num, int base) void print(unsigned long long num, int base) { - if (base == 0) + if (base == 0) { write(num); return; } - else + else { - printUint64(num, base); + printUint64(num, base); return; } } @@ -279,26 +291,29 @@ void print(unsigned long num, int base) void printFloat(double number, uint8_t digits) { - if (std::isnan(number)) + if (std::isnan(number)) { print("nan"); return; - } - if (std::isinf(number)) + } + + if (std::isinf(number)) { print("inf"); return; } - if (number > 4294967040.0) + + if (number > 4294967040.0) { print("ovf"); // constant determined empirically return; } - if (number <-4294967040.0) + + if (number < -4294967040.0) { print("ovf"); // constant determined empirically return; - } + } // Handle negative numbers if (number < 0.0) @@ -309,8 +324,9 @@ void printFloat(double number, uint8_t digits) // Round correctly so that print(1.999, 2) prints as "2.00" double rounding = 0.5; - for (uint8_t i=0; i 0) + if (digits > 0) { print('.'); } @@ -407,7 +423,8 @@ void println(double num) uint32_t digitalRead(uint32_t dwPin) { - print("ignoring digitalRead: pin: ");print(dwPin); + print("ignoring digitalRead: pin: "); + print(dwPin); println(", returning 0"); return 0; } @@ -427,15 +444,19 @@ void digitalWrite(unsigned long pin, unsigned long value) } else { - print("dummy digitalWrite: pin: ");print(pin); - print(", value: ");println(value, HEX); + print("dummy digitalWrite: pin: "); + print(pin); + print(", value: "); + println(value, HEX); } } void pinMode(unsigned long pin, unsigned long mode) { - print("ignoring pinMode: pin: ");print(pin); - print(", mode: ");println(mode, HEX); + print("ignoring pinMode: pin: "); + print(pin); + print(", mode: "); + println(mode, HEX); } typedef void (*IsrFuncPtr)(); @@ -445,7 +466,7 @@ static void gpioButtonFxn0(uint_least8_t index) gpioCallback(); } -void attachInterrupt(uint32_t pin, IsrFuncPtr callback, uint32_t mode) +void attachInterrupt(uint32_t pin, IsrFuncPtr callback, uint32_t mode) { if (pin == Board_GPIO_BUTTON0) { @@ -458,22 +479,24 @@ void attachInterrupt(uint32_t pin, IsrFuncPtr callback, uint32_t mode) } else { - print("dummy attachInterrupt: pin: ");print(pin); - print(", mode: ");println(mode, HEX); + print("dummy attachInterrupt: pin: "); + print(pin); + print(", mode: "); + println(mode, HEX); } } 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 + *(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() +void CC1310Platform::init() { // TI Drivers init // According to SDK docs it is safe to call them AFTER NoRTOS_Start() @@ -497,14 +520,14 @@ void CC1310Platform::init() uint8_t* CC1310Platform::getEepromBuffer(uint32_t size) { - if(size > KNX_FLASH_SIZE) + if (size > KNX_FLASH_SIZE) { fatalError(); } - NVS_read(nvsHandle, 0, (void *) NVS_buffer, size); + NVS_read(nvsHandle, 0, (void*) NVS_buffer, size); - for (int i=0; ibegin(19200, SERIAL_8E1, _rxPin, _txPin); - while (!_knxSerial) + + while (!_knxSerial) ; } @@ -56,7 +57,7 @@ uint32_t Esp32Platform::currentDefaultGateway() return WiFi.gatewayIP(); } -void Esp32Platform::macAddress(uint8_t * addr) +void Esp32Platform::macAddress(uint8_t* addr) { esp_wifi_get_mac(WIFI_IF_STA, addr); } @@ -78,9 +79,9 @@ void Esp32Platform::restart() 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()); + WiFi.localIP().toString().c_str()); uint8_t result = _udp.beginMulticast(mcastaddr, port); KNX_DEBUG_SERIAL.printf("result %d\n", result); } @@ -90,7 +91,7 @@ void Esp32Platform::closeMultiCast() _udp.stop(); } -bool Esp32Platform::sendBytesMultiCast(uint8_t * buffer, uint16_t len) +bool Esp32Platform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) { //printHex("<- ",buffer, len); _udp.beginMulticastPacket(); @@ -99,17 +100,20 @@ bool Esp32Platform::sendBytesMultiCast(uint8_t * buffer, uint16_t len) return true; } -int Esp32Platform::readBytesMultiCast(uint8_t * buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port) +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 > maxLen) { println("Unexpected UDP data packet length - drop packet"); + for (size_t i = 0; i < len; i++) _udp.read(); + return 0; } @@ -130,29 +134,35 @@ bool Esp32Platform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buff { IPAddress ucastaddr(htonl(addr)); - if(!addr) + if (!addr) ucastaddr = _remoteIP; - - if(!port) + + if (!port) port = _remotePort; - if(_udp.beginPacket(ucastaddr, port) == 1) + if (_udp.beginPacket(ucastaddr, port) == 1) { _udp.write(buffer, len); - if(_udp.endPacket() == 0) println("sendBytesUniCast endPacket fail"); + + if (_udp.endPacket() == 0) + println("sendBytesUniCast endPacket fail"); } else println("sendBytesUniCast beginPacket fail"); + return true; } -uint8_t * Esp32Platform::getEepromBuffer(uint32_t size) +uint8_t* Esp32Platform::getEepromBuffer(uint32_t size) { - uint8_t * eepromptr = EEPROM.getDataPtr(); - if(eepromptr == nullptr) { + uint8_t* eepromptr = EEPROM.getDataPtr(); + + if (eepromptr == nullptr) + { EEPROM.begin(size); eepromptr = EEPROM.getDataPtr(); } + return eepromptr; } diff --git a/src/esp32_platform.h b/src/esp32_platform.h index 4318fa41..4f8fb8f6 100644 --- a/src/esp32_platform.h +++ b/src/esp32_platform.h @@ -6,46 +6,48 @@ 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; + 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 diff --git a/src/esp_platform.cpp b/src/esp_platform.cpp index f155d527..504ccbd4 100644 --- a/src/esp_platform.cpp +++ b/src/esp_platform.cpp @@ -8,7 +8,7 @@ #include "knx/bits.h" #ifndef KNX_SERIAL -#define KNX_SERIAL Serial + #define KNX_SERIAL Serial #endif EspPlatform::EspPlatform() @@ -37,7 +37,7 @@ uint32_t EspPlatform::currentDefaultGateway() return WiFi.gatewayIP(); } -void EspPlatform::macAddress(uint8_t * addr) +void EspPlatform::macAddress(uint8_t* addr) { wifi_get_macaddr(STATION_IF, addr); } @@ -58,9 +58,9 @@ 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()); + WiFi.localIP().toString().c_str()); uint8 result = _udp.beginMulticast(WiFi.localIP(), mcastaddr, port); KNX_DEBUG_SERIAL.printf("result %d\n", result); } @@ -70,7 +70,7 @@ void EspPlatform::closeMultiCast() _udp.stop(); } -bool EspPlatform::sendBytesMultiCast(uint8_t * buffer, uint16_t len) +bool EspPlatform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) { //printHex("<- ",buffer, len); _udp.beginPacketMulticast(_multicastAddr, _multicastPort, WiFi.localIP()); @@ -79,12 +79,13 @@ bool EspPlatform::sendBytesMultiCast(uint8_t * buffer, uint16_t len) return true; } -int EspPlatform::readBytesMultiCast(uint8_t * buffer, uint16_t maxLen) +int EspPlatform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) { int len = _udp.parsePacket(); + if (len == 0) return 0; - + if (len > maxLen) { KNX_DEBUG_SERIAL.printf("udp buffer to small. was %d, needed %d\n", maxLen, len); @@ -100,21 +101,30 @@ bool EspPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer { IPAddress ucastaddr(htonl(addr)); println("sendBytesUniCast endPacket fail"); - if(_udp.beginPacket(ucastaddr, port) == 1) { + + if (_udp.beginPacket(ucastaddr, port) == 1) + { _udp.write(buffer, len); - if(_udp.endPacket() == 0) println("sendBytesUniCast endPacket fail"); + + if (_udp.endPacket() == 0) + println("sendBytesUniCast endPacket fail"); } - else println("sendBytesUniCast beginPacket fail"); + else + println("sendBytesUniCast beginPacket fail"); + return true; } -uint8_t * EspPlatform::getEepromBuffer(uint32_t size) +uint8_t* EspPlatform::getEepromBuffer(uint32_t size) { - uint8_t * eepromptr = EEPROM.getDataPtr(); - if(eepromptr == nullptr) { + uint8_t* eepromptr = EEPROM.getDataPtr(); + + if (eepromptr == nullptr) + { EEPROM.begin(size); eepromptr = EEPROM.getDataPtr(); } + return eepromptr; } diff --git a/src/esp_platform.h b/src/esp_platform.h index ce55d13e..1d4361ce 100644 --- a/src/esp_platform.h +++ b/src/esp_platform.h @@ -6,38 +6,38 @@ 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; + 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 diff --git a/src/knx/address_table_object.cpp b/src/knx/address_table_object.cpp index 7b18af46..23ab5922 100644 --- a/src/knx/address_table_object.cpp +++ b/src/knx/address_table_object.cpp @@ -37,28 +37,33 @@ uint16_t AddressTableObject::getGroupAddress(uint16_t tsap) uint16_t AddressTableObject::getTsap(uint16_t addr) { uint16_t size = entryCount(); - #ifdef USE_BINSEARCH +#ifdef USE_BINSEARCH - uint16_t low,high,i; + uint16_t low, high, i; low = 1; high = size; - while(low <= high) + while (low <= high) { - i = (low+high)/2; + i = (low + high) / 2; uint16_t ga = ntohs(_groupAddresses[i]); + if (ga == addr) return i; - if(addr < ga) + + if (addr < ga) high = i - 1; else low = i + 1 ; } - #else + +#else + for (uint16_t i = 1; i <= size; i++) if (ntohs(_groupAddresses[i]) == addr) return i; - #endif + +#endif return 0; } @@ -83,6 +88,7 @@ bool AddressTableObject::contains(uint16_t addr) void AddressTableObject::beforeStateChange(LoadState& newState) { TableObject::beforeStateChange(newState); + if (newState != LS_LOADED) return; diff --git a/src/knx/address_table_object.h b/src/knx/address_table_object.h index 13b1ebb8..0fd28908 100644 --- a/src/knx/address_table_object.h +++ b/src/knx/address_table_object.h @@ -2,56 +2,56 @@ #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 + * 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). + * 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; + 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; }; diff --git a/src/knx/aes.c b/src/knx/aes.c index eaf2b69e..07d4ba9f 100644 --- a/src/knx/aes.c +++ b/src/knx/aes.c @@ -19,10 +19,10 @@ ECB-AES128 2b7e151628aed2a6abf7158809cf4f3c resulting cipher - 3ad77bb40d7a3660a89ecaf32466ef97 - f5d3d58503b9699de785895a96fdbaaf - 43b1cd7f598ece23881b00e3ed030688 - 7b0c785e27e8ad3f8223207104725dd4 + 3ad77bb40d7a3660a89ecaf32466ef97 + f5d3d58503b9699de785895a96fdbaaf + 43b1cd7f598ece23881b00e3ed030688 + 7b0c785e27e8ad3f8223207104725dd4 NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0) @@ -55,11 +55,11 @@ NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0) #define Nr 10 // The number of rounds in AES Cipher. #endif -// jcallan@github points out that declaring Multiply as a function +// jcallan@github points out that declaring Multiply as a function // reduces code size considerably with the Keil ARM compiler. // See this link for more information: https://github.com/kokke/tiny-AES-C/pull/3 #ifndef MULTIPLY_AS_A_FUNCTION - #define MULTIPLY_AS_A_FUNCTION 0 + #define MULTIPLY_AS_A_FUNCTION 0 #endif @@ -74,57 +74,63 @@ typedef uint8_t state_t[4][4]; // The lookup-tables are marked const so they can be placed in read-only storage instead of RAM -// The numbers below can be computed dynamically trading ROM for RAM - +// The numbers below can be computed dynamically trading ROM for RAM - // This can be useful in (embedded) bootloader applications, where ROM is often limited. -static const uint8_t sbox[256] = { - //0 1 2 3 4 5 6 7 8 9 A B C D E F - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, - 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, - 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, - 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, - 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, - 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, - 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, - 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, - 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; - -static const uint8_t rsbox[256] = { - 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, - 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, - 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, - 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, - 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, - 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, - 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, - 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, - 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, - 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, - 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, - 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, - 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, - 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, - 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; - -// The round constant word array, Rcon[i], contains the values given by +static const uint8_t sbox[256] = +{ + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +static const uint8_t rsbox[256] = +{ + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +}; + +// The round constant word array, Rcon[i], contains the values given by // x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8) -static const uint8_t Rcon[11] = { - 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; +static const uint8_t Rcon[11] = +{ + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 +}; /* * Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12), * that you can remove most of the elements in the Rcon array, because they are unused. * * From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon - * - * "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed), + * + * "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed), * up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm." */ @@ -147,93 +153,97 @@ static uint8_t getSBoxInvert(uint8_t num) */ #define getSBoxInvert(num) (rsbox[(num)]) -// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. +// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) { - unsigned i, j, k; - uint8_t tempa[4]; // Used for the column/row operations - - // The first round key is the key itself. - for (i = 0; i < Nk; ++i) - { - RoundKey[(i * 4) + 0] = Key[(i * 4) + 0]; - RoundKey[(i * 4) + 1] = Key[(i * 4) + 1]; - RoundKey[(i * 4) + 2] = Key[(i * 4) + 2]; - RoundKey[(i * 4) + 3] = Key[(i * 4) + 3]; - } - - // All other round keys are found from the previous round keys. - for (i = Nk; i < Nb * (Nr + 1); ++i) - { - { - k = (i - 1) * 4; - tempa[0]=RoundKey[k + 0]; - tempa[1]=RoundKey[k + 1]; - tempa[2]=RoundKey[k + 2]; - tempa[3]=RoundKey[k + 3]; + unsigned i, j, k; + uint8_t tempa[4]; // Used for the column/row operations + // The first round key is the key itself. + for (i = 0; i < Nk; ++i) + { + RoundKey[(i * 4) + 0] = Key[(i * 4) + 0]; + RoundKey[(i * 4) + 1] = Key[(i * 4) + 1]; + RoundKey[(i * 4) + 2] = Key[(i * 4) + 2]; + RoundKey[(i * 4) + 3] = Key[(i * 4) + 3]; } - if (i % Nk == 0) + // All other round keys are found from the previous round keys. + for (i = Nk; i < Nb * (Nr + 1); ++i) { - // This function shifts the 4 bytes in a word to the left once. - // [a0,a1,a2,a3] becomes [a1,a2,a3,a0] - - // Function RotWord() - { - const uint8_t u8tmp = tempa[0]; - tempa[0] = tempa[1]; - tempa[1] = tempa[2]; - tempa[2] = tempa[3]; - tempa[3] = u8tmp; - } - - // SubWord() is a function that takes a four-byte input word and - // applies the S-box to each of the four bytes to produce an output word. - - // Function Subword() - { - tempa[0] = getSBoxValue(tempa[0]); - tempa[1] = getSBoxValue(tempa[1]); - tempa[2] = getSBoxValue(tempa[2]); - tempa[3] = getSBoxValue(tempa[3]); - } - - tempa[0] = tempa[0] ^ Rcon[i/Nk]; - } + { + k = (i - 1) * 4; + tempa[0] = RoundKey[k + 0]; + tempa[1] = RoundKey[k + 1]; + tempa[2] = RoundKey[k + 2]; + tempa[3] = RoundKey[k + 3]; + + } + + if (i % Nk == 0) + { + // This function shifts the 4 bytes in a word to the left once. + // [a0,a1,a2,a3] becomes [a1,a2,a3,a0] + + // Function RotWord() + { + const uint8_t u8tmp = tempa[0]; + tempa[0] = tempa[1]; + tempa[1] = tempa[2]; + tempa[2] = tempa[3]; + tempa[3] = u8tmp; + } + + // SubWord() is a function that takes a four-byte input word and + // applies the S-box to each of the four bytes to produce an output word. + + // Function Subword() + { + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + + tempa[0] = tempa[0] ^ Rcon[i / Nk]; + } + #if defined(AES256) && (AES256 == 1) - if (i % Nk == 4) - { - // Function Subword() - { - tempa[0] = getSBoxValue(tempa[0]); - tempa[1] = getSBoxValue(tempa[1]); - tempa[2] = getSBoxValue(tempa[2]); - tempa[3] = getSBoxValue(tempa[3]); - } - } + + if (i % Nk == 4) + { + // Function Subword() + { + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + } + #endif - j = i * 4; k=(i - Nk) * 4; - RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0]; - RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1]; - RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2]; - RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3]; - } + j = i * 4; + k = (i - Nk) * 4; + RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0]; + RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1]; + RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2]; + RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3]; + } } void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key) { - KeyExpansion(ctx->RoundKey, key); + KeyExpansion(ctx->RoundKey, key); } #if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv) { - KeyExpansion(ctx->RoundKey, key); - memcpy (ctx->Iv, iv, AES_BLOCKLEN); + KeyExpansion(ctx->RoundKey, key); + memcpy (ctx->Iv, iv, AES_BLOCKLEN); } void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv) { - memcpy (ctx->Iv, iv, AES_BLOCKLEN); + memcpy (ctx->Iv, iv, AES_BLOCKLEN); } #endif @@ -241,28 +251,30 @@ void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv) // The round key is added to the state by an XOR function. static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey) { - uint8_t i,j; - for (i = 0; i < 4; ++i) - { - for (j = 0; j < 4; ++j) + uint8_t i, j; + + for (i = 0; i < 4; ++i) { - (*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j]; + for (j = 0; j < 4; ++j) + { + (*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j]; + } } - } } // The SubBytes Function Substitutes the values in the // state matrix with values in an S-box. static void SubBytes(state_t* state) { - uint8_t i, j; - for (i = 0; i < 4; ++i) - { - for (j = 0; j < 4; ++j) + uint8_t i, j; + + for (i = 0; i < 4; ++i) { - (*state)[j][i] = getSBoxValue((*state)[j][i]); + for (j = 0; j < 4; ++j) + { + (*state)[j][i] = getSBoxValue((*state)[j][i]); + } } - } } // The ShiftRows() function shifts the rows in the state to the left. @@ -270,51 +282,60 @@ static void SubBytes(state_t* state) // Offset = Row number. So the first row is not shifted. static void ShiftRows(state_t* state) { - uint8_t temp; - - // Rotate first row 1 columns to left - temp = (*state)[0][1]; - (*state)[0][1] = (*state)[1][1]; - (*state)[1][1] = (*state)[2][1]; - (*state)[2][1] = (*state)[3][1]; - (*state)[3][1] = temp; - - // Rotate second row 2 columns to left - temp = (*state)[0][2]; - (*state)[0][2] = (*state)[2][2]; - (*state)[2][2] = temp; - - temp = (*state)[1][2]; - (*state)[1][2] = (*state)[3][2]; - (*state)[3][2] = temp; - - // Rotate third row 3 columns to left - temp = (*state)[0][3]; - (*state)[0][3] = (*state)[3][3]; - (*state)[3][3] = (*state)[2][3]; - (*state)[2][3] = (*state)[1][3]; - (*state)[1][3] = temp; + uint8_t temp; + + // Rotate first row 1 columns to left + temp = (*state)[0][1]; + (*state)[0][1] = (*state)[1][1]; + (*state)[1][1] = (*state)[2][1]; + (*state)[2][1] = (*state)[3][1]; + (*state)[3][1] = temp; + + // Rotate second row 2 columns to left + temp = (*state)[0][2]; + (*state)[0][2] = (*state)[2][2]; + (*state)[2][2] = temp; + + temp = (*state)[1][2]; + (*state)[1][2] = (*state)[3][2]; + (*state)[3][2] = temp; + + // Rotate third row 3 columns to left + temp = (*state)[0][3]; + (*state)[0][3] = (*state)[3][3]; + (*state)[3][3] = (*state)[2][3]; + (*state)[2][3] = (*state)[1][3]; + (*state)[1][3] = temp; } static uint8_t xtime(uint8_t x) { - return ((x<<1) ^ (((x>>7) & 1) * 0x1b)); + return ((x << 1) ^ (((x >> 7) & 1) * 0x1b)); } // MixColumns function mixes the columns of the state matrix static void MixColumns(state_t* state) { - uint8_t i; - uint8_t Tmp, Tm, t; - for (i = 0; i < 4; ++i) - { - t = (*state)[i][0]; - Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ; - Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ; - Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ; - Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ; - Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ; - } + uint8_t i; + uint8_t Tmp, Tm, t; + + for (i = 0; i < 4; ++i) + { + t = (*state)[i][0]; + Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ; + Tm = (*state)[i][0] ^ (*state)[i][1] ; + Tm = xtime(Tm); + (*state)[i][0] ^= Tm ^ Tmp ; + Tm = (*state)[i][1] ^ (*state)[i][2] ; + Tm = xtime(Tm); + (*state)[i][1] ^= Tm ^ Tmp ; + Tm = (*state)[i][2] ^ (*state)[i][3] ; + Tm = xtime(Tm); + (*state)[i][2] ^= Tm ^ Tmp ; + Tm = (*state)[i][3] ^ t ; + Tm = xtime(Tm); + (*state)[i][3] ^= Tm ^ Tmp ; + } } // Multiply is used to multiply numbers in the field GF(2^8) @@ -324,19 +345,19 @@ static void MixColumns(state_t* state) #if MULTIPLY_AS_A_FUNCTION static uint8_t Multiply(uint8_t x, uint8_t y) { - return (((y & 1) * x) ^ - ((y>>1 & 1) * xtime(x)) ^ - ((y>>2 & 1) * xtime(xtime(x))) ^ - ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ - ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */ - } + return (((y & 1) * x) ^ + ((y >> 1 & 1) * xtime(x)) ^ + ((y >> 2 & 1) * xtime(xtime(x))) ^ + ((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^ + ((y >> 4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */ +} #else #define Multiply(x, y) \ - ( ((y & 1) * x) ^ \ - ((y>>1 & 1) * xtime(x)) ^ \ - ((y>>2 & 1) * xtime(xtime(x))) ^ \ - ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \ - ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \ + ( ((y & 1) * x) ^ \ + ((y>>1 & 1) * xtime(x)) ^ \ + ((y>>2 & 1) * xtime(xtime(x))) ^ \ + ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \ + ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \ #endif @@ -346,20 +367,21 @@ static uint8_t Multiply(uint8_t x, uint8_t y) // Please use the references to gain more information. static void InvMixColumns(state_t* state) { - int i; - uint8_t a, b, c, d; - for (i = 0; i < 4; ++i) - { - a = (*state)[i][0]; - b = (*state)[i][1]; - c = (*state)[i][2]; - d = (*state)[i][3]; - - (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09); - (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d); - (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b); - (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e); - } + int i; + uint8_t a, b, c, d; + + for (i = 0; i < 4; ++i) + { + a = (*state)[i][0]; + b = (*state)[i][1]; + c = (*state)[i][2]; + d = (*state)[i][3]; + + (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09); + (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d); + (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b); + (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e); + } } @@ -367,93 +389,101 @@ static void InvMixColumns(state_t* state) // state matrix with values in an S-box. static void InvSubBytes(state_t* state) { - uint8_t i, j; - for (i = 0; i < 4; ++i) - { - for (j = 0; j < 4; ++j) + uint8_t i, j; + + for (i = 0; i < 4; ++i) { - (*state)[j][i] = getSBoxInvert((*state)[j][i]); + for (j = 0; j < 4; ++j) + { + (*state)[j][i] = getSBoxInvert((*state)[j][i]); + } } - } } static void InvShiftRows(state_t* state) { - uint8_t temp; - - // Rotate first row 1 columns to right - temp = (*state)[3][1]; - (*state)[3][1] = (*state)[2][1]; - (*state)[2][1] = (*state)[1][1]; - (*state)[1][1] = (*state)[0][1]; - (*state)[0][1] = temp; - - // Rotate second row 2 columns to right - temp = (*state)[0][2]; - (*state)[0][2] = (*state)[2][2]; - (*state)[2][2] = temp; - - temp = (*state)[1][2]; - (*state)[1][2] = (*state)[3][2]; - (*state)[3][2] = temp; - - // Rotate third row 3 columns to right - temp = (*state)[0][3]; - (*state)[0][3] = (*state)[1][3]; - (*state)[1][3] = (*state)[2][3]; - (*state)[2][3] = (*state)[3][3]; - (*state)[3][3] = temp; + uint8_t temp; + + // Rotate first row 1 columns to right + temp = (*state)[3][1]; + (*state)[3][1] = (*state)[2][1]; + (*state)[2][1] = (*state)[1][1]; + (*state)[1][1] = (*state)[0][1]; + (*state)[0][1] = temp; + + // Rotate second row 2 columns to right + temp = (*state)[0][2]; + (*state)[0][2] = (*state)[2][2]; + (*state)[2][2] = temp; + + temp = (*state)[1][2]; + (*state)[1][2] = (*state)[3][2]; + (*state)[3][2] = temp; + + // Rotate third row 3 columns to right + temp = (*state)[0][3]; + (*state)[0][3] = (*state)[1][3]; + (*state)[1][3] = (*state)[2][3]; + (*state)[2][3] = (*state)[3][3]; + (*state)[3][3] = temp; } #endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) // Cipher is the main function that encrypts the PlainText. static void Cipher(state_t* state, const uint8_t* RoundKey) { - uint8_t round = 0; - - // Add the First round key to the state before starting the rounds. - AddRoundKey(0, state, RoundKey); - - // There will be Nr rounds. - // The first Nr-1 rounds are identical. - // These Nr rounds are executed in the loop below. - // Last one without MixColumns() - for (round = 1; ; ++round) - { - SubBytes(state); - ShiftRows(state); - if (round == Nr) { - break; + uint8_t round = 0; + + // Add the First round key to the state before starting the rounds. + AddRoundKey(0, state, RoundKey); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr rounds are executed in the loop below. + // Last one without MixColumns() + for (round = 1; ; ++round) + { + SubBytes(state); + ShiftRows(state); + + if (round == Nr) + { + break; + } + + MixColumns(state); + AddRoundKey(round, state, RoundKey); } - MixColumns(state); - AddRoundKey(round, state, RoundKey); - } - // Add round key to last round - AddRoundKey(Nr, state, RoundKey); + + // Add round key to last round + AddRoundKey(Nr, state, RoundKey); } #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) static void InvCipher(state_t* state, const uint8_t* RoundKey) { - uint8_t round = 0; - - // Add the First round key to the state before starting the rounds. - AddRoundKey(Nr, state, RoundKey); - - // There will be Nr rounds. - // The first Nr-1 rounds are identical. - // These Nr rounds are executed in the loop below. - // Last one without InvMixColumn() - for (round = (Nr - 1); ; --round) - { - InvShiftRows(state); - InvSubBytes(state); - AddRoundKey(round, state, RoundKey); - if (round == 0) { - break; + uint8_t round = 0; + + // Add the First round key to the state before starting the rounds. + AddRoundKey(Nr, state, RoundKey); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr rounds are executed in the loop below. + // Last one without InvMixColumn() + for (round = (Nr - 1); ; --round) + { + InvShiftRows(state); + InvSubBytes(state); + AddRoundKey(round, state, RoundKey); + + if (round == 0) + { + break; + } + + InvMixColumns(state); } - InvMixColumns(state); - } } #endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) @@ -466,14 +496,14 @@ static void InvCipher(state_t* state, const uint8_t* RoundKey) void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf) { - // The next function call encrypts the PlainText with the Key using AES algorithm. - Cipher((state_t*)buf, ctx->RoundKey); + // The next function call encrypts the PlainText with the Key using AES algorithm. + Cipher((state_t*)buf, ctx->RoundKey); } void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf) { - // The next function call decrypts the PlainText with the Key using AES algorithm. - InvCipher((state_t*)buf, ctx->RoundKey); + // The next function call decrypts the PlainText with the Key using AES algorithm. + InvCipher((state_t*)buf, ctx->RoundKey); } @@ -488,40 +518,44 @@ void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf) static void XorWithIv(uint8_t* buf, const uint8_t* Iv) { - uint8_t i; - for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size - { - buf[i] ^= Iv[i]; - } + uint8_t i; + + for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size + { + buf[i] ^= Iv[i]; + } } -void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t* buf, uint32_t length) +void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length) { - uintptr_t i; - uint8_t *Iv = ctx->Iv; - for (i = 0; i < length; i += AES_BLOCKLEN) - { - XorWithIv(buf, Iv); - Cipher((state_t*)buf, ctx->RoundKey); - Iv = buf; - buf += AES_BLOCKLEN; - } - /* store Iv in ctx for next call */ - memcpy(ctx->Iv, Iv, AES_BLOCKLEN); + uintptr_t i; + uint8_t* Iv = ctx->Iv; + + for (i = 0; i < length; i += AES_BLOCKLEN) + { + XorWithIv(buf, Iv); + Cipher((state_t*)buf, ctx->RoundKey); + Iv = buf; + buf += AES_BLOCKLEN; + } + + /* store Iv in ctx for next call */ + memcpy(ctx->Iv, Iv, AES_BLOCKLEN); } void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length) { - uintptr_t i; - uint8_t storeNextIv[AES_BLOCKLEN]; - for (i = 0; i < length; i += AES_BLOCKLEN) - { - memcpy(storeNextIv, buf, AES_BLOCKLEN); - InvCipher((state_t*)buf, ctx->RoundKey); - XorWithIv(buf, ctx->Iv); - memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN); - buf += AES_BLOCKLEN; - } + uintptr_t i; + uint8_t storeNextIv[AES_BLOCKLEN]; + + for (i = 0; i < length; i += AES_BLOCKLEN) + { + memcpy(storeNextIv, buf, AES_BLOCKLEN); + InvCipher((state_t*)buf, ctx->RoundKey); + XorWithIv(buf, ctx->Iv); + memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN); + buf += AES_BLOCKLEN; + } } @@ -534,35 +568,38 @@ void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length) /* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */ void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length) { - uint8_t buffer[AES_BLOCKLEN]; - - unsigned i; - int bi; - for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi) - { - if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */ + uint8_t buffer[AES_BLOCKLEN]; + + unsigned i; + int bi; + + for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi) { - - memcpy(buffer, ctx->Iv, AES_BLOCKLEN); - Cipher((state_t*)buffer,ctx->RoundKey); - - /* Increment Iv and handle overflow */ - for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi) - { - /* inc will overflow */ - if (ctx->Iv[bi] == 255) - { - ctx->Iv[bi] = 0; - continue; - } - ctx->Iv[bi] += 1; - break; - } - bi = 0; + if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */ + { + + memcpy(buffer, ctx->Iv, AES_BLOCKLEN); + Cipher((state_t*)buffer, ctx->RoundKey); + + /* Increment Iv and handle overflow */ + for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi) + { + /* inc will overflow */ + if (ctx->Iv[bi] == 255) + { + ctx->Iv[bi] = 0; + continue; + } + + ctx->Iv[bi] += 1; + break; + } + + bi = 0; + } + + buf[i] = (buf[i] ^ buffer[bi]); } - - buf[i] = (buf[i] ^ buffer[bi]); - } } #endif // #if defined(CTR) && (CTR == 1) diff --git a/src/knx/aes.h b/src/knx/aes.h index 0d3b2e05..c2a2159e 100644 --- a/src/knx/aes.h +++ b/src/knx/aes.h @@ -11,15 +11,15 @@ // The #ifndef-guard allows it to be configured before #include'ing or at compile time. #ifndef CBC - #define CBC 1 + #define CBC 1 #endif #ifndef ECB - #define ECB 1 + #define ECB 1 #endif #ifndef CTR - #define CTR 1 + #define CTR 1 #endif @@ -42,47 +42,47 @@ struct AES_ctx { - uint8_t RoundKey[AES_keyExpSize]; + uint8_t RoundKey[AES_keyExpSize]; #if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) - uint8_t Iv[AES_BLOCKLEN]; + uint8_t Iv[AES_BLOCKLEN]; #endif }; void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key); #if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) -void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv); -void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv); + void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv); + void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv); #endif #if defined(ECB) && (ECB == 1) -// buffer size is exactly AES_BLOCKLEN bytes; -// you need only AES_init_ctx as IV is not used in ECB -// NB: ECB is considered insecure for most uses -void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf); -void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf); + // buffer size is exactly AES_BLOCKLEN bytes; + // you need only AES_init_ctx as IV is not used in ECB + // NB: ECB is considered insecure for most uses + void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf); + void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf); #endif // #if defined(ECB) && (ECB == !) #if defined(CBC) && (CBC == 1) -// buffer size MUST be mutile of AES_BLOCKLEN; -// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme -// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv() -// no IV should ever be reused with the same key -void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); -void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); + // buffer size MUST be mutile of AES_BLOCKLEN; + // Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme + // NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv() + // no IV should ever be reused with the same key + void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); + void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); #endif // #if defined(CBC) && (CBC == 1) #if defined(CTR) && (CTR == 1) -// Same function for encrypting as for decrypting. -// IV is incremented for every block, and used after encryption as XOR-compliment for output -// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme -// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv() -// no IV should ever be reused with the same key -void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); + // Same function for encrypting as for decrypting. + // IV is incremented for every block, and used after encryption as XOR-compliment for output + // Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme + // NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv() + // no IV should ever be reused with the same key + void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); #endif // #if defined(CTR) && (CTR == 1) diff --git a/src/knx/aes.hpp b/src/knx/aes.hpp index ade16425..4b234b72 100644 --- a/src/knx/aes.hpp +++ b/src/knx/aes.hpp @@ -2,7 +2,7 @@ #define _AES_HPP_ #ifndef __cplusplus -#error Do not include the hpp header in a c project! + #error Do not include the hpp header in a c project! #endif //__cplusplus extern "C" { diff --git a/src/knx/apdu.cpp b/src/knx/apdu.cpp index 98672153..966de35b 100644 --- a/src/knx/apdu.cpp +++ b/src/knx/apdu.cpp @@ -12,8 +12,10 @@ ApduType APDU::type() apci = getWord(_data); popWord(apci, _data); apci &= 0x3ff; + if ((apci >> 6) < 11 && (apci >> 6) != 7) //short apci apci &= 0x3c0; + return (ApduType)apci; } @@ -44,10 +46,14 @@ void APDU::printPDU() print(type(), HEX); print(" "); print(_data[0] & 0x3, HEX); + for (uint8_t i = 1; i < length() + 1; ++i) { - if (i) print(" "); + if (i) + print(" "); + print(_data[i], HEX); } + println(); } diff --git a/src/knx/apdu.h b/src/knx/apdu.h index 4b9fcf25..7eacd323 100644 --- a/src/knx/apdu.h +++ b/src/knx/apdu.h @@ -10,44 +10,44 @@ class CemiFrame; */ class APDU { - friend class CemiFrame; + friend class CemiFrame; - public: - /** - * Get the type of the APDU. - */ - ApduType type(); - /** - * 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 the contents of the APDU to console. - */ - void printPDU(); + public: + /** + * Get the type of the APDU. + */ + ApduType type(); + /** + * 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 the contents of the APDU to console. + */ + void printPDU(); - 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); + 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; + private: + uint8_t* _data = 0; + CemiFrame& _frame; }; \ No newline at end of file diff --git a/src/knx/application_layer.cpp b/src/knx/application_layer.cpp index 21346a6f..c7a39285 100644 --- a/src/knx/application_layer.cpp +++ b/src/knx/application_layer.cpp @@ -8,7 +8,7 @@ #include "bits.h" #include -const SecurityControl ApplicationLayer::noSecurity {.toolAccess=false, .dataSecurity=DataSecurity::None}; +const SecurityControl ApplicationLayer::noSecurity {.toolAccess = false, .dataSecurity = DataSecurity::None}; ApplicationLayer::ApplicationLayer(BusAccessUnit& bau) : _bau(bau) { @@ -40,6 +40,7 @@ void ApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priori 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 @@ -53,6 +54,7 @@ void ApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priori uint16_t startIdx = 0; int32_t asap = _assocTable->nextAsap(tsap, startIdx); + for (; asap != -1; asap = _assocTable->nextAsap(tsap, startIdx)) { switch (apdu.type()) @@ -60,11 +62,14 @@ void ApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priori 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; @@ -77,28 +82,34 @@ void ApplicationLayer::dataGroupConfirm(AckType ack, HopCountType hopType, Prior 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) +void ApplicationLayer::dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl, bool status) { switch (apdu.type()) { - case GroupValueRead: - if (_savedAsapReadRequest > 0) - _bau.groupValueReadLocalConfirm(ack, _savedAsapReadRequest, priority, hopType, secCtrl, status); - _savedAsapReadRequest = 0; - break; - case GroupValueResponse: - if (_savedAsapResponse > 0) - _bau.groupValueReadResponseConfirm(ack, _savedAsapResponse, priority, hopType, secCtrl, apdu.data(), apdu.length() - 1, status); - _savedAsapResponse = 0; - break; - case GroupValueWrite: - if (_savedAsapWriteRequest > 0) - _bau.groupValueWriteLocalConfirm(ack, _savedAsapWriteRequest, priority, hopType, secCtrl, apdu.data(), apdu.length() - 1, status); - _savedAsapWriteRequest = 0; - break; - default: - print("datagroup-confirm: unhandled APDU-Type: "); - println(apdu.type()); + case GroupValueRead: + if (_savedAsapReadRequest > 0) + _bau.groupValueReadLocalConfirm(ack, _savedAsapReadRequest, priority, hopType, secCtrl, status); + + _savedAsapReadRequest = 0; + break; + + case GroupValueResponse: + if (_savedAsapResponse > 0) + _bau.groupValueReadResponseConfirm(ack, _savedAsapResponse, priority, hopType, secCtrl, apdu.data(), apdu.length() - 1, status); + + _savedAsapResponse = 0; + break; + + case GroupValueWrite: + if (_savedAsapWriteRequest > 0) + _bau.groupValueWriteLocalConfirm(ack, _savedAsapWriteRequest, priority, hopType, secCtrl, apdu.data(), apdu.length() - 1, status); + + _savedAsapWriteRequest = 0; + break; + + default: + print("datagroup-confirm: unhandled APDU-Type: "); + println(apdu.type()); } } @@ -110,6 +121,7 @@ void ApplicationLayer::dataBroadcastIndication(HopCountType hopType, Priority pr void ApplicationLayer::dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl& secCtrl) { uint8_t* data = apdu.data(); + switch (apdu.type()) { case IndividualAddressWrite: @@ -119,26 +131,31 @@ void ApplicationLayer::dataBroadcastIndication(HopCountType hopType, Priority pr _bau.individualAddressWriteIndication(hopType, secCtrl, newAddress); break; } + case IndividualAddressRead: _bau.individualAddressReadIndication(hopType, secCtrl); break; + case IndividualAddressResponse: _bau.individualAddressReadAppLayerConfirm(hopType, secCtrl, apdu.frame().sourceAddress()); break; + case IndividualAddressSerialNumberRead: { uint8_t* knxSerialNumber = &data[1]; _bau.individualAddressSerialNumberReadIndication(priority, hopType, secCtrl, knxSerialNumber); break; } + case IndividualAddressSerialNumberResponse: { uint16_t domainAddress; popWord(domainAddress, data + 7); _bau.individualAddressSerialNumberReadAppLayerConfirm(hopType, secCtrl, data + 1, apdu.frame().sourceAddress(), - domainAddress); + domainAddress); break; } + case IndividualAddressSerialNumberWrite: { uint8_t* knxSerialNumber = &data[1]; @@ -147,6 +164,7 @@ void ApplicationLayer::dataBroadcastIndication(HopCountType hopType, Priority pr _bau.individualAddressSerialNumberWriteIndication(priority, hopType, secCtrl, newIndividualAddress, knxSerialNumber); break; } + default: print("Broadcast-indication: unhandled APDU-Type: "); println(apdu.type()); @@ -162,6 +180,7 @@ void ApplicationLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, P void ApplicationLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl, bool status) { uint8_t* data = apdu.data(); + switch (apdu.type()) { case IndividualAddressWrite: @@ -171,15 +190,19 @@ void ApplicationLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, P _bau.individualAddressWriteLocalConfirm(ack, hopType, secCtrl, newAddress, status); break; } + case IndividualAddressRead: _bau.individualAddressReadLocalConfirm(ack, hopType, secCtrl, status); break; + case IndividualAddressResponse: _bau.individualAddressReadResponseConfirm(ack, hopType, secCtrl, status); break; + case IndividualAddressSerialNumberRead: _bau.individualAddressSerialNumberReadLocalConfirm(ack, hopType, secCtrl, data + 1, status); break; + case IndividualAddressSerialNumberResponse: { uint16_t domainAddress; @@ -187,6 +210,7 @@ void ApplicationLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, P _bau.individualAddressSerialNumberReadResponseConfirm(ack, hopType, secCtrl, data + 1, domainAddress, status); break; } + case IndividualAddressSerialNumberWrite: { uint16_t newAddress; @@ -194,6 +218,7 @@ void ApplicationLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, P _bau.individualAddressSerialNumberWriteLocalConfirm(ack, hopType, secCtrl, data + 1, newAddress, status); break; } + default: print("Broadcast-confirm: unhandled APDU-Type: "); println(apdu.type()); @@ -206,9 +231,10 @@ void ApplicationLayer::dataSystemBroadcastIndication(HopCountType hopType, Prior dataSystemBroadcastIndication(hopType, priority, source, apdu, noSecurity); } -void ApplicationLayer::dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl &secCtrl) +void ApplicationLayer::dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl& secCtrl) { const uint8_t* data = apdu.data(); + switch (apdu.type()) { // TODO: testInfo could be of any length @@ -226,6 +252,7 @@ void ApplicationLayer::dataSystemBroadcastIndication(HopCountType hopType, Prior _bau.systemNetworkParameterReadIndication(priority, hopType, secCtrl, objectType, propertyId, testInfo, sizeof(testInfo)); break; } + case DomainAddressSerialNumberWrite: { const uint8_t* knxSerialNumber = &data[1]; @@ -233,12 +260,14 @@ void ApplicationLayer::dataSystemBroadcastIndication(HopCountType hopType, Prior _bau.domainAddressSerialNumberWriteIndication(priority, hopType, secCtrl, domainAddress, knxSerialNumber); break; } + case DomainAddressSerialNumberRead: { const uint8_t* knxSerialNumber = &data[1]; _bau.domainAddressSerialNumberReadIndication(priority, hopType, secCtrl, knxSerialNumber); break; } + default: print("SystemBroadcast-indication: unhandled APDU-Type: "); println(apdu.type()); @@ -246,13 +275,15 @@ void ApplicationLayer::dataSystemBroadcastIndication(HopCountType hopType, Prior } } -void ApplicationLayer::dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, bool status) { +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) { const uint8_t* data = apdu.data(); + switch (apdu.type()) { // TODO: testInfo could be of any length @@ -270,6 +301,7 @@ void ApplicationLayer::dataSystemBroadcastConfirm(HopCountType hopType, Priority _bau.systemNetworkParameterReadLocalConfirm(priority, hopType, secCtrl, objectType, propertyId, testInfo, sizeof(testInfo), status); break; } + case DomainAddressSerialNumberWrite: { const uint8_t* knxSerialNumber = &data[1]; @@ -277,12 +309,14 @@ void ApplicationLayer::dataSystemBroadcastConfirm(HopCountType hopType, Priority _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()); @@ -305,7 +339,7 @@ void ApplicationLayer::dataIndividualConfirm(AckType ack, HopCountType hopType, dataIndividualConfirm(ack, hopType, priority, tsap, apdu, noSecurity, status); } -void ApplicationLayer::dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl &secCtrl, bool status) +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); } @@ -365,11 +399,12 @@ void ApplicationLayer::groupValueReadRequest(AckType ack, uint16_t asap, Priorit CemiFrame frame(1); APDU& apdu = frame.apdu(); apdu.type(GroupValueRead); - + int32_t value = _assocTable->translateAsap(asap); + if (value < 0) return; // there is no tsap in association table for this asap - + uint16_t tsap = (uint16_t)value; // first to bus then to itself @@ -377,13 +412,13 @@ void ApplicationLayer::groupValueReadRequest(AckType ack, uint16_t asap, Priorit dataGroupIndication(hopType, priority, tsap, apdu, secCtrl); } -void ApplicationLayer::groupValueReadResponse(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t * data, uint8_t dataLength) +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); } -void ApplicationLayer::groupValueWriteRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t * data, uint8_t dataLength) +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); @@ -407,7 +442,7 @@ void ApplicationLayer::individualAddressReadRequest(AckType ack, HopCountType ho dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); } -void ApplicationLayer::individualAddressReadResponse(AckType ack, HopCountType hopType, const SecurityControl &secCtrl) +void ApplicationLayer::individualAddressReadResponse(AckType ack, HopCountType hopType, const SecurityControl& secCtrl) { CemiFrame frame(1); APDU& apdu = frame.apdu(); @@ -415,7 +450,7 @@ void ApplicationLayer::individualAddressReadResponse(AckType ack, HopCountType h dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); } -void ApplicationLayer::individualAddressSerialNumberReadRequest(AckType ack, HopCountType hopType, const SecurityControl &secCtrl, uint8_t * serialNumber) +void ApplicationLayer::individualAddressSerialNumberReadRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber) { CemiFrame frame(7); APDU& apdu = frame.apdu(); @@ -426,7 +461,7 @@ void ApplicationLayer::individualAddressSerialNumberReadRequest(AckType ack, Hop } void ApplicationLayer::individualAddressSerialNumberReadResponse(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, - uint8_t * serialNumber, uint16_t domainAddress) + uint8_t* serialNumber, uint16_t domainAddress) { CemiFrame frame(7); APDU& apdu = frame.apdu(); @@ -438,8 +473,8 @@ void ApplicationLayer::individualAddressSerialNumberReadResponse(AckType ack, Ho dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl); } -void ApplicationLayer::individualAddressSerialNumberWriteRequest(AckType ack, HopCountType hopType, const SecurityControl &secCtrl, uint8_t * serialNumber, - uint16_t newaddress) +void ApplicationLayer::individualAddressSerialNumberWriteRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, + uint16_t newaddress) { CemiFrame frame(13); APDU& apdu = frame.apdu(); @@ -452,43 +487,47 @@ void ApplicationLayer::individualAddressSerialNumberWriteRequest(AckType ack, Ho } void ApplicationLayer::deviceDescriptorReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t descriptorType) + 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); } void ApplicationLayer::deviceDescriptorReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t descriptorType, uint8_t* deviceDescriptor) + uint8_t descriptorType, uint8_t* deviceDescriptor) { uint8_t length = 0; + switch (descriptorType) { - case 0: - length = 3; - break; - case 2: - length = 14; - break; - default: - length = 1; - descriptorType = 0x3f; - break; + case 0: + length = 3; + break; + + case 2: + length = 14; + break; + + default: + length = 1; + descriptorType = 0x3f; + break; } + CemiFrame frame(length); APDU& apdu = frame.apdu(); apdu.type(DeviceDescriptorResponse); uint8_t* data = apdu.data(); *data |= (descriptorType & 0x3f); - + if (length > 1) memcpy(data + 1, deviceDescriptor, length - 1); - + individualSend(ack, hopType, priority, asap, apdu, secCtrl); } @@ -526,10 +565,10 @@ void ApplicationLayer::restartResponse(AckType ack, Priority priority, HopCountT } //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) +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(); @@ -548,10 +587,10 @@ void ApplicationLayer::systemNetworkParameterReadResponse(Priority priority, Hop //TODO: ApplicationLayer::domainAddressSerialNumberWriteRequest() //TODO: ApplicationLayer::domainAddressSerialNumberReadRequest() -void ApplicationLayer::domainAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const SecurityControl &secCtrl, const uint8_t* rfDoA, - const uint8_t* knxSerialNumber) +void ApplicationLayer::domainAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA, + const uint8_t* knxSerialNumber) { - CemiFrame frame(13); + CemiFrame frame(13); APDU& apdu = frame.apdu(); apdu.type(DomainAddressSerialNumberResponse); @@ -567,10 +606,10 @@ void ApplicationLayer::domainAddressSerialNumberReadResponse(Priority priority, //TODO: ApplicationLayer::IndividualAddressSerialNumberWriteRequest() //TODO: ApplicationLayer::IndividualAddressSerialNumberReadRequest() -void ApplicationLayer::IndividualAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const SecurityControl &secCtrl, const uint8_t* domainAddress, - const uint8_t* knxSerialNumber) +void ApplicationLayer::IndividualAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* domainAddress, + const uint8_t* knxSerialNumber) { - CemiFrame frame(11); + CemiFrame frame(11); APDU& apdu = frame.apdu(); apdu.type(IndividualAddressSerialNumberResponse); @@ -585,7 +624,7 @@ void ApplicationLayer::IndividualAddressSerialNumberReadResponse(Priority priori } 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) + uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) { CemiFrame frame(5); APDU& apdu = frame.apdu(); @@ -596,26 +635,26 @@ void ApplicationLayer::propertyValueReadRequest(AckType ack, Priority priority, 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) +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); + startIndex, data, length); } -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) +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); } -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) +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, @@ -623,14 +662,14 @@ void ApplicationLayer::propertyValueExtWriteConResponse(AckType ack, Priority pr } 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) + 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); + startIndex, data, length); } void ApplicationLayer::adcReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t channelNr, uint8_t readCount, int16_t value) + uint8_t channelNr, uint8_t readCount, int16_t value) { CemiFrame frame(4); APDU& apdu = frame.apdu(); @@ -649,7 +688,7 @@ void ApplicationLayer::adcReadResponse(AckType ack, Priority priority, HopCountT } 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) + uint8_t objectIndex, uint8_t propertyId, uint8_t* resultData, uint8_t resultLength) { CemiFrame frame(3 + resultLength); APDU& apdu = frame.apdu(); @@ -658,6 +697,7 @@ void ApplicationLayer::functionPropertyStateResponse(AckType ack, Priority prior data[0] = objectIndex; data[1] = propertyId; + if (resultLength > 0) memcpy(&data[2], resultData, resultLength); @@ -668,7 +708,7 @@ void ApplicationLayer::functionPropertyStateResponse(AckType ack, Priority prior } 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) + uint16_t objectType, uint8_t objectInstance, uint16_t propertyId, uint8_t* resultData, uint8_t resultLength) { CemiFrame frame(5 + resultLength + 1); APDU& apdu = frame.apdu(); @@ -678,8 +718,9 @@ void ApplicationLayer::functionPropertyExtStateResponse(AckType ack, Priority pr data[0] = ((uint16_t)objectType) >> 8; data[1] = ((uint16_t)objectType) & 0xFF; data[2] = objectInstance >> 4; - data[3] = ((objectInstance&0x0F) << 4) | (propertyId >> 8); + 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); @@ -690,8 +731,8 @@ void ApplicationLayer::functionPropertyExtStateResponse(AckType ack, Priority pr 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) +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(); @@ -704,8 +745,8 @@ void ApplicationLayer::propertyDescriptionReadRequest(AckType ack, Priority prio } 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) + 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(); @@ -714,8 +755,10 @@ void ApplicationLayer::propertyDescriptionReadResponse(AckType ack, Priority pri 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; @@ -723,8 +766,8 @@ void ApplicationLayer::propertyDescriptionReadResponse(AckType ack, Priority pri } 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) + 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(); @@ -747,6 +790,7 @@ void ApplicationLayer::propertyExtDescriptionReadResponse(AckType ack, Priority if (writeEnable) data[12] |= 0x80; + data[12] |= (type & 0x3f); pushWord(maxNumberOfElements & 0xfff, data + 13); @@ -755,7 +799,7 @@ void ApplicationLayer::propertyExtDescriptionReadResponse(AckType ack, Priority } void ApplicationLayer::memoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress) + uint16_t memoryAddress) { CemiFrame frame(3); APDU& apdu = frame.apdu(); @@ -767,25 +811,25 @@ void ApplicationLayer::memoryReadRequest(AckType ack, Priority priority, HopCoun } void ApplicationLayer::memoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t * memoryData) + 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) + 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) + 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) + uint8_t number, uint32_t memoryAddress, uint8_t* memoryData) { CemiFrame frame(5 + number); APDU& apdu = frame.apdu(); @@ -802,7 +846,7 @@ void ApplicationLayer::memoryExtReadResponse(AckType ack, Priority priority, Hop } 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) + uint8_t number, uint32_t memoryAddress, uint8_t* memoryData) { bool withCrc = code == ReturnCodes::SuccessWithCrc; @@ -826,13 +870,13 @@ void ApplicationLayer::memoryExtWriteResponse(AckType ack, Priority priority, Ho } void ApplicationLayer::memoryWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t number, uint16_t memoryAddress, uint8_t * data) + uint8_t number, uint16_t memoryAddress, uint8_t* data) { memorySend(MemoryWrite, ack, priority, hopType, asap, secCtrl, number, memoryAddress, data); } void ApplicationLayer::userMemoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t number, uint32_t memoryAddress) + uint8_t number, uint32_t memoryAddress) { CemiFrame frame(4); APDU& apdu = frame.apdu(); @@ -845,13 +889,13 @@ void ApplicationLayer::userMemoryReadRequest(AckType ack, Priority priority, Hop } void ApplicationLayer::userMemoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t number, uint32_t memoryAddress, uint8_t * memoryData) + 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) + uint8_t number, uint32_t memoryAddress, uint8_t* memoryData) { userMemorySend(UserMemoryWrite, ack, priority, hopType, asap, secCtrl, number, memoryAddress, memoryData); } @@ -865,7 +909,7 @@ void ApplicationLayer::userManufacturerInfoReadRequest(AckType ack, Priority pri } void ApplicationLayer::userManufacturerInfoReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, - uint8_t* info) + uint8_t* info) { CemiFrame frame(4); APDU& apdu = frame.apdu(); @@ -917,7 +961,7 @@ void ApplicationLayer::keyWriteResponse(AckType ack, Priority priority, HopCount } 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) + 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(); @@ -929,6 +973,7 @@ void ApplicationLayer::propertyDataSend(ApduType type, AckType ack, Priority pri pushWord(startIndex & 0xfff, apduData); *apduData |= ((numberOfElements & 0xf) << 4); apduData += 2; + if (length > 0) memcpy(apduData, data, length); @@ -939,7 +984,7 @@ void ApplicationLayer::propertyDataSend(ApduType type, AckType ack, Priority pri } 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) + 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(); @@ -950,14 +995,14 @@ void ApplicationLayer::propertyExtDataSend(ApduType type, AckType ack, Priority apduData[0] = ((uint16_t)objectType) >> 8; apduData[1] = ((uint16_t)objectType) & 0xFF; apduData[2] = objectInstance >> 4; - apduData[3] = ((objectInstance&0x0F) << 4) | (propertyId >> 8); + apduData[3] = ((objectInstance & 0x0F) << 4) | (propertyId >> 8); apduData[4] = (propertyId & 0xFF); apduData[5] = numberOfElements; - apduData[6] = (startIndex & 0x0FFF)>> 8; + apduData[6] = (startIndex & 0x0FFF) >> 8; apduData[7] = startIndex & 0xFF; if (length > 0) - memcpy(apduData+8, data, length); + memcpy(apduData + 8, data, length); if (asap == _connectedTsap) dataConnectedRequest(asap, priority, apdu, secCtrl); @@ -965,8 +1010,8 @@ void ApplicationLayer::propertyExtDataSend(ApduType type, AckType ack, Priority 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) +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; @@ -975,6 +1020,7 @@ void ApplicationLayer::groupValueSend(ApduType type, AckType ack, uint16_t asap, APDU& apdu = frame.apdu(); apdu.type(type); uint8_t* apdudata = apdu.data(); + if (dataLength == 0) { // data size is six bit or less. So store in first byte @@ -985,6 +1031,7 @@ void ApplicationLayer::groupValueSend(ApduType type, AckType ack, uint16_t asap, { memcpy(apdudata + 1, data, dataLength); } + // 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); @@ -992,7 +1039,7 @@ void ApplicationLayer::groupValueSend(ApduType type, AckType ack, uint16_t asap, } 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) + uint16_t memoryAddress, uint8_t* memoryData) { CemiFrame frame(3 + number); APDU& apdu = frame.apdu(); @@ -1000,6 +1047,7 @@ void ApplicationLayer::memorySend(ApduType type, AckType ack, Priority priority, uint8_t* data = apdu.data(); *data |= (number & 0x3f); pushWord(memoryAddress, data + 1); + if (number > 0) memcpy(data + 3, memoryData, number); @@ -1007,7 +1055,7 @@ void ApplicationLayer::memorySend(ApduType type, AckType ack, Priority priority, } 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) + uint16_t memoryAddress, uint8_t* memoryData) { CemiFrame frame(4 + number); APDU& apdu = frame.apdu(); @@ -1015,13 +1063,15 @@ void ApplicationLayer::memoryRouterSend(ApduType type, AckType ack, Priority pri uint8_t* data = apdu.data(); data[1] |= (number & 0xf); pushWord(memoryAddress & 0xffff, data + 2); + if (number > 0) memcpy(data + 4, memoryData, number); + individualSend(ack, hopType, priority, asap, apdu, secCtrl); } 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) + uint16_t memoryAddress, uint8_t* memoryData) { CemiFrame frame(4 + number); APDU& apdu = frame.apdu(); @@ -1029,13 +1079,15 @@ void ApplicationLayer::memoryRoutingTableSend(ApduType type, AckType ack, Priori uint8_t* data = apdu.data(); data[1] |= (number & 0xf); pushWord(memoryAddress & 0xffff, data + 2); + if (number > 0) memcpy(data + 4, memoryData, number); + individualSend(ack, hopType, priority, asap, apdu, secCtrl); } 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) + uint32_t memoryAddress, uint8_t* memoryData) { CemiFrame frame(4 + number); APDU& apdu = frame.apdu(); @@ -1044,27 +1096,33 @@ void ApplicationLayer::userMemorySend(ApduType type, AckType ack, Priority prior 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); } -void ApplicationLayer::individualIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU & apdu, const SecurityControl& secCtrl) +void ApplicationLayer::individualIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) { uint8_t* data = apdu.data(); + switch (apdu.type()) { case DeviceDescriptorRead: _bau.deviceDescriptorReadIndication(priority, hopType, tsap, secCtrl, *data & 0x3f); break; + case DeviceDescriptorResponse: _bau.deviceDescriptorReadAppLayerConfirm(priority, hopType, tsap, secCtrl, *data & 0x3f, data + 1); break; + case Restart: case RestartMasterReset: { // These reserved bits must be 0 uint8_t reservedBits = data[0] & 0x1e; + if (reservedBits != 0) return; @@ -1072,14 +1130,17 @@ void ApplicationLayer::individualIndication(HopCountType hopType, Priority prior 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; } + case PropertyValueRead: { uint16_t startIndex; @@ -1088,24 +1149,27 @@ void ApplicationLayer::individualIndication(HopCountType hopType, Priority prior _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); + startIndex, data + 5, apdu.length() - 5); 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); + startIndex, data + 5, apdu.length() - 5); break; } + case PropertyValueExtRead: { ObjectType objectType = (ObjectType)(((data[1] & 0xff) << 8) | (data[2] & 0xff)); @@ -1116,6 +1180,7 @@ void ApplicationLayer::individualIndication(HopCountType hopType, Priority prior _bau.propertyValueExtReadIndication(priority, hopType, tsap, secCtrl, objectType, objectInstance, propertyId, numberOfElements, startIndex); break; } + case PropertyValueExtWriteCon: case PropertyValueExtWriteUnCon: { @@ -1129,12 +1194,15 @@ void ApplicationLayer::individualIndication(HopCountType hopType, Priority prior 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 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)); @@ -1144,6 +1212,7 @@ void ApplicationLayer::individualIndication(HopCountType hopType, Priority prior _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)); @@ -1153,9 +1222,11 @@ void ApplicationLayer::individualIndication(HopCountType hopType, Priority prior _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 PropertyExtDescriptionRead: { ObjectType objectType = (ObjectType)(((data[1] & 0xff) << 8) | (data[2] & 0xff)); @@ -1167,48 +1238,60 @@ void ApplicationLayer::individualIndication(HopCountType hopType, Priority prior _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]); + (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 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; - // EC + // 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 RoutingTableOpen: println("Received OpenRoutingTable APDU, doing nothing"); 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 RoutingTableWrite: _bau.memoryRoutingTableWriteIndication(priority, hopType, tsap, secCtrl, data[1], getWord(data + 2), data + 4); break; + // end EC - case MemoryExtRead: { + 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; @@ -1219,6 +1302,7 @@ void ApplicationLayer::individualIndication(HopCountType hopType, Priority prior _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; @@ -1228,36 +1312,45 @@ void ApplicationLayer::individualIndication(HopCountType hopType, Priority prior _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 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 UserManufacturerInfoResponse: _bau.userManufacturerInfoAppLayerConfirm(priority, hopType, tsap, secCtrl, data + 1); 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 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 ADCRead: { //Since we don't have an adc for bus voltage, we just send zero as readCount @@ -1265,120 +1358,147 @@ void ApplicationLayer::individualIndication(HopCountType hopType, Priority prior this->adcReadResponse(AckRequested, priority, hopType, tsap, secCtrl, channelNr, 0, 0); break; } + default: print("Individual-indication: unhandled APDU-Type: "); apdu.printPDU(); } } -void ApplicationLayer::individualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU & apdu, const SecurityControl &secCtrl, bool status) +void ApplicationLayer::individualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl, bool status) { uint8_t* data = apdu.data(); + switch (apdu.type()) { case DeviceDescriptorRead: _bau.deviceDescriptorReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, *data & 0x3f, status); break; + case DeviceDescriptorResponse: _bau.deviceDescriptorReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, *data & 0x3f, data + 1, status); break; + case Restart: _bau.restartRequestLocalConfirm(ack, priority, hopType, tsap, secCtrl, 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); + startIndex, 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); + startIndex, data + 5, apdu.length() - 5, 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); + 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 PropertyExtDescriptionRead: _bau.propertyExtDescriptionReadLocalConfirm(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); + (data[4] & 0x80) > 0, data[4] & 0x3f, getWord(data + 5) & 0xfff, data[7], status); break; + case MemoryRead: _bau.memoryReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), status); break; + case MemoryResponse: _bau.memoryReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3, status); break; + case MemoryWrite: _bau.memoryWriteLocalConfirm(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 MemoryExtReadResponse: _bau.memoryExtReadResponseConfirm(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 MemoryExtWriteResponse: _bau.memoryExtWriteResponseConfirm(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 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 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 UserManufacturerInfoRead: _bau.userManufacturerInfoLocalConfirm(ack, priority, hopType, tsap, secCtrl, status); break; + case UserManufacturerInfoResponse: _bau.userManufacturerInfoResponseConfirm(ack, priority, hopType, tsap, secCtrl, data + 1, status); break; + case AuthorizeRequest: _bau.authorizeLocalConfirm(ack, priority, hopType, tsap, secCtrl, getInt(data + 2), status); break; + case AuthorizeResponse: _bau.authorizeResponseConfirm(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; + case KeyResponse: _bau.keyWriteResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[1], status); break; + default: print("Individual-confirm: unhandled APDU-Type: "); println(apdu.type()); @@ -1403,7 +1523,7 @@ void ApplicationLayer::dataGroupRequest(AckType ack, HopCountType hopType, Prior (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 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); @@ -1418,7 +1538,7 @@ void ApplicationLayer::dataIndividualRequest(AckType ack, HopCountType hopType, (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 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 diff --git a/src/knx/application_layer.h b/src/knx/application_layer.h index e7f80d1e..9f8f2c59 100644 --- a/src/knx/application_layer.h +++ b/src/knx/application_layer.h @@ -9,217 +9,220 @@ 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 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); + 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); + 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) + // 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 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); + #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 + 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 + 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 + // 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;} + uint16_t getConnectedTsasp() + { + return _connectedTsap; + } - // Protected: we need to access it in derived class SecureApplicationLayer - TransportLayer* _transportLayer = 0; + // Protected: we need to access it in derived class SecureApplicationLayer + TransportLayer* _transportLayer = 0; - static const SecurityControl noSecurity; + 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); + 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; + uint16_t _savedAsapReadRequest = 0; + uint16_t _savedAsapWriteRequest = 0; + uint16_t _savedAsapResponse = 0; + AssociationTableObject* _assocTable = nullptr; + BusAccessUnit& _bau; - int32_t _connectedTsap = -1; + int32_t _connectedTsap = -1; }; diff --git a/src/knx/application_program_object.cpp b/src/knx/application_program_object.cpp index d58061fc..c885f3d7 100644 --- a/src/knx/application_program_object.cpp +++ b/src/knx/application_program_object.cpp @@ -17,17 +17,17 @@ ApplicationProgramObject::ApplicationProgramObject(Memory& memory) 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; + [](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; + }) }; TableObject::initializeProperties(sizeof(properties), properties); @@ -56,7 +56,7 @@ uint16_t ApplicationProgramObject::saveSize() return TableObject::saveSize() + 5; // sizeof(programVersion) } -uint8_t * ApplicationProgramObject::data(uint32_t addr) +uint8_t* ApplicationProgramObject::data(uint32_t addr) { return TableObject::data() + addr; } @@ -83,12 +83,15 @@ double ApplicationProgramObject::getFloat(uint32_t addr, ParameterFloatEncodings 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; diff --git a/src/knx/application_program_object.h b/src/knx/application_program_object.h index c989a1c6..dc20bb30 100644 --- a/src/knx/application_program_object.h +++ b/src/knx/application_program_object.h @@ -5,14 +5,14 @@ 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); + 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); }; diff --git a/src/knx/association_table_object.cpp b/src/knx/association_table_object.cpp index ad1761c2..7eebca2d 100644 --- a/src/knx/association_table_object.cpp +++ b/src/knx/association_table_object.cpp @@ -40,8 +40,8 @@ uint16_t AssociationTableObject::getASAP(uint16_t idx) } // 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 +// binary search access. If not, sortedEntryCount stays 0, +// otherwise sortedEntryCount represents size of bin search array void AssociationTableObject::prepareBinarySearch() { sortedEntryCount = 0; @@ -50,24 +50,29 @@ void AssociationTableObject::prepareBinarySearch() 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) { + // the remaining ASAP have to be all repetitions, otherwise we set sortedEntryCount to 0, which forces linear search + if (_tableData != nullptr) + { for (uint16_t idx = 0; idx < entryCount(); idx++) { currentASAP = getASAP(idx); + if (sortedEntryCount) { // 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 @@ -87,11 +92,13 @@ void AssociationTableObject::prepareBinarySearch() } } } + // in case complete table is strictly increasing if (lookupIdx == 0 && sortedEntryCount == 0) sortedEntryCount = entryCount(); - } -#endif + } + +#endif } const uint8_t* AssociationTableObject::restore(const uint8_t* buffer) @@ -113,13 +120,15 @@ int32_t AssociationTableObject::translateAsap(uint16_t asap) uint16_t low = 0; uint16_t high = sortedEntryCount - 1; - while(low <= high) + while (low <= high) { uint16_t i = (low + high) / 2; uint16_t asap_i = getASAP(i); + if (asap_i == asap) return getTSAP(i); - if(asap_i > asap) + + if (asap_i > asap) high = i - 1; else low = i + 1 ; @@ -127,17 +136,19 @@ int32_t AssociationTableObject::translateAsap(uint16_t asap) } else { - // if ASAP numbers are not strictly increasing linear seach is used + // 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); } + return -1; } void AssociationTableObject::beforeStateChange(LoadState& newState) { TableObject::beforeStateChange(newState); + if (newState != LS_LOADED) return; @@ -148,14 +159,16 @@ void AssociationTableObject::beforeStateChange(LoadState& newState) int32_t AssociationTableObject::nextAsap(uint16_t tsap, uint16_t& startIdx) { uint16_t entries = entryCount(); + for (uint16_t i = startIdx; i < entries; i++) { - startIdx = i+1; + startIdx = i + 1; if (getTSAP(i) == tsap) { return getASAP(i); } } + return -1; } diff --git a/src/knx/association_table_object.h b/src/knx/association_table_object.h index 2e68a009..7465de67 100644 --- a/src/knx/association_table_object.h +++ b/src/knx/association_table_object.h @@ -4,22 +4,22 @@ class AssociationTableObject : public TableObject { - public: - AssociationTableObject(Memory& memory); + 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; }; diff --git a/src/knx/bau.cpp b/src/knx/bau.cpp index a4958ff6..e4810164 100644 --- a/src/knx/bau.cpp +++ b/src/knx/bau.cpp @@ -4,319 +4,319 @@ void BusAccessUnit::groupValueReadLocalConfirm(AckType ack, uint16_t asap, Prior { } -void BusAccessUnit::groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl &secCtrl) +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::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::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::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::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::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::individualAddressWriteIndication(HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress) { } -void BusAccessUnit::individualAddressReadLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl &secCtrl, bool status) +void BusAccessUnit::individualAddressReadLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, bool status) { } -void BusAccessUnit::individualAddressReadIndication(HopCountType hopType, const SecurityControl &secCtrl) +void BusAccessUnit::individualAddressReadIndication(HopCountType hopType, const SecurityControl& secCtrl) { } -void BusAccessUnit::individualAddressReadResponseConfirm(AckType ack, HopCountType hopType, const SecurityControl &secCtrl, bool status) +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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::keyWriteAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level) { } @@ -324,31 +324,31 @@ 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::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::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::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::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::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::domainAddressSerialNumberReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber, bool status) { } diff --git a/src/knx/bau.h b/src/knx/bau.h index 44a0833b..6269abed 100644 --- a/src/knx/bau.h +++ b/src/knx/bau.h @@ -4,181 +4,181 @@ #include "interface_object.h" 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); +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, + 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 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, + 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, + 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 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 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(); }; diff --git a/src/knx/bau07B0.cpp b/src/knx/bau07B0.cpp index 099987a5..129e1de3 100644 --- a/src/knx/bau07B0.cpp +++ b/src/knx/bau07B0.cpp @@ -10,10 +10,10 @@ using namespace std; Bau07B0::Bau07B0(Platform& platform) : BauSystemBDevice(platform), DataLinkLayerCallbacks(), - _dlLayer(_deviceObj, _netLayer.getInterface(), _platform, *this, (ITpUartCallBacks&) *this, (DataLinkLayerCallbacks*) this) + _dlLayer(_deviceObj, _netLayer.getInterface(), _platform, *this, (ITpUartCallBacks&) * this, (DataLinkLayerCallbacks*) this) #ifdef USE_CEMI_SERVER , _cemiServer(*this) -#endif +#endif { _netLayer.getInterface().dataLinkLayer(_dlLayer); #ifdef USE_CEMI_SERVER @@ -50,28 +50,38 @@ InterfaceObject* Bau07B0::getInterfaceObject(uint8_t idx) { case 0: return &_deviceObj; + case 1: return &_addrTable; + case 2: return &_assocTable; + case 3: return &_groupObjTable; + case 4: return &_appProgram; + case 5: // would be app_program 2 return nullptr; #if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER) + case 6: return &_secIfObj; + case 7: return &_cemiServerObject; #elif defined(USE_CEMI_SERVER) + case 6: return &_cemiServerObject; #elif defined(USE_DATASECURE) + case 6: return &_secIfObj; #endif + default: return nullptr; } @@ -79,7 +89,7 @@ InterfaceObject* Bau07B0::getInterfaceObject(uint8_t idx) InterfaceObject* Bau07B0::getInterfaceObject(ObjectType objectType, uint16_t objectInstance) { - // We do not use it right now. + // We do not use it right now. // Required for coupler mode as there are multiple router objects for example (void) objectInstance; @@ -87,22 +97,29 @@ InterfaceObject* Bau07B0::getInterfaceObject(ObjectType objectType, uint16_t obj { case OT_DEVICE: return &_deviceObj; + case OT_ADDR_TABLE: return &_addrTable; + case OT_ASSOC_TABLE: return &_assocTable; + case OT_GRP_OBJ_TABLE: return &_groupObjTable; + case OT_APPLICATION_PROG: return &_appProgram; #ifdef USE_DATASECURE + case OT_SECURITY: return &_secIfObj; #endif #ifdef USE_CEMI_SERVER + case OT_CEMI_SERVER: return &_cemiServerObject; -#endif +#endif + default: return nullptr; } @@ -122,9 +139,9 @@ void Bau07B0::loop() { _dlLayer.loop(); BauSystemBDevice::loop(); -#ifdef USE_CEMI_SERVER +#ifdef USE_CEMI_SERVER _cemiServer.loop(); -#endif +#endif } TPAckType Bau07B0::isAckRequired(uint16_t address, bool isGrpAddr) @@ -134,8 +151,9 @@ TPAckType Bau07B0::isAckRequired(uint16_t address, bool isGrpAddr) // ACK for broadcasts if (address == 0) return TPAckType::AckReqAck; + // is group address in group address table? ACK if yes. - if(_addrTable.contains(address)) + if (_addrTable.contains(address)) return TPAckType::AckReqAck; else return TPAckType::AckReqNone; @@ -153,7 +171,8 @@ TPAckType Bau07B0::isAckRequired(uint16_t address, bool isGrpAddr) return TPAckType::AckReqNone; } -TpUartDataLinkLayer* Bau07B0::getDataLinkLayer() { +TpUartDataLinkLayer* Bau07B0::getDataLinkLayer() +{ return (TpUartDataLinkLayer*)&_dlLayer; } #endif diff --git a/src/knx/bau07B0.h b/src/knx/bau07B0.h index 44c51ca8..7867d00f 100644 --- a/src/knx/bau07B0.h +++ b/src/knx/bau07B0.h @@ -10,25 +10,25 @@ class Bau07B0 : public BauSystemBDevice, public ITpUartCallBacks, public DataLinkLayerCallbacks { - public: - Bau07B0(Platform& platform); - void loop() override; - bool enabled() override; - void enabled(bool value) override; + 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; -#endif + CemiServer _cemiServer; + CemiServerObject _cemiServerObject; +#endif }; #endif diff --git a/src/knx/bau091A.cpp b/src/knx/bau091A.cpp index 20319d10..dc239440 100644 --- a/src/knx/bau091A.cpp +++ b/src/knx/bau091A.cpp @@ -18,9 +18,9 @@ Bau091A::Bau091A(Platform& platform) _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, *this, (DataLinkLayerCallbacks*) this), - _dlLayerSecondary(_deviceObj, _netLayer.getSecondaryInterface(), platform, *this, (ITpUartCallBacks&) *this, (DataLinkLayerCallbacks*) this) + _dlLayerSecondary(_deviceObj, _netLayer.getSecondaryInterface(), platform, *this, (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 @@ -77,24 +77,32 @@ InterfaceObject* Bau091A::getInterfaceObject(uint8_t idx) { case 0: return &_deviceObj; + case 1: return &_routerObj; + case 2: return &_appProgram; + case 3: return &_ipParameters; #if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER) + case 4: return &_secIfObj; + case 5: return &_cemiServerObject; #elif defined(USE_CEMI_SERVER) + case 4: return &_cemiServerObject; #elif defined(USE_DATASECURE) + case 4: return &_secIfObj; #endif + default: return nullptr; } @@ -102,7 +110,7 @@ InterfaceObject* Bau091A::getInterfaceObject(uint8_t idx) InterfaceObject* Bau091A::getInterfaceObject(ObjectType objectType, uint16_t objectInstance) { - // We do not use it right now. + // We do not use it right now. // Required for coupler mode as there are multiple router objects for example (void) objectInstance; @@ -110,20 +118,26 @@ InterfaceObject* Bau091A::getInterfaceObject(ObjectType objectType, uint16_t obj { case OT_DEVICE: return &_deviceObj; + case OT_ROUTER: return &_routerObj; + case OT_APPLICATION_PROG: return &_appProgram; + case OT_IP_PARAMETER: return &_ipParameters; #ifdef USE_DATASECURE + case OT_SECURITY: return &_secIfObj; #endif #ifdef USE_CEMI_SERVER + case OT_CEMI_SERVER: return &_cemiServerObject; #endif + default: return nullptr; } @@ -166,7 +180,8 @@ TPAckType Bau091A::isAckRequired(uint16_t address, bool isGrpAddr) 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) + + if (lcconfig) prop_lcconfig->read(lcconfig); if (isGrpAddr) @@ -175,35 +190,40 @@ TPAckType Bau091A::isAckRequired(uint16_t address, bool isGrpAddr) 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)) + if (_netLayer.isRoutedGroupAddress(address, 1)) ack = TPAckType::AckReqAck; else ack = TPAckType::AckReqNone; else // all are ACKED ack = TPAckType::AckReqAck; + #ifdef KNX_TUNNELING - if(_dlLayerPrimary.isSentToTunnel(address, isGrpAddr)) + + if (_dlLayerPrimary.isSentToTunnel(address, isGrpAddr)) ack = TPAckType::AckReqAck; + #endif } else { - if((lcconfig & LCCONFIG::PHYS_IACK) == LCCONFIG::PHYS_IACK_ALL) + if ((lcconfig & LCCONFIG::PHYS_IACK) == LCCONFIG::PHYS_IACK_ALL) ack = TPAckType::AckReqAck; - else if((lcconfig & LCCONFIG::PHYS_IACK) == LCCONFIG::PHYS_IACK_NACK) + 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 - if(_netLayer.isRoutedIndividualAddress(address, 1) || address == _deviceObj.individualAddress()) // Also ACK for our own individual address - ack = TPAckType::AckReqAck; - else - ack = TPAckType::AckReqNone; + ack = TPAckType::AckReqNone; #ifdef KNX_TUNNELING - if(_dlLayerPrimary.isSentToTunnel(address, isGrpAddr)) + + if (_dlLayerPrimary.isSentToTunnel(address, isGrpAddr)) ack = TPAckType::AckReqAck; + #endif } @@ -213,23 +233,25 @@ TPAckType Bau091A::isAckRequired(uint16_t address, bool isGrpAddr) 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; - + _configured = _routerObj.loadState() == LS_LOADED; #ifdef USE_DATASECURE _configured &= _secIfObj.loadState() == LS_LOADED; #endif - + return _configured; } -IpDataLinkLayer* Bau091A::getPrimaryDataLinkLayer() { +IpDataLinkLayer* Bau091A::getPrimaryDataLinkLayer() +{ return (IpDataLinkLayer*)&_dlLayerPrimary; } -TpUartDataLinkLayer* Bau091A::getSecondaryDataLinkLayer() { +TpUartDataLinkLayer* Bau091A::getSecondaryDataLinkLayer() +{ return (TpUartDataLinkLayer*)&_dlLayerSecondary; } #endif diff --git a/src/knx/bau091A.h b/src/knx/bau091A.h index 494d2dab..78f3b435 100644 --- a/src/knx/bau091A.h +++ b/src/knx/bau091A.h @@ -12,31 +12,31 @@ 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; + 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 }; #endif diff --git a/src/knx/bau27B0.cpp b/src/knx/bau27B0.cpp index 35732021..462d7733 100644 --- a/src/knx/bau27B0.cpp +++ b/src/knx/bau27B0.cpp @@ -13,7 +13,7 @@ Bau27B0::Bau27B0(Platform& platform) _dlLayer(_deviceObj, _rfMediumObj, _netLayer.getInterface(), _platform, *this) #ifdef USE_CEMI_SERVER , _cemiServer(*this) -#endif +#endif { _netLayer.getInterface().dataLinkLayer(_dlLayer); _memory.addSaveRestore(&_rfMediumObj); @@ -61,30 +61,41 @@ InterfaceObject* Bau27B0::getInterfaceObject(uint8_t idx) { case 0: return &_deviceObj; + case 1: return &_addrTable; + case 2: return &_assocTable; + case 3: return &_groupObjTable; + case 4: return &_appProgram; + case 5: // would be app_program 2 return nullptr; + case 6: return &_rfMediumObj; #if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER) + case 7: return &_secIfObj; + case 8: return &_cemiServerObject; #elif defined(USE_CEMI_SERVER) + case 7: return &_cemiServerObject; #elif defined(USE_DATASECURE) + case 7: return &_secIfObj; #endif + default: return nullptr; } @@ -92,7 +103,7 @@ InterfaceObject* Bau27B0::getInterfaceObject(uint8_t idx) InterfaceObject* Bau27B0::getInterfaceObject(ObjectType objectType, uint16_t objectInstance) { - // We do not use it right now. + // We do not use it right now. // Required for coupler mode as there are multiple router objects for example (void) objectInstance; @@ -100,24 +111,32 @@ InterfaceObject* Bau27B0::getInterfaceObject(ObjectType objectType, uint16_t obj { case OT_DEVICE: return &_deviceObj; + case OT_ADDR_TABLE: return &_addrTable; + case OT_ASSOC_TABLE: return &_assocTable; + case OT_GRP_OBJ_TABLE: return &_groupObjTable; + case OT_APPLICATION_PROG: return &_appProgram; + case OT_RF_MEDIUM: return &_rfMediumObj; #ifdef USE_DATASECURE + case OT_SECURITY: return &_secIfObj; #endif #ifdef USE_CEMI_SERVER + case OT_CEMI_SERVER: return &_cemiServerObject; -#endif +#endif + default: return nullptr; } @@ -145,13 +164,13 @@ void Bau27B0::loop() { _dlLayer.loop(); BauSystemBDevice::loop(); -#ifdef USE_CEMI_SERVER +#ifdef USE_CEMI_SERVER _cemiServer.loop(); -#endif +#endif } -void Bau27B0::domainAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl &secCtrl, const uint8_t* rfDoA, - const uint8_t* knxSerialNumber) +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 @@ -159,7 +178,7 @@ void Bau27B0::domainAddressSerialNumberWriteIndication(Priority priority, HopCou _rfMediumObj.rfDomainAddress(rfDoA); } -void Bau27B0::domainAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl &secCtrl, const uint8_t* 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 @@ -167,21 +186,22 @@ void Bau27B0::domainAddressSerialNumberReadIndication(Priority priority, HopCoun _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" +#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() { +RfDataLinkLayer* Bau27B0::getDataLinkLayer() +{ return (RfDataLinkLayer*)&_dlLayer; } #endif // #ifdef USE_RF diff --git a/src/knx/bau27B0.h b/src/knx/bau27B0.h index d0020402..3b5e4233 100644 --- a/src/knx/bau27B0.h +++ b/src/knx/bau27B0.h @@ -6,9 +6,9 @@ #include "bau_systemB_device.h" #include "rf_medium_object.h" #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 "rf_data_link_layer.h" #include "cemi_server.h" @@ -16,32 +16,32 @@ class Bau27B0 : public BauSystemBDevice { - public: - Bau27B0(Platform& platform); - void loop() override; - bool enabled() override; - void enabled(bool value) override; + 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; }; #endif diff --git a/src/knx/bau2920.cpp b/src/knx/bau2920.cpp index b0ed9b4c..13ea690e 100644 --- a/src/knx/bau2920.cpp +++ b/src/knx/bau2920.cpp @@ -14,10 +14,10 @@ Bau2920::Bau2920(Platform& platform) _rtObjPrimary(memory()), _rtObjSecondary(memory()), _rfMediumObject(), - _dlLayerPrimary(_deviceObj, _netLayer.getPrimaryInterface(), _platform, *this, (ITpUartCallBacks&) *this), + _dlLayerPrimary(_deviceObj, _netLayer.getPrimaryInterface(), _platform, *this, (ITpUartCallBacks&) * this), _dlLayerSecondary(_deviceObj, _rfMediumObject, _netLayer.getSecondaryInterface(), platform, *this) #ifdef USE_CEMI_SERVER - , + , _cemiServer(*this) #endif { @@ -72,26 +72,35 @@ InterfaceObject* Bau2920::getInterfaceObject(uint8_t idx) { case 0: return &_deviceObj; + case 1: return &_rtObjPrimary; + case 2: return &_rtObjSecondary; + case 3: return &_appProgram; + case 4: return &_rfMediumObject; #if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER) + case 5: return &_secIfObj; + case 6: return &_cemiServerObject; #elif defined(USE_CEMI_SERVER) + case 5: return &_cemiServerObject; #elif defined(USE_DATASECURE) + case 5: return &_secIfObj; #endif + default: return nullptr; } @@ -99,7 +108,7 @@ InterfaceObject* Bau2920::getInterfaceObject(uint8_t idx) InterfaceObject* Bau2920::getInterfaceObject(ObjectType objectType, uint16_t objectInstance) { - // We do not use it right now. + // We do not use it right now. // Required for coupler mode as there are multiple router objects for example (void) objectInstance; @@ -107,20 +116,26 @@ InterfaceObject* Bau2920::getInterfaceObject(ObjectType objectType, uint16_t obj { case OT_DEVICE: return &_deviceObj; + case OT_ROUTER: return objectInstance == 0 ? &_rtObjPrimary : &_rtObjSecondary; + case OT_APPLICATION_PROG: return &_appProgram; + case OT_RF_MEDIUM: return &_rfMediumObject; #ifdef USE_DATASECURE + case OT_SECURITY: return &_secIfObj; #endif #ifdef USE_CEMI_SERVER + case OT_CEMI_SERVER: return &_cemiServerObject; #endif + default: return nullptr; } @@ -154,11 +169,13 @@ void Bau2920::loop() BauSystemBCoupler::loop(); } -TpUartDataLinkLayer* Bau2920::getPrimaryDataLinkLayer() { +TpUartDataLinkLayer* Bau2920::getPrimaryDataLinkLayer() +{ return (TpUartDataLinkLayer*)&_dlLayerPrimary; } -RfDataLinkLayer* Bau2920::getSecondaryDataLinkLayer() { +RfDataLinkLayer* Bau2920::getSecondaryDataLinkLayer() +{ return (RfDataLinkLayer*)&_dlLayerSecondary; } #endif diff --git a/src/knx/bau2920.h b/src/knx/bau2920.h index 98552fce..210f4afe 100644 --- a/src/knx/bau2920.h +++ b/src/knx/bau2920.h @@ -6,38 +6,38 @@ #include "bau_systemB_coupler.h" #include "tpuart_data_link_layer.h" #if defined(DeviceFamily_CC13X0) - #include "rf_physical_layer_cc1310.h" + #include "rf_physical_layer_cc1310.h" #else - #include "rf_physical_layer_cc1101.h" -#endif + #include "rf_physical_layer_cc1101.h" +#endif #include "rf_data_link_layer.h" #include "rf_medium_object.h" #include "cemi_server_object.h" class Bau2920 : public BauSystemBCoupler { - public: - Bau2920(Platform& platform); - void loop() override; - bool enabled() override; - void enabled(bool value) override; + 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 }; #endif diff --git a/src/knx/bau57B0.cpp b/src/knx/bau57B0.cpp index 84da0a58..da4fec83 100644 --- a/src/knx/bau57B0.cpp +++ b/src/knx/bau57B0.cpp @@ -13,7 +13,7 @@ Bau57B0::Bau57B0(Platform& platform) _ipParameters(_deviceObj, platform), _dlLayer(_deviceObj, _ipParameters, _netLayer.getInterface(), _platform, *this, (DataLinkLayerCallbacks*) this) #ifdef USE_CEMI_SERVER - , _cemiServer(*this) + , _cemiServer(*this) #endif { _netLayer.getInterface().dataLinkLayer(_dlLayer); @@ -54,30 +54,41 @@ InterfaceObject* Bau57B0::getInterfaceObject(uint8_t idx) { case 0: return &_deviceObj; + case 1: return &_addrTable; + case 2: return &_assocTable; + case 3: return &_groupObjTable; + case 4: return &_appProgram; + case 5: // would be app_program 2 return nullptr; + case 6: return &_ipParameters; #if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER) + case 7: return &_secIfObj; + case 8: return &_cemiServerObject; #elif defined(USE_CEMI_SERVER) + case 7: return &_cemiServerObject; #elif defined(USE_DATASECURE) + case 7: return &_secIfObj; #endif + default: return nullptr; } @@ -85,7 +96,7 @@ InterfaceObject* Bau57B0::getInterfaceObject(uint8_t idx) InterfaceObject* Bau57B0::getInterfaceObject(ObjectType objectType, uint16_t objectInstance) { - // We do not use it right now. + // We do not use it right now. // Required for coupler mode as there are multiple router objects for example (void) objectInstance; @@ -93,24 +104,32 @@ InterfaceObject* Bau57B0::getInterfaceObject(ObjectType objectType, uint16_t obj { case OT_DEVICE: return &_deviceObj; + case OT_ADDR_TABLE: return &_addrTable; + case OT_ASSOC_TABLE: return &_assocTable; + case OT_GRP_OBJ_TABLE: return &_groupObjTable; + case OT_APPLICATION_PROG: return &_appProgram; + case OT_IP_PARAMETER: return &_ipParameters; #ifdef USE_DATASECURE + case OT_SECURITY: return &_secIfObj; #endif #ifdef USE_CEMI_SERVER + case OT_CEMI_SERVER: return &_cemiServerObject; #endif + default: return nullptr; } @@ -143,7 +162,8 @@ void Bau57B0::loop() #endif } -IpDataLinkLayer* Bau57B0::getDataLinkLayer() { +IpDataLinkLayer* Bau57B0::getDataLinkLayer() +{ return (IpDataLinkLayer*)&_dlLayer; } #endif diff --git a/src/knx/bau57B0.h b/src/knx/bau57B0.h index e8e68357..48ec3703 100644 --- a/src/knx/bau57B0.h +++ b/src/knx/bau57B0.h @@ -10,24 +10,24 @@ 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); + public: + Bau57B0(Platform& platform); + void loop() override; + bool enabled() override; + void enabled(bool value) override; - void doMasterReset(EraseCode eraseCode, uint8_t channel) override; - private: - IpParameterObject _ipParameters; - IpDataLinkLayer _dlLayer; + 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; #ifdef USE_CEMI_SERVER - CemiServer _cemiServer; - CemiServerObject _cemiServerObject; + CemiServer _cemiServer; + CemiServerObject _cemiServerObject; #endif }; #endif diff --git a/src/knx/bau_systemB.cpp b/src/knx/bau_systemB.cpp index 61e8b828..b7271486 100644 --- a/src/knx/bau_systemB.cpp +++ b/src/knx/bau_systemB.cpp @@ -15,7 +15,7 @@ static constexpr auto kFunctionPropertyResultBufferMaxSize = 0xFF; static constexpr auto kRestartProcessTime = 3; BauSystemB::BauSystemB(Platform& platform): _memory(platform, _deviceObj), - _appProgram(_memory), + _appProgram(_memory), _platform(platform) { _memory.addSaveRestore(&_appProgram); @@ -58,42 +58,49 @@ uint8_t BauSystemB::checkmasterResetValidity(EraseCode eraseCode, uint8_t channe println("Confirmed restart requested."); 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::ResetIA: { // TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER) println("ResetIA 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::ResetParam: { // TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER) println("ResetParam 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::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: "); @@ -103,17 +110,17 @@ uint8_t BauSystemB::checkmasterResetValidity(EraseCode eraseCode, uint8_t channe } } -void BauSystemB::deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t descriptorType) +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) +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); @@ -122,6 +129,7 @@ void BauSystemB::memoryRouterWriteIndication(Priority priority, HopCountType hop print(" data: "); printHex("=>", data, number); _memory.writeMemory(memoryAddress, number, data); + if (_deviceObj.verifyMode()) { print("Sending Read indication"); @@ -129,22 +137,22 @@ void BauSystemB::memoryRouterWriteIndication(Priority priority, HopCountType hop } } -void BauSystemB::memoryRouterReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t *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) +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) +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) +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); @@ -153,39 +161,41 @@ void BauSystemB::memoryRoutingTableWriteIndication(Priority priority, HopCountTy 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) +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::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number, - uint16_t memoryAddress, uint8_t * 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::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number, - uint16_t 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)); + _memory.toAbsolute(memoryAddress)); } -void BauSystemB::memoryExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t * 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); applicationLayer().memoryExtWriteResponse(AckRequested, priority, hopType, asap, secCtrl, ReturnCodes::Success, number, memoryAddress, _memory.toAbsolute(memoryAddress)); } -void BauSystemB::memoryExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number, uint32_t memoryAddress) +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)); } @@ -196,11 +206,12 @@ void BauSystemB::doMasterReset(EraseCode eraseCode, uint8_t channel) _appProgram.masterReset(eraseCode, channel); } -void BauSystemB::restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, RestartType restartType, EraseCode eraseCode, uint8_t channel) +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"); + if (_beforeRestart != 0) _beforeRestart(); } @@ -224,18 +235,18 @@ void BauSystemB::restartRequestIndication(Priority priority, HopCountType hopTyp _platform.restart(); } -void BauSystemB::authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint32_t key) +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::userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number, uint32_t memoryAddress) +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)); + _memory.toAbsolute(memoryAddress)); } -void BauSystemB::userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data) +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); @@ -243,8 +254,8 @@ void BauSystemB::userMemoryWriteIndication(Priority priority, HopCountType hopTy userMemoryReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress); } -void BauSystemB::propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t objectIndex, - uint8_t propertyId, uint8_t propertyIndex) +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; @@ -252,56 +263,64 @@ void BauSystemB::propertyDescriptionReadIndication(Priority priority, HopCountTy 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); + 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) +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(propertyId > 0xFF || propertyIndex > 0xFF) + + if (propertyId > 0xFF || propertyIndex > 0xFF) { println("BauSystemB::propertyExtDescriptionReadIndication: propertyId or Idx > 256 are not supported"); return; } - if(descriptionType != 0) + + if (descriptionType != 0) { println("BauSystemB::propertyExtDescriptionReadIndication: only descriptionType 0 supported"); return; } + bool writeEnable = false; uint8_t type = 0; uint16_t numberOfElements = 0; uint8_t access = 0; InterfaceObject* obj = getInterfaceObject((ObjectType)objectType, objectInstance); + if (obj) obj->readPropertyDescription(pid, pidx, writeEnable, type, numberOfElements, access); applicationLayer().propertyExtDescriptionReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, propertyIndex, - descriptionType, writeEnable, type, numberOfElements, access); + descriptionType, writeEnable, type, numberOfElements, access); } -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) +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); - if(obj) + + if (obj) obj->writeProperty((PropertyID)propertyId, startIndex, data, numberOfElements); + propertyValueReadIndication(priority, hopType, asap, secCtrl, objectIndex, propertyId, numberOfElements, startIndex); } -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) +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; InterfaceObject* obj = getInterfaceObject(objectType, objectInstance); - if(obj) + + if (obj) obj->writeProperty((PropertyID)propertyId, startIndex, data, numberOfElements); else returnCode = ReturnCodes::AddressVoid; @@ -312,8 +331,8 @@ void BauSystemB::propertyValueExtWriteIndication(Priority priority, HopCountType } } -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) +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; @@ -329,9 +348,11 @@ void BauSystemB::propertyValueReadIndication(Priority priority, HopCountType hop #endif InterfaceObject* obj = getInterfaceObject(objectIndex); + if (obj) { uint8_t elementSize = obj->propertySize((PropertyID)propertyId); + if (startIndex > 0) size = elementSize * numberOfElements; else @@ -341,25 +362,28 @@ void BauSystemB::propertyValueReadIndication(Priority priority, HopCountType hop elementCount = 0; uint8_t data[size]; - if(obj) + + if (obj) obj->readProperty((PropertyID)propertyId, startIndex, elementCount, data); - + if (elementCount == 0) size = 0; - + applicationLayer().propertyValueReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, propertyId, elementCount, - startIndex, data, size); + 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) +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); + if (obj) { uint8_t elementSize = obj->propertySize((PropertyID)propertyId); + if (startIndex > 0) size = elementSize * numberOfElements; else @@ -369,18 +393,19 @@ void BauSystemB::propertyValueExtReadIndication(Priority priority, HopCountType elementCount = 0; uint8_t data[size]; - if(obj) + + if (obj) obj->readProperty((PropertyID)propertyId, startIndex, elementCount, data); if (elementCount == 0) size = 0; applicationLayer().propertyValueExtReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, elementCount, - startIndex, data, size); + 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) +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 @@ -388,7 +413,8 @@ void BauSystemB::functionPropertyCommandIndication(Priority priority, HopCountTy bool handled = false; InterfaceObject* obj = getInterfaceObject(objectIndex); - if(obj) + + if (obj) { if (obj->property((PropertyID)propertyId)->Type() == PDT_FUNCTION) { @@ -397,23 +423,25 @@ void BauSystemB::functionPropertyCommandIndication(Priority priority, HopCountTy } else { - if(_functionProperty != 0) - if(_functionProperty(objectIndex, propertyId, length, data, resultData, resultLength)) + if (_functionProperty != 0) + if (_functionProperty(objectIndex, propertyId, length, data, resultData, resultLength)) handled = true; } - } else { - if(_functionProperty != 0) - if(_functionProperty(objectIndex, propertyId, length, data, resultData, resultLength)) + } + 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) + 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) +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 @@ -421,7 +449,8 @@ void BauSystemB::functionPropertyStateIndication(Priority priority, HopCountType bool handled = true; InterfaceObject* obj = getInterfaceObject(objectIndex); - if(obj) + + if (obj) { if (obj->property((PropertyID)propertyId)->Type() == PDT_FUNCTION) { @@ -430,29 +459,32 @@ void BauSystemB::functionPropertyStateIndication(Priority priority, HopCountType } else { - if(_functionPropertyState != 0) - if(_functionPropertyState(objectIndex, propertyId, length, data, resultData, resultLength)) + if (_functionPropertyState != 0) + if (_functionPropertyState(objectIndex, propertyId, length, data, resultData, resultLength)) handled = true; } - } else { - if(_functionPropertyState != 0) - if(_functionPropertyState(objectIndex, propertyId, length, data, resultData, resultLength)) + } + 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) + 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) +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); - if(obj) + + if (obj) { PropertyDataType propType = obj->property((PropertyID)propertyId)->Type(); @@ -460,6 +492,7 @@ void BauSystemB::functionPropertyExtCommandIndication(Priority priority, HopCoun { // The first byte is reserved and 0 for PDT_FUNCTION uint8_t reservedByte = data[0]; + if (reservedByte != 0x00) { resultData[0] = ReturnCodes::DataVoid; @@ -476,6 +509,7 @@ void BauSystemB::functionPropertyExtCommandIndication(Priority priority, HopCoun 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 @@ -501,14 +535,15 @@ void BauSystemB::functionPropertyExtCommandIndication(Priority priority, HopCoun 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) +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) + + if (obj) { PropertyDataType propType = obj->property((PropertyID)propertyId)->Type(); @@ -516,6 +551,7 @@ void BauSystemB::functionPropertyExtStateIndication(Priority priority, HopCountT { // The first byte is reserved and 0 for PDT_FUNCTION uint8_t reservedByte = data[0]; + if (reservedByte != 0x00) { resultData[0] = ReturnCodes::DataVoid; @@ -548,20 +584,20 @@ void BauSystemB::functionPropertyExtStateIndication(Priority priority, HopCountT applicationLayer().functionPropertyExtStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, resultData, resultLength); } -void BauSystemB::individualAddressReadIndication(HopCountType hopType, const SecurityControl &secCtrl) +void BauSystemB::individualAddressReadIndication(HopCountType hopType, const SecurityControl& secCtrl) { if (_deviceObj.progMode()) applicationLayer().individualAddressReadResponse(AckRequested, hopType, secCtrl); } -void BauSystemB::individualAddressWriteIndication(HopCountType hopType, const SecurityControl &secCtrl, uint16_t newaddress) +void BauSystemB::individualAddressWriteIndication(HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress) { if (_deviceObj.progMode()) _deviceObj.individualAddress(newaddress); } -void BauSystemB::individualAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl &secCtrl, uint16_t newIndividualAddress, - uint8_t* knxSerialNumber) +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 @@ -569,7 +605,7 @@ void BauSystemB::individualAddressSerialNumberWriteIndication(Priority priority, _deviceObj.individualAddress(newIndividualAddress); } -void BauSystemB::individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl &secCtrl, uint8_t* knxSerialNumber) +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. @@ -590,6 +626,7 @@ 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); @@ -618,10 +655,13 @@ void BauSystemB::nextRestartState() case Idle: /* inactive state, do nothing */ break; + case Connecting: /* wait for connection, we do nothing here */ break; + case Connected: + /* connection confirmed, we send restartRequest, but we wait a moment (sending ACK etc)... */ if (millis() - _restartDelay > 30) { @@ -629,58 +669,64 @@ void BauSystemB::nextRestartState() _restartState = Restarted; _restartDelay = millis(); } + break; + case Restarted: + /* restart is finished, we send a disconnect */ if (millis() - _restartDelay > 30) { applicationLayer().disconnectRequest(SystemPriority); _restartState = Idle; } + default: break; } } -void BauSystemB::systemNetworkParameterReadIndication(Priority priority, HopCountType hopType, const SecurityControl &secCtrl, uint16_t objectType, - uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength) +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) // See KNX spec. 3.5.2 p.33 (Management Procedures: Procedures with A_SystemNetworkParameter_Read) - switch((NmReadSerialNumberType)operand) + switch ((NmReadSerialNumberType)operand) { case NM_Read_SerialNumber_By_ProgrammingMode: // NM_Read_SerialNumber_By_ProgrammingMode + // 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); + testInfo, testInfoLength, (uint8_t*)_deviceObj.propertyData(PID_SERIAL_NUMBER), 6); } - break; + + break; case NM_Read_SerialNumber_By_ExFactoryState: // NM_Read_SerialNumber_By_ExFactoryState - break; + break; case NM_Read_SerialNumber_By_PowerReset: // NM_Read_SerialNumber_By_PowerReset - break; + break; case NM_Read_SerialNumber_By_ManufacturerSpecific: // Manufacturer specific use of A_SystemNetworkParameter_Read - break; + break; } } -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::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) + uint8_t& numberOfElements, uint16_t startIndex, + uint8_t** data, uint32_t& length) { uint32_t size = 0; uint8_t elementCount = numberOfElements; @@ -690,10 +736,12 @@ void BauSystemB::propertyValueRead(ObjectType objectType, uint8_t objectInstance if (obj) { uint8_t elementSize = obj->propertySize((PropertyID)propertyId); + if (startIndex > 0) size = elementSize * 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); } @@ -708,13 +756,14 @@ void BauSystemB::propertyValueRead(ObjectType objectType, uint8_t objectInstance } void BauSystemB::propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, - uint8_t &numberOfElements, uint16_t startIndex, + uint8_t& numberOfElements, uint16_t startIndex, uint8_t* data, uint32_t length) { InterfaceObject* obj = getInterfaceObject(objectType, objectInstance); - if(obj) + + if (obj) obj->writeProperty((PropertyID)propertyId, startIndex, data, numberOfElements); - else + else numberOfElements = 0; } diff --git a/src/knx/bau_systemB.h b/src/knx/bau_systemB.h index c652c940..576dac73 100644 --- a/src/knx/bau_systemB.h +++ b/src/knx/bau_systemB.h @@ -14,120 +14,120 @@ 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; + 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(); + Platform& platform(); + ApplicationProgramObject& parameters(); + DeviceObject& deviceObject(); - Memory& memory(); - void readMemory(); - void writeMemory(); - void addSaveRestore(SaveRestore* obj); + Memory& memory(); + void readMemory(); + void writeMemory(); + void addSaveRestore(SaveRestore* obj); - bool restartRequest(uint16_t asap, const SecurityControl secCtrl); - uint8_t checkmasterResetValidity(EraseCode eraseCode, uint8_t channel); + bool restartRequest(uint16_t asap, const SecurityControl secCtrl); + uint8_t checkmasterResetValidity(EraseCode eraseCode, uint8_t channel); - 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 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(); - protected: - virtual ApplicationLayer& applicationLayer() = 0; - virtual InterfaceObject* getInterfaceObject(uint8_t idx) = 0; - virtual InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance) = 0; + protected: + virtual ApplicationLayer& applicationLayer() = 0; + virtual InterfaceObject* getInterfaceObject(uint8_t idx) = 0; + virtual InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance) = 0; - 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; + 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; - void nextRestartState(); - virtual void doMasterReset(EraseCode eraseCode, uint8_t channel); + void nextRestartState(); + virtual void doMasterReset(EraseCode eraseCode, uint8_t channel); - enum RestartState - { - Idle, - Connecting, - Connected, - Restarted - }; + 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; + 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; }; diff --git a/src/knx/bau_systemB_coupler.cpp b/src/knx/bau_systemB_coupler.cpp index 5a7f12bf..e71164fe 100644 --- a/src/knx/bau_systemB_coupler.cpp +++ b/src/knx/bau_systemB_coupler.cpp @@ -38,15 +38,15 @@ void BauSystemBCoupler::loop() 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; - + _configured = _appProgram.loadState() == LS_LOADED; #ifdef USE_DATASECURE _configured &= _secIfObj.loadState() == LS_LOADED; #endif - + return _configured; } diff --git a/src/knx/bau_systemB_coupler.h b/src/knx/bau_systemB_coupler.h index 2cfc5be7..4fea4f4e 100644 --- a/src/knx/bau_systemB_coupler.h +++ b/src/knx/bau_systemB_coupler.h @@ -16,25 +16,25 @@ class BauSystemBCoupler : public BauSystemB { - public: - BauSystemBCoupler(Platform& platform); - void loop() override; - bool configured() override; + 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; }; diff --git a/src/knx/bau_systemB_device.cpp b/src/knx/bau_systemB_device.cpp index 3ee44250..872d6777 100644 --- a/src/knx/bau_systemB_device.cpp +++ b/src/knx/bau_systemB_device.cpp @@ -53,9 +53,9 @@ void BauSystemBDevice::loop() void BauSystemBDevice::sendNextGroupTelegram() { - if(!configured()) + if (!configured()) return; - + static uint16_t startIdx = 1; GroupObjectTableObject& table = _groupObjTable; @@ -66,19 +66,23 @@ void BauSystemBDevice::sendNextGroupTelegram() GroupObject& go = table.get(asap); ComFlag flag = go.commFlag(); + if (flag != ReadRequest && flag != WriteRequest) continue; - if (flag == WriteRequest) + if (flag == WriteRequest) { #ifdef SMALL_GROUPOBJECT GroupObject::processClassCallback(go); #else GroupObjectUpdatedHandler handler = go.callback(); + if (handler) handler(go); + #endif } + if (!go.communicationEnable()) { go.commFlag(Ok); @@ -99,7 +103,7 @@ void BauSystemBDevice::sendNextGroupTelegram() { uint8_t* data = go.valueRef(); _appLayer.groupValueWriteRequest(AckRequested, asap, go.priority(), NetworkLayerParameter, goSecurity, data, - go.sizeInTelegram()); + go.sizeInTelegram()); } else if (flag == ReadRequest) { @@ -115,9 +119,10 @@ void BauSystemBDevice::sendNextGroupTelegram() startIdx = 1; } -void BauSystemBDevice::updateGroupObject(GroupObject & go, uint8_t * data, uint8_t length) +void BauSystemBDevice::updateGroupObject(GroupObject& go, uint8_t* data, uint8_t length) { uint8_t* goData = go.valueRef(); + if (length != go.valueSize()) { go.commFlag(Error); @@ -133,8 +138,10 @@ void BauSystemBDevice::updateGroupObject(GroupObject & go, uint8_t * data, uint8 GroupObject::processClassCallback(go); #else GroupObjectUpdatedHandler handler = go.callback(); + if (handler) handler(go); + #endif } else @@ -146,14 +153,14 @@ void BauSystemBDevice::updateGroupObject(GroupObject & go, uint8_t * data, uint8 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; - + _configured = _groupObjTable.loadState() == LS_LOADED - && _addrTable.loadState() == LS_LOADED - && _assocTable.loadState() == LS_LOADED - && _appProgram.loadState() == LS_LOADED; + && _addrTable.loadState() == LS_LOADED + && _assocTable.loadState() == LS_LOADED + && _appProgram.loadState() == LS_LOADED; #ifdef USE_DATASECURE _configured &= _secIfObj.loadState() == LS_LOADED; @@ -174,25 +181,27 @@ void BauSystemBDevice::doMasterReset(EraseCode eraseCode, uint8_t 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) +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); } -void BauSystemBDevice::groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl &secCtrl, bool status) +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); } -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; @@ -205,19 +214,20 @@ void BauSystemBDevice::groupValueReadIndication(uint16_t asap, Priority priority println("GroupValueRead: access denied due to wrong security flags"); return; } + #endif GroupObject& go = _groupObjTable.get(asap); if (!go.communicationEnable() || !go.readEnable()) return; - + 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) +void BauSystemBDevice::groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, + uint8_t dataLength) { GroupObject& go = _groupObjTable.get(asap); @@ -227,7 +237,7 @@ void BauSystemBDevice::groupValueReadAppLayerConfirm(uint16_t asap, Priority pri 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; @@ -240,6 +250,7 @@ void BauSystemBDevice::groupValueWriteIndication(uint16_t asap, Priority priorit println("GroupValueWrite: access denied due to wrong security flags"); return; } + #endif GroupObject& go = _groupObjTable.get(asap); diff --git a/src/knx/bau_systemB_device.h b/src/knx/bau_systemB_device.h index 1dadf87d..4e5e283e 100644 --- a/src/knx/bau_systemB_device.h +++ b/src/knx/bau_systemB_device.h @@ -18,40 +18,40 @@ 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, + 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; }; diff --git a/src/knx/bits.cpp b/src/knx/bits.cpp index d69f17dc..16c2d6b8 100644 --- a/src/knx/bits.cpp +++ b/src/knx/bits.cpp @@ -9,14 +9,21 @@ const uint8_t* popByte(uint8_t& b, const uint8_t* data) } #ifndef KNX_NO_PRINT -void printHex(const char* suffix, const uint8_t *data, size_t length, bool newline) +void printHex(const char* suffix, const uint8_t* data, size_t length, bool newline) { print(suffix); - for (size_t i = 0; i < length; i++) { - if (data[i] < 0x10) { print("0"); } + + for (size_t i = 0; i < length; i++) + { + if (data[i] < 0x10) + { + print("0"); + } + print(data[i], HEX); print(" "); } + if (newline) { println(); @@ -76,7 +83,7 @@ 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]; - + data += size; return data; } @@ -86,7 +93,7 @@ uint16_t getWord(const uint8_t* data) return (data[0] << 8) + data[1]; } -uint32_t getInt(const uint8_t * data) +uint32_t getInt(const uint8_t* data) { return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]; } @@ -109,6 +116,7 @@ uint64_t sixBytesToUInt64(uint8_t* data) { l = (l << 8) + data[i]; } + return l; } @@ -127,35 +135,44 @@ uint16_t crc16Ccitt(uint8_t* input, uint16_t length) uint32_t polynom = 0x1021; uint32_t 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; + if ((result & 0x10000) != 0) result ^= polynom; } + return result & 0xffff; } 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 - - // for much data, using a lookup table would be a way faster CRC calculation - uint32_t crc = 0; - for (uint32_t i = 0; i < length; i++) { - uint8_t bite = input[i] & 0xff; - 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; - } + // 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 (uint32_t i = 0; i < length; i++) + { + uint8_t bite = input[i] & 0xff; + + 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; } diff --git a/src/knx/bits.h b/src/knx/bits.h index fe58f48d..3df81891 100644 --- a/src/knx/bits.h +++ b/src/knx/bits.h @@ -4,102 +4,102 @@ #include #if defined(__linux__) -#include + #include #elif defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_STM32) || defined (DeviceFamily_CC13X0) -#define getbyte(x,n) (*(((uint8_t*)&(x))+n)) -#define htons(x) ( (getbyte(x,0)<<8) | getbyte(x,1) ) -#define htonl(x) ( (getbyte(x,0)<<24) | (getbyte(x,1)<<16) | (getbyte(x,2)<<8) | getbyte(x,3) ) -#define ntohs(x) htons(x) -#define ntohl(x) htonl(x) + #define getbyte(x,n) (*(((uint8_t*)&(x))+n)) + #define htons(x) ( (getbyte(x,0)<<8) | getbyte(x,1) ) + #define htonl(x) ( (getbyte(x,0)<<24) | (getbyte(x,1)<<16) | (getbyte(x,2)<<8) | getbyte(x,3) ) + #define ntohs(x) htons(x) + #define ntohl(x) htonl(x) #endif #ifndef MIN -#define MIN(a, b) ((a < b) ? (a) : (b)) + #define MIN(a, b) ((a < b) ? (a) : (b)) #endif #ifndef MAX -#define MAX(a, b) ((a > b) ? (a) : (b)) + #define MAX(a, b) ((a > b) ? (a) : (b)) #endif #ifndef ABS -#define ABS(x) ((x > 0) ? (x) : (-x)) + #define ABS(x) ((x > 0) ? (x) : (-x)) #endif #if defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_STM32) -#include + #include #elif defined(ARDUINO_ARCH_ESP8266) -#include -#include + #include + #include #elif defined(ARDUINO_ARCH_ESP32) -#include -#include + #include + #include #else // Non-Arduino platforms -#define lowByte(val) ((val)&255) -#define highByte(val) (((val) >> ((sizeof(val) - 1) << 3)) & 255) -#define bitRead(val, bitno) (((val) >> (bitno)) & 1) - -// print functions are implemented in the platform files -#define DEC 10 -#define HEX 16 - -#define INPUT (0x0) -#define OUTPUT (0x1) -#define INPUT_PULLUP (0x2) -#define INPUT_PULLDOWN (0x3) - -#define LOW (0x0) -#define HIGH (0x1) -#define CHANGE 2 -#define FALLING 3 -#define RISING 4 - -void delay(uint32_t millis); -void delayMicroseconds (unsigned int howLong); -uint32_t millis(); -void pinMode(uint32_t dwPin, uint32_t dwMode); -void digitalWrite(uint32_t dwPin, uint32_t dwVal); -uint32_t digitalRead(uint32_t dwPin); -typedef void (*voidFuncPtr)(void); -void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode); + #define lowByte(val) ((val)&255) + #define highByte(val) (((val) >> ((sizeof(val) - 1) << 3)) & 255) + #define bitRead(val, bitno) (((val) >> (bitno)) & 1) + + // print functions are implemented in the platform files + #define DEC 10 + #define HEX 16 + + #define INPUT (0x0) + #define OUTPUT (0x1) + #define INPUT_PULLUP (0x2) + #define INPUT_PULLDOWN (0x3) + + #define LOW (0x0) + #define HIGH (0x1) + #define CHANGE 2 + #define FALLING 3 + #define RISING 4 + + void delay(uint32_t millis); + void delayMicroseconds (unsigned int howLong); + uint32_t millis(); + void pinMode(uint32_t dwPin, uint32_t dwMode); + void digitalWrite(uint32_t dwPin, uint32_t dwVal); + uint32_t digitalRead(uint32_t dwPin); + typedef void (*voidFuncPtr)(void); + void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode); #endif #ifndef KNX_NO_PRINT -void print(const char[]); -void print(char); -void print(unsigned char, int = DEC); -void print(int, int = DEC); -void print(unsigned int, int = DEC); -void print(long, int = DEC); -void print(unsigned long, int = DEC); -void print(long long, int = DEC); -void print(unsigned long long, int = DEC); -void print(double); - -void println(const char[]); -void println(char); -void println(unsigned char, int = DEC); -void println(int, int = DEC); -void println(unsigned int, int = DEC); -void println(long, int = DEC); -void println(unsigned long, int = DEC); -void println(long long, int = DEC); -void println(unsigned long long, int = DEC); -void println(double); -void println(void); - -void printHex(const char* suffix, const uint8_t *data, size_t length, bool newline = true); + void print(const char[]); + void print(char); + void print(unsigned char, int = DEC); + void print(int, int = DEC); + void print(unsigned int, int = DEC); + void print(long, int = DEC); + void print(unsigned long, int = DEC); + void print(long long, int = DEC); + void print(unsigned long long, int = DEC); + void print(double); + + void println(const char[]); + void println(char); + void println(unsigned char, int = DEC); + void println(int, int = DEC); + void println(unsigned int, int = DEC); + void println(long, int = DEC); + void println(unsigned long, int = DEC); + void println(long long, int = DEC); + void println(unsigned long long, int = DEC); + void println(double); + void println(void); + + void printHex(const char* suffix, const uint8_t* data, size_t length, bool newline = true); #else -#define print(...) do {} while(0) -#define println(...) do {} while(0) -#define printHex(...) do {} while(0) + #define print(...) do {} while(0) + #define println(...) do {} while(0) + #define printHex(...) do {} while(0) #endif #ifdef KNX_ACTIVITYCALLBACK -#define KNX_ACTIVITYCALLBACK_DIR 0x00 -#define KNX_ACTIVITYCALLBACK_DIR_RECV 0x00 -#define KNX_ACTIVITYCALLBACK_DIR_SEND 0x01 -#define KNX_ACTIVITYCALLBACK_IPUNICAST 0x02 -#define KNX_ACTIVITYCALLBACK_NET 0x04 + #define KNX_ACTIVITYCALLBACK_DIR 0x00 + #define KNX_ACTIVITYCALLBACK_DIR_RECV 0x00 + #define KNX_ACTIVITYCALLBACK_DIR_SEND 0x01 + #define KNX_ACTIVITYCALLBACK_IPUNICAST 0x02 + #define KNX_ACTIVITYCALLBACK_NET 0x04 #endif const uint8_t* popByte(uint8_t& b, const uint8_t* data); @@ -128,8 +128,8 @@ enum ParameterFloatEncodings #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 -#undef max -#undef min -// end of temporary undef + // 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 + #undef max + #undef min + // end of temporary undef #endif diff --git a/src/knx/callback_property.h b/src/knx/callback_property.h index 542b6597..3a99f9f6 100644 --- a/src/knx/callback_property.h +++ b/src/knx/callback_property.h @@ -6,33 +6,34 @@ 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; + 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) + {} - 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; + 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 _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; }; diff --git a/src/knx/cemi_frame.cpp b/src/knx/cemi_frame.cpp index 50354b81..2b04e7a9 100644 --- a/src/knx/cemi_frame.cpp +++ b/src/knx/cemi_frame.cpp @@ -7,17 +7,17 @@ cEMI Frame Format +--------+--------+--------+--------+---------+---------+--------+---------+ - | _data | + | _data | +--------+--------+--------+--------+---------+---------+--------+---------+ - | LPDU | - +--------+--------+--------+--------+---------+---------+--------+---------+ - | NPDU | + | LPDU | + +--------+--------+--------+--------+---------+---------+--------+---------+ + | NPDU | +---------+--------+--------+--------+--------+---------+---------+--------+---------+ | Header | Msg |Add.Info| Ctrl 1 | Ctrl 2 | Source | Dest. | Data | TPDU | | | Code | Length | | | Address | Address | Length | APDU | +---------+--------+--------+--------+--------+---------+---------+--------+---------+ 6 bytes 1 byte 1 byte 1 byte 1 byte 2 bytes 2 bytes 1 byte n bytes - + Header = See below the structure of a cEMI header Message Code = See below. On Appendix A is the list of all existing EMI and cEMI codes Add.Info Length = 0x00 - no additional info @@ -31,9 +31,9 @@ cEMI Frame Format protocol control information (TPCI), application protocol control information (APCI) and data passed as an argument from higher layers of the KNX communication stack - + Control Field 1 - + Bit | ------+--------------------------------------------------------------- 7 | Frame Type - 0x0 for extended frame @@ -60,9 +60,9 @@ Control Field 1 0 | Confirm - 0x0 no error | (L_Data.con) - 0x1 error ------+--------------------------------------------------------------- - + Control Field 2 - + Bit | ------+--------------------------------------------------------------- 7 | Destination Address Type - 0x0 individual address @@ -72,11 +72,11 @@ Control Field 1 ------+--------------------------------------------------------------- 3-0 | Extended Frame Format - 0x0 standard frame ------+--------------------------------------------------------------- -*/ +*/ CemiFrame::CemiFrame(uint8_t* data, uint16_t length) - : _npdu(data + data[1] + NPDU_LPDU_DIFF, *this), - _tpdu(data + data[1] + TPDU_LPDU_DIFF, *this), + : _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; @@ -86,8 +86,8 @@ CemiFrame::CemiFrame(uint8_t* data, uint16_t length) CemiFrame::CemiFrame(uint8_t apduLength) : _data(buffer), - _npdu(_data + NPDU_LPDU_DIFF, *this), - _tpdu(_data + TPDU_LPDU_DIFF, *this), + _npdu(_data + NPDU_LPDU_DIFF, *this), + _tpdu(_data + TPDU_LPDU_DIFF, *this), _apdu(_data + APDU_LPDU_DIFF, *this) { _ctrl1 = _data + CEMI_HEADER_SIZE; @@ -98,13 +98,13 @@ CemiFrame::CemiFrame(uint8_t apduLength) _length = _npdu.length() + NPDU_LPDU_DIFF; } -CemiFrame::CemiFrame(const CemiFrame & other) +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; + _ctrl1 = _data + CEMI_HEADER_SIZE; _length = other._length; memcpy(_data, other._data, other.totalLenght()); @@ -149,7 +149,7 @@ uint16_t CemiFrame::telegramLengthtTP() const void CemiFrame::fillTelegramTP(uint8_t* data) { uint16_t len = telegramLengthtTP(); - + if (frameType() == StandardFrame) { uint8_t octet5 = (_ctrl1[1] & 0xF0) | (_ctrl1[6] & 0x0F); @@ -162,6 +162,7 @@ void CemiFrame::fillTelegramTP(uint8_t* data) { memcpy(data, _ctrl1, len - 1); } + data[len - 1] = calcCrcTP(data, len - 1); } @@ -180,7 +181,7 @@ void CemiFrame::fillTelegramRF(uint8_t* data) // 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 + // 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 @@ -201,13 +202,13 @@ uint16_t CemiFrame::dataLength() return _length; } -uint8_t CemiFrame::calcCrcTP(uint8_t * buffer, uint16_t len) +uint8_t CemiFrame::calcCrcTP(uint8_t* buffer, uint16_t len) { uint8_t crc = 0xFF; - + for (uint16_t i = 0; i < len; i++) crc ^= buffer[i]; - + return crc; } @@ -387,14 +388,16 @@ bool CemiFrame::valid() const 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) - ){ + || (_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; } diff --git a/src/knx/cemi_frame.h b/src/knx/cemi_frame.h index 8c82d43f..03ac2a3c 100644 --- a/src/knx/cemi_frame.h +++ b/src/knx/cemi_frame.h @@ -18,77 +18,77 @@ class CemiFrame { - friend class DataLinkLayer; + 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); #ifdef USE_RF - // 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); #endif - 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; - 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 #ifdef USE_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 - #endif + // 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; }; diff --git a/src/knx/cemi_server.cpp b/src/knx/cemi_server.cpp index 3961c617..a4e7bc8b 100644 --- a/src/knx/cemi_server.cpp +++ b/src/knx/cemi_server.cpp @@ -13,10 +13,10 @@ 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), @@ -80,6 +80,7 @@ void CemiServer::dataIndicationToTunnel(CemiFrame& frame) #endif #ifdef USE_RF + if (isRf) { data[0] = L_data_ind; // Message Code @@ -97,6 +98,7 @@ void CemiServer::dataIndicationToTunnel(CemiFrame& frame) memcpy(&data[0], frame.data(), frame.dataLength()); #ifdef USE_RF } + #endif CemiFrame tmpFrame(data, sizeof(data)); @@ -121,7 +123,7 @@ void CemiServer::dataIndicationToTunnel(CemiFrame& frame) void CemiServer::frameReceived(CemiFrame& frame) { - switch(frame.messageCode()) + switch (frame.messageCode()) { case L_data_req: { @@ -143,13 +145,13 @@ void CemiServer::frameReceived(CemiFrame& frame) case M_FuncPropCommand_req: { - println("M_FuncPropCommand_req not implemented"); + println("M_FuncPropCommand_req not implemented"); break; } case M_FuncPropStateRead_req: { - println("M_FuncPropStateRead_req not implemented"); + println("M_FuncPropStateRead_req not implemented"); break; } @@ -166,6 +168,7 @@ void CemiServer::frameReceived(CemiFrame& frame) 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: @@ -175,31 +178,35 @@ void CemiServer::frameReceived(CemiFrame& frame) void CemiServer::handleLData(CemiFrame& frame) { - // Fill in the cEMI client address if the client sets + // 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) + if (frame.sourceAddress() == 0x0000) { frame.sourceAddress(_clientAddress); } + #endif #ifdef USE_RF + 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) + ((frame.data())[2] == 0x02) && // Additional info type: RF + ((frame.data())[3] == 0x08) ) // Additional info length of type RF: 8 bytes (fixed) { 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]); } @@ -216,6 +223,7 @@ void CemiServer::handleLData(CemiFrame& frame) _frameNumber = (_frameNumber + 1) & 0x7; } } + #endif #ifdef KNX_LOG_TUNNELING @@ -233,13 +241,13 @@ void CemiServer::handleMPropRead(CemiFrame& frame) #ifdef KNX_LOG_TUNNELING 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); + uint16_t startIndex = frame.data()[6] | ((frame.data()[5] & 0x0F) << 8); uint8_t* data = nullptr; uint32_t dataSize = 0; @@ -264,15 +272,15 @@ void CemiServer::handleMPropRead(CemiFrame& frame) // 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)) + 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)) + else if (((ObjectType) objectType == OT_DEVICE) && + (propertyId == PID_SUBNET_ADDR) && + (numberOfElements == 1)) { data[0] = (uint8_t) ((_clientAddress >> 8) & 0xFF); } @@ -286,7 +294,7 @@ void CemiServer::handleMPropRead(CemiFrame& frame) // Prepare positive response uint8_t responseData[7 + dataSize]; memcpy(responseData, frame.data(), 7); - memcpy(&responseData[7], data, dataSize); + memcpy(&responseData[7], data, dataSize); CemiFrame responseFrame(responseData, sizeof(responseData)); responseFrame.messageCode(M_PropRead_con); @@ -313,21 +321,21 @@ void CemiServer::handleMPropRead(CemiFrame& frame) #ifdef USE_USB _usbTunnelInterface.sendCemiFrame(responseFrame); #elif defined(KNX_TUNNELING) - _dataLinkLayerPrimary->dataRequestToTunnel(responseFrame); + _dataLinkLayerPrimary->dataRequestToTunnel(responseFrame); #endif } } void CemiServer::handleMPropWrite(CemiFrame& frame) { - print("M_PropWrite_req: "); + 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); + uint16_t startIndex = frame.data()[6] | ((frame.data()[5] & 0x0F) << 8); uint8_t* requestData = &frame.data()[7]; uint32_t requestDataSize = frame.dataLength() - 7; @@ -345,9 +353,9 @@ void CemiServer::handleMPropWrite(CemiFrame& frame) printHex(" -> data: ", requestData, requestDataSize); // Patch request for device address in device object - if (((ObjectType) objectType == OT_DEVICE) && - (propertyId == PID_DEVICE_ADDR) && - (numberOfElements == 1)) + 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 @@ -355,16 +363,16 @@ void CemiServer::handleMPropWrite(CemiFrame& frame) print("cEMI client address: "); println(_clientAddress, HEX); } - else if (((ObjectType) objectType == OT_DEVICE) && - (propertyId == PID_SUBNET_ADDR) && - (numberOfElements == 1)) + 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); @@ -383,7 +391,7 @@ void CemiServer::handleMPropWrite(CemiFrame& frame) #ifdef USE_USB _usbTunnelInterface.sendCemiFrame(responseFrame); #elif defined(KNX_TUNNELING) - _dataLinkLayerPrimary->dataRequestToTunnel(responseFrame); + _dataLinkLayerPrimary->dataRequestToTunnel(responseFrame); #endif } else @@ -402,14 +410,14 @@ void CemiServer::handleMPropWrite(CemiFrame& frame) #ifdef USE_USB _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"); + 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 diff --git a/src/knx/cemi_server.h b/src/knx/cemi_server.h index f97ead89..2aac12b1 100644 --- a/src/knx/cemi_server.h +++ b/src/knx/cemi_server.h @@ -14,54 +14,54 @@ 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 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); + public: + /** + * The constructor. + * @param bau methods are called here depending of the content of the APDU + */ + CemiServer(BauSystemB& bau); - void dataLinkLayer(DataLinkLayer& layer); + void dataLinkLayer(DataLinkLayer& layer); #ifdef KNX_TUNNELING - void dataLinkLayerPrimary(DataLinkLayer& layer); + void dataLinkLayerPrimary(DataLinkLayer& layer); #endif - // from data link layer - // Only L_Data service - void dataIndicationToTunnel(CemiFrame& frame); - void dataConfirmationToTunnel(CemiFrame& frame); + // from data link layer + // Only L_Data service + void dataIndicationToTunnel(CemiFrame& frame); + void dataConfirmationToTunnel(CemiFrame& frame); - // From tunnel interface - void frameReceived(CemiFrame& frame); + // From tunnel interface + void frameReceived(CemiFrame& frame); - uint16_t clientAddress() const; - void clientAddress(uint16_t value); + uint16_t clientAddress() const; + void clientAddress(uint16_t value); - void loop(); - - private: - uint16_t _clientAddress = 0; - uint8_t _frameNumber = 0; + void loop(); - void handleLData(CemiFrame& frame); - void handleMPropRead(CemiFrame& frame); - void handleMPropWrite(CemiFrame& frame); - void handleMReset(CemiFrame& frame); + private: + uint16_t _clientAddress = 0; + uint8_t _frameNumber = 0; - DataLinkLayer* _dataLinkLayer = nullptr; + void handleLData(CemiFrame& frame); + void handleMPropRead(CemiFrame& frame); + void handleMPropWrite(CemiFrame& frame); + void handleMReset(CemiFrame& frame); + + DataLinkLayer* _dataLinkLayer = nullptr; #ifdef KNX_TUNNELING - DataLinkLayer* _dataLinkLayerPrimary = nullptr; + DataLinkLayer* _dataLinkLayerPrimary = nullptr; #endif - BauSystemB& _bau; + BauSystemB& _bau; #ifdef USE_USB - UsbTunnelInterface _usbTunnelInterface; + UsbTunnelInterface _usbTunnelInterface; #endif }; diff --git a/src/knx/cemi_server_object.cpp b/src/knx/cemi_server_object.cpp index 140c4149..30ef39d7 100644 --- a/src/knx/cemi_server_object.cpp +++ b/src/knx/cemi_server_object.cpp @@ -26,20 +26,23 @@ void CemiServerObject::setMediumTypeAsSupported(DptMedium dptMedium) uint16_t mediaTypesSupported; property(PID_MEDIUM_TYPE)->read(mediaTypesSupported); - switch(dptMedium) + 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; + 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); diff --git a/src/knx/cemi_server_object.h b/src/knx/cemi_server_object.h index 726f82e3..143c7d7d 100644 --- a/src/knx/cemi_server_object.h +++ b/src/knx/cemi_server_object.h @@ -7,11 +7,11 @@ class CemiServerObject: public InterfaceObject { -public: - CemiServerObject(); + public: + CemiServerObject(); - void setMediumTypeAsSupported(DptMedium dptMedium); - void clearSupportedMediaTypes(); + void setMediumTypeAsSupported(DptMedium dptMedium); + void clearSupportedMediaTypes(); }; #endif diff --git a/src/knx/config.h b/src/knx/config.h index a7a0adab..c2a394e2 100644 --- a/src/knx/config.h +++ b/src/knx/config.h @@ -2,83 +2,83 @@ #ifndef NO_KNX_CONFIG -#ifdef ARDUINO_ARCH_SAMD -#define SPI_SS_PIN 10 -#define GPIO_GDO2_PIN 9 -#define GPIO_GDO0_PIN 7 -#else // Linux Platform (Raspberry Pi) -#define SPI_SS_PIN 8 // GPIO 8 (SPI_CE0_N) -> WiringPi: 10 -> Pin number on header: 24 -#define GPIO_GDO2_PIN 25 // GPIO 25 (GPIO_GEN6) -> WiringPi: 6 -> Pin number on header: 22 -#define GPIO_GDO0_PIN 24 // GPIO 24 (GPIO_GEN5) -> WiringPi: 5 -> Pin number on header: 18 -#endif - -// Normal devices -// TP1: 0x07B0 -// RF: 0x27B0 -// IP: 0x57B0 -//#define MASK_VERSION 0x07B0 -//#define MASK_VERSION 0x27B0 -//#define MASK_VERSION 0x57B0 - -// Couplers -// IP/TP1: 0x091A -// TP1/RF: 0x2920 -//#define MASK_VERSION 0x091A -//#define MASK_VERSION 0x2920 - -// Data Linklayer Driver Options -#if MASK_VERSION == 0x07B0 -#define USE_TP -#endif - -#if MASK_VERSION == 0x27B0 -#define USE_RF -#endif - -#if MASK_VERSION == 0x57B0 -#define USE_IP -#endif - -#if MASK_VERSION == 0x091A -#define USE_TP -#define USE_IP -#endif - -#if MASK_VERSION == 0x2920 -#define USE_TP -#define USE_RF -#endif - -// cEMI options -//#define USE_USB -//#define USE_CEMI_SERVER -#if defined(USE_USB) || defined(KNX_TUNNELING) -#define USE_CEMI_SERVER -#endif - -// KNX Data Secure Options -// Define via a compiler -D flag if required -// #define USE_DATASECURE - -// option to have GroupObjects (KO in German) use 8 bytes mangement information RAM instead of 19 bytes -// see knx-demo-small-go for example -// this option might be also set via compiler flag -DSMALL_GROUPOBJECT if required -//#define SMALL_GROUPOBJECT - -// Some defines to reduce footprint -// Do not perform conversion from KNXValue(const char*) to other types, it mainly avoids the expensive strtod -//#define KNX_NO_STRTOx_CONVERSION -// Do not print messages -//#define KNX_NO_PRINT -// Do not use SPI (Arduino variants) -//#define KNX_NO_SPI -// Do not use the default UART (Arduino variants), it must be defined by ArduinoPlatform::knxUart -// (combined with other flags (HWSERIAL_NONE for stm32) - avoid allocation of RX/TX buffers for all serial lines) -//#define KNX_NO_DEFAULT_UART + #ifdef ARDUINO_ARCH_SAMD + #define SPI_SS_PIN 10 + #define GPIO_GDO2_PIN 9 + #define GPIO_GDO0_PIN 7 + #else // Linux Platform (Raspberry Pi) + #define SPI_SS_PIN 8 // GPIO 8 (SPI_CE0_N) -> WiringPi: 10 -> Pin number on header: 24 + #define GPIO_GDO2_PIN 25 // GPIO 25 (GPIO_GEN6) -> WiringPi: 6 -> Pin number on header: 22 + #define GPIO_GDO0_PIN 24 // GPIO 24 (GPIO_GEN5) -> WiringPi: 5 -> Pin number on header: 18 + #endif + + // Normal devices + // TP1: 0x07B0 + // RF: 0x27B0 + // IP: 0x57B0 + //#define MASK_VERSION 0x07B0 + //#define MASK_VERSION 0x27B0 + //#define MASK_VERSION 0x57B0 + + // Couplers + // IP/TP1: 0x091A + // TP1/RF: 0x2920 + //#define MASK_VERSION 0x091A + //#define MASK_VERSION 0x2920 + + // Data Linklayer Driver Options + #if MASK_VERSION == 0x07B0 + #define USE_TP + #endif + + #if MASK_VERSION == 0x27B0 + #define USE_RF + #endif + + #if MASK_VERSION == 0x57B0 + #define USE_IP + #endif + + #if MASK_VERSION == 0x091A + #define USE_TP + #define USE_IP + #endif + + #if MASK_VERSION == 0x2920 + #define USE_TP + #define USE_RF + #endif + + // cEMI options + //#define USE_USB + //#define USE_CEMI_SERVER + #if defined(USE_USB) || defined(KNX_TUNNELING) + #define USE_CEMI_SERVER + #endif + + // KNX Data Secure Options + // Define via a compiler -D flag if required + // #define USE_DATASECURE + + // option to have GroupObjects (KO in German) use 8 bytes mangement information RAM instead of 19 bytes + // see knx-demo-small-go for example + // this option might be also set via compiler flag -DSMALL_GROUPOBJECT if required + //#define SMALL_GROUPOBJECT + + // Some defines to reduce footprint + // Do not perform conversion from KNXValue(const char*) to other types, it mainly avoids the expensive strtod + //#define KNX_NO_STRTOx_CONVERSION + // Do not print messages + //#define KNX_NO_PRINT + // Do not use SPI (Arduino variants) + //#define KNX_NO_SPI + // Do not use the default UART (Arduino variants), it must be defined by ArduinoPlatform::knxUart + // (combined with other flags (HWSERIAL_NONE for stm32) - avoid allocation of RX/TX buffers for all serial lines) + //#define KNX_NO_DEFAULT_UART #endif #if !defined(MASK_VERSION) -#error MASK_VERSION must be defined! See config.h for possible values! + #error MASK_VERSION must be defined! See config.h for possible values! #endif diff --git a/src/knx/data_link_layer.cpp b/src/knx/data_link_layer.cpp index 5782fadc..f3396d46 100644 --- a/src/knx/data_link_layer.cpp +++ b/src/knx/data_link_layer.cpp @@ -9,7 +9,7 @@ void DataLinkLayerCallbacks::activity(uint8_t info) { - if(_activityCallback) + if (_activityCallback) _activityCallback(info); } @@ -61,31 +61,33 @@ void DataLinkLayer::dataRequestFromTunnel(CemiFrame& frame) _cemiServer->dataConfirmationToTunnel(frame); frame.messageCode(L_data_ind); - + // 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 + // 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.addressType() == AddressType::IndividualAddress) { - if(frame.destinationAddress() == _deviceObject.individualAddress()) + if (frame.destinationAddress() == _deviceObject.individualAddress()) return; - if(isRoutedPA(frame.destinationAddress())) + + if (isRoutedPA(frame.destinationAddress())) return; - if(isTunnelingPA(frame.destinationAddress())) + + if (isTunnelingPA(frame.destinationAddress())) return; } #endif - + // Send to KNX medium sendFrame(frame); } @@ -93,7 +95,7 @@ void DataLinkLayer::dataRequestFromTunnel(CemiFrame& frame) 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) + // 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); @@ -101,7 +103,7 @@ void DataLinkLayer::dataRequest(AckType ack, AddressType addrType, uint16_t dest 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) + // 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); } @@ -121,6 +123,7 @@ void DataLinkLayer::dataConReceived(CemiFrame& frame, bool success) 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()) @@ -128,13 +131,14 @@ void DataLinkLayer::dataConReceived(CemiFrame& frame, bool success) // Stop processing here and do NOT send it the local network layer return; } -#endif + +#endif 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); + if (systemBroadcast == SysBroadcast) + _networkLayerEntity.systemBroadcastConfirm(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); @@ -156,15 +160,19 @@ void DataLinkLayer::frameReceived(CemiFrame& frame) #ifdef USE_CEMI_SERVER // 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) + if ( _networkLayerEntity.getEntityIndex() == 1) _cemiServer->dataIndicationToTunnel(frame); + #else + if (frame.sourceAddress() != _cemiServer->clientAddress()) { _cemiServer->dataIndicationToTunnel(frame); } + #endif #endif @@ -180,7 +188,7 @@ void DataLinkLayer::frameReceived(CemiFrame& frame) { if (systemBroadcast == SysBroadcast) _networkLayerEntity.systemBroadcastIndication(ack, type, npdu, priority, source); - else + else _networkLayerEntity.broadcastIndication(ack, type, npdu, priority, source); } else @@ -189,7 +197,7 @@ void DataLinkLayer::frameReceived(CemiFrame& frame) } } -bool DataLinkLayer::sendTelegram(NPDU & npdu, AckType ack, uint16_t destinationAddr, AddressType addrType, uint16_t sourceAddr, FrameFormat format, Priority priority, SystemBroadcast systemBroadcast, bool doNotRepeat) +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 ?: "); @@ -199,7 +207,7 @@ bool DataLinkLayer::sendTelegram(NPDU & npdu, AckType ack, uint16_t destinationA frame.sourceAddress(sourceAddr); frame.addressType(addrType); frame.priority(priority); - frame.repetition(doNotRepeat?NoRepitiion:RepetitionAllowed); + frame.repetition(doNotRepeat ? NoRepitiion : RepetitionAllowed); frame.systemBroadcast(systemBroadcast); if (npdu.octetCount() <= 15) @@ -214,11 +222,11 @@ bool DataLinkLayer::sendTelegram(NPDU & npdu, AckType ack, uint16_t destinationA return false; } -// if (frame.npdu().octetCount() > 0) -// { -// _print("<- DLL "); -// frame.apdu().printPDU(); -// } + // if (frame.npdu().octetCount() > 0) + // { + // _print("<- DLL "); + // frame.apdu().printPDU(); + // } bool sendTheFrame = true; bool success = true; @@ -226,22 +234,23 @@ bool DataLinkLayer::sendTelegram(NPDU & npdu, AckType ack, uint16_t destinationA #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 + // 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 (_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)) + 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 + // 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) + if (sendTheFrame) success = sendFrame(frame); #ifdef USE_CEMI_SERVER @@ -250,14 +259,15 @@ bool DataLinkLayer::sendTelegram(NPDU & npdu, AckType ack, uint16_t destinationA // a pointer to const uint8_t data in either device object (serial) or // RF medium object (domain address) #ifdef USE_RF - tmpFrame.rfSerialOrDoA(frame.rfSerialOrDoA()); + tmpFrame.rfSerialOrDoA(frame.rfSerialOrDoA()); tmpFrame.rfInfo(frame.rfInfo()); tmpFrame.rfLfn(frame.rfLfn()); #endif tmpFrame.confirm(ConfirmNoError); - if(_networkLayerEntity.getEntityIndex() == 1) // only send to tunnel if we are the secondary (TP) interface + if (_networkLayerEntity.getEntityIndex() == 1) // only send to tunnel if we are the secondary (TP) interface _cemiServer->dataIndicationToTunnel(tmpFrame); + #endif return success; @@ -275,27 +285,35 @@ bool DataLinkLayer::isTunnelingPA(uint16_t pa) uint32_t len = 0; uint8_t* data = nullptr; _bau.propertyValueRead(OT_IP_PARAMETER, 0, PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, num, 1, &data, len); + //printHex("isTunnelingPA, PID_ADDITIONAL_INDIVIDUAL_ADDRESSES: ", *data, len); - if(len != KNX_TUNNELING * 2) + if (len != KNX_TUNNELING * 2) { println("Tunnel PAs unkwnown"); - if(data != nullptr) + + if (data != nullptr) delete[] data; + return false; } - for(uint8_t i = 0; i < KNX_TUNNELING; i++) + + for (uint8_t i = 0; i < KNX_TUNNELING; i++) { uint16_t tunnelpa; - popWord(tunnelpa, (data)+i*2); - if(pa == tunnelpa) + popWord(tunnelpa, (data) + i * 2); + + if (pa == tunnelpa) { - if(data != nullptr) + if (data != nullptr) delete[] data; + return true; - } + } } - if(data != nullptr) + + if (data != nullptr) delete[] data; + return false; } diff --git a/src/knx/data_link_layer.h b/src/knx/data_link_layer.h index b544fb0a..531f5a73 100644 --- a/src/knx/data_link_layer.h +++ b/src/knx/data_link_layer.h @@ -15,59 +15,59 @@ 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); + 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, BusAccessUnit& busAccessUnit); + public: + DataLinkLayer(DeviceObject& devObj, NetworkLayerEntity& netLayerEntity, + Platform& platform, BusAccessUnit& busAccessUnit); #ifdef USE_CEMI_SERVER - // from tunnel - void cemiServer(CemiServer& cemiServer); - void dataRequestFromTunnel(CemiFrame& frame); + // from tunnel + void cemiServer(CemiServer& cemiServer); + void dataRequestFromTunnel(CemiFrame& frame); #ifdef KNX_TUNNELING - virtual void dataRequestToTunnel(CemiFrame& frame); - virtual void dataConfirmationToTunnel(CemiFrame& frame); - virtual void dataIndicationToTunnel(CemiFrame& frame); - virtual bool isTunnelAddress(uint16_t addr); + virtual void dataRequestToTunnel(CemiFrame& frame); + virtual void dataConfirmationToTunnel(CemiFrame& frame); + virtual void dataIndicationToTunnel(CemiFrame& frame); + virtual bool isTunnelAddress(uint16_t addr); #endif #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; - BusAccessUnit& _bau; + 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; + BusAccessUnit& _bau; #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); + bool isTunnelingPA(uint16_t pa); + bool isRoutedPA(uint16_t pa); #endif }; diff --git a/src/knx/data_property.cpp b/src/knx/data_property.cpp index 8cd92372..f2279b40 100644 --- a/src/knx/data_property.cpp +++ b/src/knx/data_property.cpp @@ -19,7 +19,7 @@ uint8_t DataProperty::read(uint16_t start, uint8_t count, uint8_t* data) const start -= 1; // data is already big enough to hold the data - memcpy(data, _data + (start * ElementSize()), count * ElementSize()); + memcpy(data, _data + (start * ElementSize()), count * ElementSize()); return count; } @@ -35,11 +35,13 @@ uint8_t DataProperty::write(uint16_t start, uint8_t count, const uint8_t* data) { // reset _data _currentElements = 0; + if (_data) { delete[] _data; _data = nullptr; } + return 1; } else @@ -48,6 +50,7 @@ uint8_t DataProperty::write(uint16_t start, uint8_t count, const uint8_t* data) // we start counting with zero start -= 1; + if (start + count > _currentElements) { // reallocate memory for _data @@ -90,7 +93,7 @@ DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType typ Property::write(value); } -DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, +DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, uint32_t value) : Property(id, writeEnable, type, maxElements, access) { @@ -126,7 +129,7 @@ const uint8_t* DataProperty::restore(const uint8_t* buffer) { if (_data != nullptr) delete[] _data; - + _data = new uint8_t[elements * ElementSize()]; _currentElements = elements; } @@ -141,6 +144,7 @@ const uint8_t* DataProperty::restore(const uint8_t* buffer) uint8_t* DataProperty::save(uint8_t* buffer) { buffer = pushWord(_currentElements, buffer); + if (_currentElements > 0) buffer = pushByteArray(_data, _currentElements * ElementSize(), buffer); diff --git a/src/knx/data_property.h b/src/knx/data_property.h index 03f344f9..f1cfca69 100644 --- a/src/knx/data_property.h +++ b/src/knx/data_property.h @@ -4,22 +4,22 @@ 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); + 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; }; diff --git a/src/knx/datapoint_types.cpp b/src/knx/datapoint_types.cpp index ef8b5fbe..b757d0f8 100644 --- a/src/knx/datapoint_types.cpp +++ b/src/knx/datapoint_types.cpp @@ -54,7 +54,8 @@ int32_t dptFromFloat(uint16_t dptValue) if (dptValue >= 0x8000) value = dptValue | (-1L & ~2047); - else value = dptValue & 2047; + else + value = dptValue & 2047; for (; exp; --exp) value <<= 1; diff --git a/src/knx/device_object.cpp b/src/knx/device_object.cpp index 4c83211b..b6138f70 100644 --- a/src/knx/device_object.cpp +++ b/src/knx/device_object.cpp @@ -18,73 +18,73 @@ DeviceObject::DeviceObject() Property* properties[] = { 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 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 - { - if(start == 0) - { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); - return 1; - } - - pushByteArray(io->propertyData(PID_SERIAL_NUMBER), 2, data); + [](DeviceObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t + { + if (start == 0) + { + uint16_t currentNoOfElements = 1; + pushWord(currentNoOfElements, 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) - { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); - return 1; - } - - *data = io->_prgMode; + 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) + { + uint16_t currentNoOfElements = 1; + pushWord(currentNoOfElements, data); return 1; - }, - [](DeviceObject* io, uint16_t start, uint8_t count, const uint8_t* data) -> uint8_t - { - if(start == 0) - return 1; - - io->_prgMode = *data; + } + + *data = io->_prgMode; + return 1; + }, + [](DeviceObject * io, uint16_t start, uint8_t count, const uint8_t* data) -> uint8_t + { + if (start == 0) 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) - { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); - return 1; - } + [](DeviceObject * 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 = ((io->_ownAddress >> 8) & 0xff); + *data = ((io->_ownAddress >> 8) & 0xff); - return 1; - }), + 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) - { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); - return 1; - } - - *data = (io->_ownAddress & 0xff); + [](DeviceObject * 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 = (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), @@ -133,11 +133,12 @@ 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; + prop->write(data); } @@ -159,6 +160,7 @@ void DeviceObject::verifyMode(bool value) data |= VERIFY_MODE; else data &= ~VERIFY_MODE; + prop->write(data); } diff --git a/src/knx/device_object.h b/src/knx/device_object.h index 744965ad..8bfd2d2a 100644 --- a/src/knx/device_object.h +++ b/src/knx/device_object.h @@ -6,46 +6,46 @@ 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; + public: + // increase this version anytime DeviceObject-API changes + // the following value represents the serialized representation of DeviceObject. + const uint16_t apiVersion = 1; - uint16_t individualAddress(); - void individualAddress(uint16_t value); + DeviceObject(); + uint8_t* save(uint8_t* buffer) override; + const uint8_t* restore(const uint8_t* buffer) override; + uint16_t saveSize() override; - 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; + 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; #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 }; diff --git a/src/knx/dpt.h b/src/knx/dpt.h index b6add26c..6c2f0be6 100644 --- a/src/knx/dpt.h +++ b/src/knx/dpt.h @@ -286,7 +286,7 @@ #define DPT_TimePeriodHrs_Z Dpt(203, 7) #define DPT_UFlowRateLiter_per_h_Z Dpt(203, 11) #define DPT_UCountValue16_Z Dpt(203, 12) -#define DPT_UElCurrent_Z Dpt(203, 13) +#define DPT_UElCurrent_Z Dpt(203, 13) #define DPT_PowerKW_Z Dpt(203, 14) #define DPT_AtmPressureAbs_Z Dpt(203, 15) #define DPT_PercentU16_Z Dpt(203, 17) @@ -362,12 +362,12 @@ 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; + 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; }; diff --git a/src/knx/dptconvert.cpp b/src/knx/dptconvert.cpp index 9b3ff293..a73a036f 100644 --- a/src/knx/dptconvert.cpp +++ b/src/knx/dptconvert.cpp @@ -6,8 +6,8 @@ #define ASSERT_PAYLOAD(x) \ if (payload_length != (x)) \ - return false -#define ENSURE_PAYLOAD(x) + return false +#define ENSURE_PAYLOAD(x) int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) @@ -19,120 +19,159 @@ int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatyp { 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; } @@ -140,120 +179,159 @@ int KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_len { 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); + // 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); + // DPT 16.* - String if (datatype.mainGroup == 16 && datatype.subGroup <= 1 && !datatype.index) return valueToBusValueString(value, payload, payload_length, datatype); + // DPT 17.* - Scene Number if (datatype.mainGroup == 17 && datatype.subGroup == 1 && !datatype.index) return valueToBusValueScene(value, payload, payload_length, datatype); + // DPT 18.* - Scene Control if (datatype.mainGroup == 18 && datatype.subGroup == 1 && datatype.index <= 1) 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 valueToBusValueDateTime(value, payload, payload_length, datatype); + // DPT 26.* - Scene Info if (datatype.mainGroup == 26 && datatype.subGroup == 1 && datatype.index <= 1) - return valueToBusValueSceneInfo(value, payload, payload_length, datatype); + return valueToBusValueSceneInfo(value, payload, payload_length, datatype); + // DPT 27.001 - 32 Bit Field if (datatype.mainGroup == 27 && datatype.subGroup == 1 && !datatype.index) return valueToBusValueUnsigned32(value, payload, payload_length, datatype); + // DPT 28.* - Unicode String if (datatype.mainGroup == 28 && datatype.subGroup == 1 && !datatype.index) 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 valueToBusValueSigned64(value, payload, payload_length, datatype); + // DPT 219.* - Alarm Info if (datatype.mainGroup == 219 && datatype.subGroup == 1 && datatype.index <= 10) return valueToBusValueAlarmInfo(value, payload, payload_length, datatype); + // DPT 221.* - Serial Number if (datatype.mainGroup == 221 && datatype.subGroup == 1 && datatype.index <= 1) return valueToBusValueSerialNumber(value, payload, payload_length, datatype); + // DPT 217.* - Version if (datatype.mainGroup == 217 && datatype.subGroup == 1 && datatype.index <= 2) 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 valueToBusValueScaling(value, payload, payload_length, datatype); + // DPT 225.003 - Next Tariff if (datatype.mainGroup == 225 && datatype.subGroup == 3 && datatype.index <= 1) return valueToBusValueTariff(value, payload, payload_length, datatype); + // DPT 231.* - Locale if (datatype.mainGroup == 231 && datatype.subGroup == 1 && datatype.index <= 1) return valueToBusValueLocale(value, payload, payload_length, datatype); + // DPT 232.600 - RGB if (datatype.mainGroup == 232 && datatype.subGroup == 600 && !datatype.index) 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 valueToBusValueLocale(value, payload, payload_length, datatype); + // DPT 235.* - Active Energy if (datatype.mainGroup == 235 && datatype.subGroup == 1 && datatype.index <= 3) return valueToBusValueActiveEnergy(value, payload, payload_length, datatype); + // DPT 238.* - Scene Config if (datatype.mainGroup == 238 && datatype.subGroup == 1 && datatype.index <= 2) return valueToBusValueSceneConfig(value, payload, payload_length, datatype); + // DPT 239.* - Flagged Scaling if (datatype.mainGroup == 239 && datatype.subGroup == 1 && datatype.index <= 1) return valueToBusValueFlaggedScaling(value, payload, payload_length, datatype); + // DPT 251.600 - RGBW if (datatype.mainGroup == 251 && datatype.subGroup == 600 && datatype.index <= 1) return valueToBusValueRGBW(value, payload, payload_length, datatype); + return false; } @@ -267,11 +345,13 @@ int busValueToBinary(const uint8_t* payload, size_t payload_length, const Dpt& d int busValueToBinaryControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(1); + switch (datatype.index) { case 0: value = bitFromPayload(payload, 6); return true; + case 1: value = bitFromPayload(payload, 7); return true; @@ -283,11 +363,13 @@ int busValueToBinaryControl(const uint8_t* payload, size_t payload_length, const int busValueToStepControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(1); + switch (datatype.index) { case 0: value = bitFromPayload(payload, 4); return true; + case 1: { const unsigned char stepCode = unsigned8FromPayload(payload, 0) & 0x07; @@ -302,8 +384,10 @@ int busValueToCharacter(const uint8_t* payload, size_t payload_length, const Dpt { ASSERT_PAYLOAD(1); int8_t charValue = signed8FromPayload(payload, 0); + if (datatype.subGroup == 1 && (charValue & 0x80)) return false; + if (datatype.subGroup == 2) { value = (uint8_t)charValue; @@ -317,6 +401,7 @@ int busValueToCharacter(const uint8_t* payload, size_t payload_length, const Dpt int busValueToUnsigned8(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(1); + switch (datatype.subGroup) { case 1: @@ -330,8 +415,10 @@ int busValueToUnsigned8(const uint8_t* payload, size_t payload_length, const Dpt case 6: { uint8_t numValue = unsigned8FromPayload(payload, 0); + if (numValue == 0xFF) return false; + value = numValue; return true; } @@ -351,6 +438,7 @@ int busValueToSigned8(const uint8_t* payload, size_t payload_length, const Dpt& int busValueToStatusAndMode(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(1); + if (datatype.index < 5) { value = bitFromPayload(payload, datatype.index); @@ -361,6 +449,7 @@ int busValueToStatusAndMode(const uint8_t* payload, size_t payload_length, const value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x07); return true; } + return false; } @@ -383,11 +472,13 @@ int busValueToTimePeriod(const uint8_t* payload, size_t payload_length, const Dp int busValueToSigned16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(2); + if (datatype.subGroup == 10) { value = signed16FromPayload(payload, 0) / 100.0; return true; } + value = signed16FromPayload(payload, 0); return true; } @@ -404,6 +495,7 @@ int busValueToTimeDelta(const uint8_t* payload, size_t payload_length, const Dpt int busValueToFloat16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(2); + if (unsigned16FromPayload(payload, 0) == 0x7FFF) return false; @@ -414,11 +506,13 @@ int busValueToFloat16(const uint8_t* payload, size_t payload_length, const Dpt& int busValueToTime(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(3); + switch (datatype.index) { case 0: value = (uint8_t)((unsigned8FromPayload(payload, 0) >> 5) & 0x07); return true; + case 1: { unsigned char hours = unsigned8FromPayload(payload, 0) & 0x1F; @@ -428,6 +522,7 @@ int busValueToTime(const uint8_t* payload, size_t payload_length, const Dpt& dat if (hours > 23 || minutes > 59 || seconds > 59) return false; + struct tm tmp = {0}; tmp.tm_hour = hours; tmp.tm_wday = weekDay; @@ -491,27 +586,34 @@ int busValueToFloat32(const uint8_t* payload, size_t payload_length, const Dpt& int busValueToAccess(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(4); + switch (datatype.index) { case 0: { int32_t digits = 0; + for (int n = 0, factor = 100000; n < 6; ++n, factor /= 10) { unsigned char digit = bcdFromPayload(payload, n); + if (digit > 9) return false; + digits += digit * factor; } + value = digits; 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; @@ -523,12 +625,15 @@ int busValueToAccess(const uint8_t* payload, size_t payload_length, const Dpt& d 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) { auto value = signed8FromPayload(payload, n); + if (!datatype.subGroup && (value & 0x80)) return false; } + value = (const char*) payload; return true; } @@ -543,6 +648,7 @@ int busValueToScene(const uint8_t* payload, size_t payload_length, const Dpt& da int busValueToSceneControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(1); + switch (datatype.index) { case 0: @@ -550,6 +656,7 @@ int busValueToSceneControl(const uint8_t* payload, size_t payload_length, const value = bitFromPayload(payload, 0); return true; } + case 1: { value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x3F); @@ -563,6 +670,7 @@ int busValueToSceneControl(const uint8_t* payload, size_t payload_length, const int busValueToSceneInfo(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(1); + switch (datatype.index) { case 0: @@ -570,6 +678,7 @@ int busValueToSceneInfo(const uint8_t* payload, size_t payload_length, const Dpt value = bitFromPayload(payload, 1); return true; } + case 1: { value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x3F); @@ -583,6 +692,7 @@ int busValueToSceneInfo(const uint8_t* payload, size_t payload_length, const Dpt int busValueToSceneConfig(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(1); + switch (datatype.index) { case 0: @@ -590,6 +700,7 @@ int busValueToSceneConfig(const uint8_t* payload, size_t payload_length, const D value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x3F); return true; } + case 1: case 2: { @@ -604,6 +715,7 @@ int busValueToSceneConfig(const uint8_t* payload, size_t payload_length, const D int busValueToDateTime(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(8); + if (datatype.index == 3) { value = bitFromPayload(payload, 48); @@ -628,6 +740,7 @@ int busValueToDateTime(const uint8_t* payload, size_t payload_length, const Dpt& if ((month < 1 || month > 12 || day < 1)) return false; + if ((hours > 24 || minutes > 59 || seconds > 59)) return false; @@ -641,6 +754,7 @@ int busValueToDateTime(const uint8_t* payload, size_t payload_length, const Dpt& value = tmp; return true; } + case 1: { if (bitFromPayload(payload, 53)) @@ -649,6 +763,7 @@ int busValueToDateTime(const uint8_t* payload, size_t payload_length, const Dpt& value = (uint8_t)((unsigned8FromPayload(payload, 3) >> 5) & 0x07); return true; } + case 2: { if (bitFromPayload(payload, 50)) @@ -657,11 +772,13 @@ int busValueToDateTime(const uint8_t* payload, size_t payload_length, const Dpt& value = bitFromPayload(payload, 49); return true; } + case 9: { value = bitFromPayload(payload, 55); return true; } + case 10: { value = bitFromPayload(payload, 56); @@ -689,62 +806,75 @@ int busValueToSigned64(const uint8_t* payload, size_t payload_length, const Dpt& int busValueToAlarmInfo(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(6); + switch (datatype.index) { case 1: { unsigned char prio = unsigned8FromPayload(payload, 1); + if (prio > 3) return false; + value = prio; 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; } int busValueToSerialNumber(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(6); + switch (datatype.index) { case 0: value = unsigned16FromPayload(payload, 0); return true; + case 1: value = unsigned32FromPayload(payload, 2); return true; } + return false; } int busValueToVersion(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(2); + switch (datatype.index) { case 0: value = (uint8_t)((unsigned8FromPayload(payload, 0) >> 3) & 0x1F); return true; + case 1: value = (uint16_t)((unsigned16FromPayload(payload, 0) >> 6) & 0x1F); return true; + case 2: value = (uint8_t)(unsigned8FromPayload(payload, 1) & 0x3F); return true; @@ -756,11 +886,13 @@ int busValueToVersion(const uint8_t* payload, size_t payload_length, const Dpt& int busValueToScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(3); + switch (datatype.index) { case 0: value = unsigned16FromPayload(payload, 0); return true; + case 1: value = (uint8_t)(unsigned8FromPayload(payload, 2) * 100.0 / 255.0); return true; @@ -772,16 +904,20 @@ int busValueToScaling(const uint8_t* payload, size_t payload_length, const Dpt& int busValueToTariff(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(3); + switch (datatype.index) { case 0: value = unsigned16FromPayload(payload, 0); return true; + case 1: { uint8_t tariff = unsigned8FromPayload(payload, 2); + if (tariff > 254) return false; + value = tariff; return true; } @@ -793,6 +929,7 @@ int busValueToTariff(const uint8_t* payload, size_t payload_length, const Dpt& d int busValueToLocale(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(datatype.mainGroup == 231 ? 4 : 2); + if (!datatype.index || (datatype.mainGroup == 231 && datatype.index == 1)) { char code[2]; @@ -801,6 +938,7 @@ int busValueToLocale(const uint8_t* payload, size_t payload_length, const Dpt& d value = code; return true; } + return false; } @@ -815,46 +953,57 @@ int busValueToRGB(const uint8_t* payload, size_t payload_length, const Dpt& data int busValueToRGBW(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(6); - switch (datatype.index) { + + switch (datatype.index) + { case 0: // The RGBW value - { - uint32_t rgbw = unsigned32FromPayload(payload, 0); - value = rgbw; - } - return true; + { + uint32_t rgbw = unsigned32FromPayload(payload, 0); + value = rgbw; + } + + return true; + case 1: // The mask bits only - value = unsigned8FromPayload(payload,5); + value = unsigned8FromPayload(payload, 5); return true; } + return false; } int busValueToFlaggedScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(2); + switch (datatype.index) { case 0: value = (uint8_t)(unsigned8FromPayload(payload, 0) * 100.0 / 255.0); return true; + case 1: value = bitFromPayload(payload, 15); return true; } + return false; } int busValueToActiveEnergy(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) { ASSERT_PAYLOAD(6); + switch (datatype.index) { case 0: value = signed32FromPayload(payload, 0); return true; + case 1: value = unsigned8FromPayload(payload, 4); return true; + case 2: case 3: value = bitFromPayload(payload, datatype.index + 44); @@ -879,9 +1028,11 @@ int valueToBusValueBinaryControl(const KNXValue& value, uint8_t* payload, size_t case 0: bitToPayload(payload, payload_length, 6, value); break; + case 1: bitToPayload(payload, payload_length, 7, value); break; + default: return false; } @@ -896,13 +1047,16 @@ int valueToBusValueStepControl(const KNXValue& value, uint8_t* payload, size_t p case 0: bitToPayload(payload, payload_length, 4, value); break; + case 1: { if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(7)) return false; + unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0x07); } break; + default: return false; } @@ -914,6 +1068,7 @@ int valueToBusValueCharacter(const KNXValue& value, uint8_t* payload, size_t pay { 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; } @@ -929,27 +1084,34 @@ int valueToBusValueUnsigned8(const KNXValue& value, uint8_t* payload, size_t pay { if ((double)value > 100.0) return false; + unsigned8ToPayload(payload, payload_length, 0, round((double)value * 255.0 / 100.0), 0xFF); break; } + case 3: { if ((double)value > 360.0) return false; + unsigned8ToPayload(payload, payload_length, 0, round((double)value * 255.0 / 360.0), 0xFF); break; } + case 6: { if ((int64_t)value > INT64_C(254)) 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); } } @@ -974,6 +1136,7 @@ int valueToBusValueStatusAndMode(const KNXValue& value, uint8_t* payload, size_t { if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(7)) return false; + unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0x07); } else @@ -1012,6 +1175,7 @@ int valueToBusValueSigned16(const KNXValue& value, uint8_t* payload, size_t payl { if ((double)value < -327.68 || (double)value > 327.67) return false; + signed16ToPayload(payload, payload_length, 0, (int16_t)((double)value * 100.0), 0xFFFF); } else @@ -1049,7 +1213,9 @@ int valueToBusValueFloat16(const KNXValue& value, uint8_t* payload, size_t paylo case 1: if (numValue < -273.0) return false; + break; + case 2: case 3: case 10: @@ -1062,7 +1228,9 @@ int valueToBusValueFloat16(const KNXValue& value, uint8_t* payload, size_t paylo case 25: if (numValue < -670760.0) return false; + break; + case 4: case 5: case 6: @@ -1071,10 +1239,13 @@ int valueToBusValueFloat16(const KNXValue& value, uint8_t* payload, size_t paylo case 28: if (numValue < 0.0) return false; + break; + case 27: if (numValue < -459.6) return false; + break; } @@ -1090,10 +1261,12 @@ int valueToBusValueTime(const KNXValue& value, uint8_t* payload, size_t payload_ { if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(7)) return false; + ENSURE_PAYLOAD(3); unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value << 5, 0xE0); break; } + case 1: { struct tm tmp = value; @@ -1102,6 +1275,7 @@ int valueToBusValueTime(const KNXValue& value, uint8_t* payload, size_t payload_ unsigned8ToPayload(payload, payload_length, 2, tmp.tm_sec, 0x3F); break; } + default: return false; } @@ -1112,6 +1286,7 @@ int valueToBusValueTime(const KNXValue& value, uint8_t* payload, size_t payload_ int valueToBusValueDate(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { struct tm tmp = value; + if (tmp.tm_year < 1990 || tmp.tm_year > 2089) return false; @@ -1151,6 +1326,7 @@ int valueToBusValueLongTimePeriod(const KNXValue& value, uint8_t* payload, size_ int valueToBusValueFloat32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { double numValue = value; + if (numValue < (-8388608.0 * pow(2, 255)) || numValue > (8388607.0 * pow(2, 255))) return false; @@ -1166,24 +1342,31 @@ int valueToBusValueAccess(const KNXValue& value, uint8_t* payload, size_t payloa { if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(999999)) return false; + ENSURE_PAYLOAD(4); + for (int n = 0, factor = 100000; n < 6; ++n, factor /= 10) bcdToPayload(payload, payload_length, n, ((uint64_t)value / factor) % 10); + break; } + case 1: case 2: case 3: case 4: bitToPayload(payload, payload_length, 23 + datatype.index, value); break; + case 5: { if ((uint64_t)value > INT64_C(15)) return false; + bcdToPayload(payload, payload_length, 7, (uint64_t)value); break; } + default: return false; } @@ -1195,10 +1378,15 @@ int valueToBusValueString(const KNXValue& value, uint8_t* payload, size_t payloa { const char* strValue = value; uint8_t val = strValue[0]; - for (int n = 0; n < 14; n++) { - if (val) val = strValue[n]; //string terminator 0x00 will stop further assignments and init the remainig payload with zero + + for (int n = 0; n < 14; n++) + { + if (val) + val = strValue[n]; //string terminator 0x00 will stop further assignments and init the remainig payload with zero + unsigned8ToPayload(payload, payload_length, n, val, 0xff); } + return true; } @@ -1218,13 +1406,16 @@ int valueToBusValueSceneControl(const KNXValue& value, uint8_t* payload, size_t case 0: bitToPayload(payload, payload_length, 0, value); break; + case 1: { 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; } + default: return false; } @@ -1239,13 +1430,16 @@ int valueToBusValueSceneInfo(const KNXValue& value, uint8_t* payload, size_t pay case 0: bitToPayload(payload, payload_length, 1, value); break; + case 1: { 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; } + default: return false; } @@ -1261,13 +1455,16 @@ int valueToBusValueSceneConfig(const KNXValue& value, uint8_t* payload, size_t p { 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; } + case 1: case 2: bitToPayload(payload, payload_length, 2 - datatype.index, value); break; + default: return false; } @@ -1301,9 +1498,11 @@ int valueToBusValueDateTime(const KNXValue& value, uint8_t* payload, size_t payl unsigned8ToPayload(payload, payload_length, 5, tmp.tm_sec, 0x3F); break; } + case 1: { ENSURE_PAYLOAD(8); + if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(7)) bitToPayload(payload, payload_length, 53, true); else @@ -1311,8 +1510,10 @@ int valueToBusValueDateTime(const KNXValue& value, uint8_t* payload, size_t payl bitToPayload(payload, payload_length, 53, false); unsigned8ToPayload(payload, payload_length, 3, (int64_t)value << 5, 0xE0); } + break; } + case 2: { ENSURE_PAYLOAD(8); @@ -1320,23 +1521,27 @@ int valueToBusValueDateTime(const KNXValue& value, uint8_t* payload, size_t payl bitToPayload(payload, payload_length, 50, false); break; } + case 3: { ENSURE_PAYLOAD(8); bitToPayload(payload, payload_length, 48, value); break; } + case 9: { ENSURE_PAYLOAD(8); bitToPayload(payload, payload_length, 55, value); break; } + case 10: { bitToPayload(payload, payload_length, 56, value); break; } + default: return false; } @@ -1364,20 +1569,24 @@ int valueToBusValueAlarmInfo(const KNXValue& value, uint8_t* payload, size_t pay { if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(3)) return false; + ENSURE_PAYLOAD(6); unsigned8ToPayload(payload, payload_length, 1, (int64_t)value, 0xFF); break; } + case 0: case 2: case 3: { if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(255)) return false; + ENSURE_PAYLOAD(6); unsigned8ToPayload(payload, payload_length, datatype.index, (int64_t)value, 0xFF); break; } + case 4: case 5: case 6: @@ -1387,6 +1596,7 @@ int valueToBusValueAlarmInfo(const KNXValue& value, uint8_t* payload, size_t pay bitToPayload(payload, payload_length, 43 - datatype.index, value); break; } + case 8: case 9: case 10: @@ -1395,6 +1605,7 @@ int valueToBusValueAlarmInfo(const KNXValue& value, uint8_t* payload, size_t pay bitToPayload(payload, payload_length, 55 - datatype.index, value); break; } + default: return false; } @@ -1410,18 +1621,22 @@ int valueToBusValueSerialNumber(const KNXValue& value, uint8_t* payload, size_t { if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(65535)) return false; + ENSURE_PAYLOAD(6); unsigned16ToPayload(payload, payload_length, 0, (int64_t)value, 0xFFFF); break; } + case 1: { if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(4294967295)) return false; + ENSURE_PAYLOAD(6); unsigned32ToPayload(payload, payload_length, 2, (int64_t)value, 0xFFFF); break; } + default: return false; } @@ -1437,24 +1652,30 @@ int valueToBusValueVersion(const KNXValue& value, uint8_t* payload, size_t paylo { if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(31)) return false; + ENSURE_PAYLOAD(2); unsigned8ToPayload(payload, payload_length, 0, (int64_t)value << 3, 0xF8); break; } + case 1: { if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(31)) return false; + unsigned16ToPayload(payload, payload_length, 0, (int64_t)value << 6, 0x07C0); 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; } @@ -1477,10 +1698,12 @@ int valueToBusValueScaling(const KNXValue& value, uint8_t* payload, size_t paylo 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; } @@ -1504,10 +1727,12 @@ int valueToBusValueTariff(const KNXValue& value, uint8_t* payload, size_t payloa unsigned16ToPayload(payload, payload_length, 0, duration, 0xFFFF); return true; } + case 1: { if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(254)) return false; + unsigned8ToPayload(payload, payload_length, 2, (int64_t)value, 0xff); break; } @@ -1519,6 +1744,7 @@ int valueToBusValueTariff(const KNXValue& value, uint8_t* payload, size_t payloa int valueToBusValueLocale(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { int strl = strlen(value); + if (strl != 2) return false; @@ -1547,18 +1773,20 @@ int valueToBusValueRGB(const KNXValue& value, uint8_t* payload, size_t payload_l int valueToBusValueRGBW(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) { - switch(datatype.index) + switch (datatype.index) { case 0: // RGBW - { - uint32_t rgbw = (uint32_t)value; - unsigned32ToPayload(payload, payload_length, 0, rgbw, 0xffffffff); // RGBW - } - break; + { + 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; } + return true; } @@ -1570,13 +1798,16 @@ int valueToBusValueFlaggedScaling(const KNXValue& value, uint8_t* payload, size_ { if ((double)value < 0.0 || (double)value > 100.0) return false; + ENSURE_PAYLOAD(2); unsigned8ToPayload(payload, payload_length, 0, round((double)value * 255.0 / 100.0), 0xff); break; } + case 1: bitToPayload(payload, payload_length, 15, value); break; + default: return false; } @@ -1592,22 +1823,27 @@ int valueToBusValueActiveEnergy(const KNXValue& value, uint8_t* payload, size_t { 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); break; } + case 1: { if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(254)) return false; + ENSURE_PAYLOAD(6); unsigned8ToPayload(payload, payload_length, 4, (int64_t)value, 0xff); break; } + case 2: case 3: bitToPayload(payload, payload_length, datatype.index + 44, value); break; + default: return false; } @@ -1650,18 +1886,19 @@ int32_t signed32FromPayload(const uint8_t* payload, int 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); + 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; + if (mantissa & 0x8000) return ((~mantissa & 0x07FF) + 1.0) * -0.01 * (1 << ((payload[index] >> 3) & 0x0F)); @@ -1669,14 +1906,22 @@ double float16FromPayload(const uint8_t* payload, int index) } float float32FromPayload(const uint8_t* payload, int index) { - union { float f; uint32_t i; } area; + union + { + float f; + uint32_t i; + } area; area.i = unsigned32FromPayload(payload, index); - return area.f; + return area.f; } double float64FromPayload(const uint8_t* payload, int index) { - union { double f; uint64_t i; } area; - area.i = unsigned64FromPayload(payload, 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) @@ -1694,6 +1939,7 @@ uint8_t bcdFromPayload(const uint8_t* payload, int index) { if (index % 2) return (uint8_t)(payload[index / 2] & 0x0F); + return (uint8_t)((payload[index / 2] >> 4) & 0x0F); } @@ -1744,6 +1990,7 @@ void signed32ToPayload(uint8_t* payload, size_t payload_length, int index, int32 void float16ToPayload(uint8_t* payload, size_t payload_length, int index, double value, uint16_t mask) { bool wasNegative = false; + if (value < 0) { wasNegative = true; @@ -1752,11 +1999,12 @@ void float16ToPayload(uint8_t* payload, size_t payload_length, int index, double value *= 100.0; unsigned short exponent = 0; - - if(value > 2048) + + 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) { @@ -1768,13 +2016,17 @@ void float16ToPayload(uint8_t* payload, size_t payload_length, int index, double mantissa *= -1; // println(mantissa); - + 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; + union + { + float f; + uint32_t i; + } num; num.f = value; unsigned32ToPayload(payload, payload_length, index, num.i, mask); } @@ -1793,6 +2045,7 @@ void signed64ToPayload(uint8_t* payload, size_t payload_length, int index, int64 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 diff --git a/src/knx/function_property.h b/src/knx/function_property.h index 361d52be..ceb6cf27 100644 --- a/src/knx/function_property.h +++ b/src/knx/function_property.h @@ -6,46 +6,48 @@ 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 - { - 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 ) + 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); - } - void state(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) override - { - if (length == 0 || _stateCallback == nullptr ) + uint8_t write(uint16_t start, uint8_t count, const uint8_t* data) override { - resultLength = 0; - return; + return 0; + } + + void command(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) override + { + if (length == 0 || _commandCallback == nullptr ) + { + resultLength = 0; + return; + } + + _commandCallback(_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); } - _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; }; diff --git a/src/knx/group_object.cpp b/src/knx/group_object.cpp index 7b172d5c..58f21a14 100644 --- a/src/knx/group_object.cpp +++ b/src/knx/group_object.cpp @@ -5,7 +5,7 @@ #include "group_object_table_object.h" #ifdef SMALL_GROUPOBJECT -GroupObjectUpdatedHandler GroupObject::_updateHandlerStatic = 0; + GroupObjectUpdatedHandler GroupObject::_updateHandlerStatic = 0; #endif GroupObjectTableObject* GroupObject::_table = 0; @@ -100,9 +100,10 @@ uint16_t GroupObject::asap() size_t GroupObject::goSize() { size_t size = sizeInTelegram(); + if (size == 0) return 1; - + return size; } @@ -111,35 +112,49 @@ size_t GroupObject::asapValueSize(uint8_t code) const { if (code < 7) return 0; + if (code < 8) return 1; + if (code < 11 || (code > 20 && code < 255)) return code - 6; + switch (code) { case 11: return 6; + case 12: return 8; + case 13: return 10; + case 14: return 14; + case 15: return 5; + case 16: return 7; + case 17: return 9; + case 18: return 11; + case 19: return 12; + case 20: return 13; + case 255: return 252; } + return -1; } @@ -152,6 +167,7 @@ ComFlag GroupObject::commFlag() void GroupObject::commFlag(ComFlag value) { _commFlagEx.commFlag = value; + if (value == WriteRequest || value == Updated || value == Ok) _commFlagEx.uninitialized = false; } @@ -186,10 +202,13 @@ size_t GroupObject::sizeInMemory() const { uint8_t code = lowByte(ntohs(_table->_tableData[_asap])); size_t result = asapValueSize(code); + if (code == 0) return 1; + if (code == 14) return 14 + 1; + return result; } @@ -304,6 +323,7 @@ bool GroupObject::valueNoSendCompare(const KNXValue& value, const Dpt& type) // check for change in converted value / update value on change only const bool dataChanged = memcmp(_data, newData, _dataLength); + if (dataChanged) memcpy(_data, newData, _dataLength); @@ -315,8 +335,9 @@ bool GroupObject::valueCompare(const KNXValue& value, const Dpt& type) { if (valueNoSendCompare(value, type)) { - objectWritten(); - return true; + objectWritten(); + return true; } + return false; } \ No newline at end of file diff --git a/src/knx/group_object.h b/src/knx/group_object.h index 244fab67..d488bb1d 100644 --- a/src/knx/group_object.h +++ b/src/knx/group_object.h @@ -31,18 +31,18 @@ struct ComFlagEx 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 -# else -# define HAS_FUNCTIONAL 0 -# endif + #if defined(__linux__) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_STM32) || defined (ARDUINO_ARCH_SAMD) || defined (ARDUINO_ARCH_RP2040) + #define HAS_FUNCTIONAL 1 + #else + #define HAS_FUNCTIONAL 0 + #endif #endif #if HAS_FUNCTIONAL -#include -typedef std::function GroupObjectUpdatedHandler; + #include + typedef std::function GroupObjectUpdatedHandler; #else -typedef void (*GroupObjectUpdatedHandler)(GroupObject& go); + typedef void (*GroupObjectUpdatedHandler)(GroupObject& go); #endif /** @@ -50,239 +50,239 @@ typedef void (*GroupObjectUpdatedHandler)(GroupObject& go); */ class GroupObject { - friend class GroupObjectTableObject; + 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); - - /** - * 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); + /** + * 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); - /** - * 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 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 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. + */ + 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. - * - * @returns true if the value of the group object was changed successfully. - */ - bool tryValue(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); #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; - ComFlagEx _commFlagEx; - uint8_t* _data = 0; - uint8_t _dataLength = 0; + size_t asapValueSize(uint8_t code) const; + size_t goSize(); + uint16_t _asap = 0; + ComFlagEx _commFlagEx; + uint8_t* _data = 0; + uint8_t _dataLength = 0; #ifndef SMALL_GROUPOBJECT - GroupObjectUpdatedHandler _updateHandler; - Dpt _datapointType; + GroupObjectUpdatedHandler _updateHandler; + Dpt _datapointType; #endif }; diff --git a/src/knx/group_object_table_object.cpp b/src/knx/group_object_table_object.cpp index 8d931ced..13d81239 100644 --- a/src/knx/group_object_table_object.cpp +++ b/src/knx/group_object_table_object.cpp @@ -67,7 +67,7 @@ GroupObject& GroupObjectTableObject::nextUpdatedObject(bool& valid) return get(1); } -void GroupObjectTableObject::groupObjects(GroupObject * objs, uint16_t size) +void GroupObjectTableObject::groupObjects(GroupObject* objs, uint16_t size) { freeGroupObjects(); _groupObjects = objs; @@ -78,6 +78,7 @@ void GroupObjectTableObject::groupObjects(GroupObject * objs, uint16_t size) void GroupObjectTableObject::beforeStateChange(LoadState& newState) { TableObject::beforeStateChange(newState); + if (newState != LS_LOADED) return; @@ -94,11 +95,11 @@ bool GroupObjectTableObject::initGroupObjects() { if (!_tableData) return false; - + freeGroupObjects(); uint16_t goCount = ntohs(_tableData[0]); - + _groupObjects = new GroupObject[goCount]; _groupObjectCount = goCount; @@ -107,12 +108,12 @@ bool GroupObjectTableObject::initGroupObjects() 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); - + if (go.valueReadOnInit()) go.requestObjectRead(); } @@ -124,7 +125,7 @@ void GroupObjectTableObject::freeGroupObjects() { if (_groupObjects) delete[] _groupObjects; - + _groupObjectCount = 0; _groupObjects = 0; } diff --git a/src/knx/group_object_table_object.h b/src/knx/group_object_table_object.h index 82393479..fc5d1314 100644 --- a/src/knx/group_object_table_object.h +++ b/src/knx/group_object_table_object.h @@ -5,25 +5,25 @@ class GroupObjectTableObject : public TableObject { - friend class GroupObject; + 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; + 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.cpp b/src/knx/interface_object.cpp index 19c58b66..93d50779 100644 --- a/src/knx/interface_object.cpp +++ b/src/knx/interface_object.cpp @@ -14,6 +14,7 @@ void InterfaceObject::readPropertyDescription(uint8_t& propertyId, uint8_t& prop uint8_t count = _propertyCount; numberOfElements = 0; + if (_properties == nullptr || count == 0) return; @@ -26,6 +27,7 @@ void InterfaceObject::readPropertyDescription(uint8_t& propertyId, uint8_t& prop for (uint8_t i = 0; i < count; i++) { Property* p = _properties[i]; + if (p->Id() != propertyId) continue; @@ -60,23 +62,25 @@ void InterfaceObject::masterReset(EraseCode eraseCode, uint8_t channel) // However, for the time being we provide an empty default implementation } -void InterfaceObject::readPropertyLength(PropertyID id, uint16_t &length) +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) + if (count == 0) { length = 0; return; } + length = ntohs(propval); } void InterfaceObject::readProperty(PropertyID id, uint16_t start, uint8_t& count, uint8_t* data) { Property* prop = property(id); + if (prop == nullptr) { count = 0; @@ -89,6 +93,7 @@ void InterfaceObject::readProperty(PropertyID id, uint16_t start, uint8_t& count void InterfaceObject::writeProperty(PropertyID id, uint16_t start, uint8_t* data, uint8_t& count) { Property* prop = property(id); + if (prop == nullptr) { count = 0; @@ -101,6 +106,7 @@ void InterfaceObject::writeProperty(PropertyID id, uint16_t start, uint8_t* data uint8_t InterfaceObject::propertySize(PropertyID id) { Property* prop = property(id); + if (prop == nullptr) { return 0; @@ -112,6 +118,7 @@ uint8_t InterfaceObject::propertySize(PropertyID 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; @@ -124,6 +131,7 @@ void InterfaceObject::command(PropertyID id, uint8_t* data, uint8_t length, uint 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; @@ -156,11 +164,13 @@ uint8_t* InterfaceObject::save(uint8_t* buffer) for (int i = 0; i < _propertyCount; i++) { Property* prop = _properties[i]; + if (!prop->WriteEnable()) continue; - + buffer = prop->save(buffer); } + return buffer; } @@ -170,11 +180,13 @@ const uint8_t* InterfaceObject::restore(const uint8_t* buffer) for (int i = 0; i < _propertyCount; i++) { Property* prop = _properties[i]; + if (!prop->WriteEnable()) continue; buffer = prop->restore(buffer); } + return buffer; } @@ -186,11 +198,13 @@ uint16_t InterfaceObject::saveSize() for (int i = 0; i < _propertyCount; i++) { Property* prop = _properties[i]; + if (!prop->WriteEnable()) continue; size += prop->saveSize(); } + return size; } @@ -201,7 +215,7 @@ const Property* InterfaceObject::property(PropertyID id) const if (_properties[i]->Id() == id) return _properties[i]; - return nullptr; + return nullptr; } diff --git a/src/knx/interface_object.h b/src/knx/interface_object.h index 0cfa5b1a..fe9a3711 100644 --- a/src/knx/interface_object.h +++ b/src/knx/interface_object.h @@ -66,145 +66,145 @@ enum ObjectType */ 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; + 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; }; diff --git a/src/knx/ip_data_link_layer.cpp b/src/knx/ip_data_link_layer.cpp index fd07359e..24039ba8 100644 --- a/src/knx/ip_data_link_layer.cpp +++ b/src/knx/ip_data_link_layer.cpp @@ -13,17 +13,17 @@ #include "knx_ip_search_response_extended.h" #include "knx_facade.h" #ifdef KNX_TUNNELING -#include "knx_ip_connect_request.h" -#include "knx_ip_connect_response.h" -#include "knx_ip_state_request.h" -#include "knx_ip_state_response.h" -#include "knx_ip_disconnect_request.h" -#include "knx_ip_disconnect_response.h" -#include "knx_ip_tunneling_request.h" -#include "knx_ip_tunneling_ack.h" -#include "knx_ip_description_request.h" -#include "knx_ip_description_response.h" -#include "knx_ip_config_request.h" + #include "knx_ip_connect_request.h" + #include "knx_ip_connect_response.h" + #include "knx_ip_state_request.h" + #include "knx_ip_state_response.h" + #include "knx_ip_disconnect_request.h" + #include "knx_ip_disconnect_response.h" + #include "knx_ip_tunneling_request.h" + #include "knx_ip_tunneling_ack.h" + #include "knx_ip_description_request.h" + #include "knx_ip_description_response.h" + #include "knx_ip_config_request.h" #endif #include @@ -35,20 +35,24 @@ #define MIN_LEN_CEMI 10 IpDataLinkLayer::IpDataLinkLayer(DeviceObject& devObj, IpParameterObject& ipParam, - NetworkLayerEntity &netLayerEntity, Platform& platform, BusAccessUnit& busAccessUnit, DataLinkLayerCallbacks* dllcb) : DataLinkLayer(devObj, netLayerEntity, platform, busAccessUnit), _ipParameters(ipParam), _dllcb(dllcb) + NetworkLayerEntity& netLayerEntity, Platform& platform, BusAccessUnit& busAccessUnit, DataLinkLayerCallbacks* dllcb) : DataLinkLayer(devObj, netLayerEntity, platform, busAccessUnit), _ipParameters(ipParam), _dllcb(dllcb) { } bool IpDataLinkLayer::sendFrame(CemiFrame& frame) { KnxIpRoutingIndication packet(frame); + // only send 50 packet per second: see KNX 3.2.6 p.6 - if(isSendLimitReached()) + if (isSendLimitReached()) return false; + bool success = sendBytes(packet.data(), packet.totalLength()); #ifdef KNX_ACTIVITYCALLBACK - if(_dllcb) + + if (_dllcb) _dllcb->activity((_netIndex << KNX_ACTIVITYCALLBACK_NET) | (KNX_ACTIVITYCALLBACK_DIR_SEND << KNX_ACTIVITYCALLBACK_DIR)); + #endif dataConReceived(frame, success); return success; @@ -57,33 +61,35 @@ bool IpDataLinkLayer::sendFrame(CemiFrame& frame) #ifdef KNX_TUNNELING void IpDataLinkLayer::dataRequestToTunnel(CemiFrame& frame) { - if(frame.addressType() == AddressType::GroupAddress) + if (frame.addressType() == AddressType::GroupAddress) { - for(int i = 0; i < KNX_TUNNELING; i++) - if(tunnels[i].ChannelId != 0 && tunnels[i].IndividualAddress == frame.sourceAddress()) + 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 + + //TODO check if source is from tunnel return; } - KnxIpTunnelConnection *tun = nullptr; - for(int i = 0; i < KNX_TUNNELING; i++) + KnxIpTunnelConnection* tun = nullptr; + + for (int i = 0; i < KNX_TUNNELING; i++) { - if(tunnels[i].IndividualAddress == frame.sourceAddress()) + if (tunnels[i].IndividualAddress == frame.sourceAddress()) continue; - if(tunnels[i].IndividualAddress == frame.destinationAddress()) + if (tunnels[i].IndividualAddress == frame.destinationAddress()) { tun = &tunnels[i]; break; } } - if(tun == nullptr) + if (tun == nullptr) { - for(int i = 0; i < KNX_TUNNELING; i++) + for (int i = 0; i < KNX_TUNNELING; i++) { - if(tunnels[i].IsConfig) + if (tunnels[i].IsConfig) { #ifdef KNX_LOG_TUNNELING println("Found config Channel"); @@ -94,7 +100,7 @@ void IpDataLinkLayer::dataRequestToTunnel(CemiFrame& frame) } } - if(tun == nullptr) + if (tun == nullptr) { #ifdef KNX_LOG_TUNNELING print("Found no Tunnel for IA: "); @@ -108,33 +114,35 @@ void IpDataLinkLayer::dataRequestToTunnel(CemiFrame& frame) void IpDataLinkLayer::dataConfirmationToTunnel(CemiFrame& frame) { - if(frame.addressType() == AddressType::GroupAddress) + if (frame.addressType() == AddressType::GroupAddress) { - for(int i = 0; i < KNX_TUNNELING; i++) - if(tunnels[i].ChannelId != 0 && tunnels[i].IndividualAddress == frame.sourceAddress()) + 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 + + //TODO check if source is from tunnel return; } - KnxIpTunnelConnection *tun = nullptr; - for(int i = 0; i < KNX_TUNNELING; i++) + KnxIpTunnelConnection* tun = nullptr; + + for (int i = 0; i < KNX_TUNNELING; i++) { - if(tunnels[i].IndividualAddress == frame.destinationAddress()) + if (tunnels[i].IndividualAddress == frame.destinationAddress()) continue; - - if(tunnels[i].IndividualAddress == frame.sourceAddress()) + + if (tunnels[i].IndividualAddress == frame.sourceAddress()) { tun = &tunnels[i]; break; } } - if(tun == nullptr) + if (tun == nullptr) { - for(int i = 0; i < KNX_TUNNELING; i++) + for (int i = 0; i < KNX_TUNNELING; i++) { - if(tunnels[i].IsConfig) + if (tunnels[i].IsConfig) { #ifdef KNX_LOG_TUNNELING println("Found config Channel"); @@ -145,7 +153,7 @@ void IpDataLinkLayer::dataConfirmationToTunnel(CemiFrame& frame) } } - if(tun == nullptr) + if (tun == nullptr) { #ifdef KNX_LOG_TUNNELING print("Found no Tunnel for IA: "); @@ -159,32 +167,34 @@ void IpDataLinkLayer::dataConfirmationToTunnel(CemiFrame& frame) void IpDataLinkLayer::dataIndicationToTunnel(CemiFrame& frame) { - if(frame.addressType() == AddressType::GroupAddress) + if (frame.addressType() == AddressType::GroupAddress) { - for(int i = 0; i < KNX_TUNNELING; i++) - if(tunnels[i].ChannelId != 0 && tunnels[i].IndividualAddress != frame.sourceAddress()) + for (int i = 0; i < KNX_TUNNELING; i++) + if (tunnels[i].ChannelId != 0 && tunnels[i].IndividualAddress != frame.sourceAddress()) sendFrameToTunnel(&tunnels[i], frame); + return; } - KnxIpTunnelConnection *tun = nullptr; - for(int i = 0; i < KNX_TUNNELING; i++) + KnxIpTunnelConnection* tun = nullptr; + + for (int i = 0; i < KNX_TUNNELING; i++) { - if(tunnels[i].ChannelId == 0 || tunnels[i].IndividualAddress == frame.sourceAddress()) + if (tunnels[i].ChannelId == 0 || tunnels[i].IndividualAddress == frame.sourceAddress()) continue; - - if(tunnels[i].IndividualAddress == frame.destinationAddress()) + + if (tunnels[i].IndividualAddress == frame.destinationAddress()) { tun = &tunnels[i]; break; } } - if(tun == nullptr) + if (tun == nullptr) { - for(int i = 0; i < KNX_TUNNELING; i++) + for (int i = 0; i < KNX_TUNNELING; i++) { - if(tunnels[i].IsConfig) + if (tunnels[i].IsConfig) { #ifdef KNX_LOG_TUNNELING println("Found config Channel"); @@ -195,7 +205,7 @@ void IpDataLinkLayer::dataIndicationToTunnel(CemiFrame& frame) } } - if(tun == nullptr) + if (tun == nullptr) { #ifdef KNX_LOG_TUNNELING print("Found no Tunnel for IA: "); @@ -207,7 +217,7 @@ void IpDataLinkLayer::dataIndicationToTunnel(CemiFrame& frame) sendFrameToTunnel(tun, frame); } -void IpDataLinkLayer::sendFrameToTunnel(KnxIpTunnelConnection *tunnel, CemiFrame& frame) +void IpDataLinkLayer::sendFrameToTunnel(KnxIpTunnelConnection* tunnel, CemiFrame& frame) { #ifdef KNX_LOG_TUNNELING print("Send to Channel: "); @@ -218,7 +228,7 @@ void IpDataLinkLayer::sendFrameToTunnel(KnxIpTunnelConnection *tunnel, CemiFrame 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) + if (frame.messageCode() != L_data_req && frame.messageCode() != L_data_con && frame.messageCode() != L_data_ind) req.serviceTypeIdentifier(DeviceConfigurationRequest); _platform.sendBytesUniCast(tunnel->IpAddress, tunnel->PortData, req.data(), req.totalLength()); @@ -226,11 +236,11 @@ void IpDataLinkLayer::sendFrameToTunnel(KnxIpTunnelConnection *tunnel, CemiFrame bool IpDataLinkLayer::isTunnelAddress(uint16_t addr) { - if(addr == 0) + 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].IndividualAddress == addr) + + for (int i = 0; i < KNX_TUNNELING; i++) + if (tunnels[i].IndividualAddress == addr) return true; return false; @@ -238,16 +248,20 @@ bool IpDataLinkLayer::isTunnelAddress(uint16_t addr) bool IpDataLinkLayer::isSentToTunnel(uint16_t address, bool isGrpAddr) { - if(isGrpAddr) + if (isGrpAddr) { - for(int i = 0; i < KNX_TUNNELING; i++) - if(tunnels[i].ChannelId != 0) + for (int i = 0; i < KNX_TUNNELING; i++) + if (tunnels[i].ChannelId != 0) return true; + return false; - } else { - for(int i = 0; i < KNX_TUNNELING; i++) - if(tunnels[i].ChannelId != 0 && tunnels[i].IndividualAddress == address) + } + else + { + for (int i = 0; i < KNX_TUNNELING; i++) + if (tunnels[i].ChannelId != 0 && tunnels[i].IndividualAddress == address) return true; + return false; } } @@ -259,17 +273,18 @@ void IpDataLinkLayer::loop() return; #ifdef KNX_TUNNELING - for(int i = 0; i < KNX_TUNNELING; i++) + + for (int i = 0; i < KNX_TUNNELING; i++) { - if(tunnels[i].ChannelId != 0) + if (tunnels[i].ChannelId != 0) { - if(millis() - tunnels[i].lastHeartbeat > 120000) + if (millis() - tunnels[i].lastHeartbeat > 120000) { - #ifdef KNX_LOG_TUNNELING +#ifdef KNX_LOG_TUNNELING print("Closed Tunnel 0x"); print(tunnels[i].ChannelId, 16); println(" due to no heartbeat in 2 minutes"); - #endif +#endif KnxIpDisconnectRequest discReq; discReq.channelId(tunnels[i].ChannelId); discReq.hpaiCtrl().length(LEN_IPHPAI); @@ -279,9 +294,11 @@ void IpDataLinkLayer::loop() _platform.sendBytesUniCast(tunnels[i].IpAddress, tunnels[i].PortCtrl, discReq.data(), discReq.totalLength()); tunnels[i].Reset(); } + break; } } + #endif @@ -289,23 +306,27 @@ void IpDataLinkLayer::loop() uint16_t remotePort = 0; uint32_t remoteAddr = 0; int len = _platform.readBytesMultiCast(buffer, 512, remoteAddr, remotePort); + if (len <= 0) return; if (len < KNXIP_HEADER_LEN) return; - - if (buffer[0] != KNXIP_HEADER_LEN - || buffer[1] != KNXIP_PROTOCOL_VERSION) + + if (buffer[0] != KNXIP_HEADER_LEN + || buffer[1] != KNXIP_PROTOCOL_VERSION) return; #ifdef KNX_ACTIVITYCALLBACK - if(_dllcb) + + if (_dllcb) _dllcb->activity((_netIndex << KNX_ACTIVITYCALLBACK_NET) | (KNX_ACTIVITYCALLBACK_DIR_RECV << KNX_ACTIVITYCALLBACK_DIR)); + #endif uint16_t code; popWord(code, buffer + 2); + switch ((KnxIpServiceType)code) { case RoutingIndication: @@ -314,7 +335,7 @@ void IpDataLinkLayer::loop() frameReceived(routingIndication.frame()); break; } - + case SearchRequest: { KnxIpSearchRequest searchRequest(buffer, len); @@ -322,20 +343,25 @@ void IpDataLinkLayer::loop() auto hpai = searchRequest.hpai(); #ifdef KNX_ACTIVITYCALLBACK - if(_dllcb) + + if (_dllcb) _dllcb->activity((_netIndex << KNX_ACTIVITYCALLBACK_NET) | (KNX_ACTIVITYCALLBACK_DIR_SEND << KNX_ACTIVITYCALLBACK_DIR) | (KNX_ACTIVITYCALLBACK_IPUNICAST)); + #endif _platform.sendBytesUniCast(hpai.ipAddress(), hpai.ipPortNumber(), searchResponse.data(), searchResponse.totalLength()); break; } + case SearchRequestExt: { - #if KNX_SERVICE_FAMILY_CORE >= 2 +#if KNX_SERVICE_FAMILY_CORE >= 2 loopHandleSearchRequestExtended(buffer, len); - #endif +#endif break; } + #ifdef KNX_TUNNELING + case ConnectRequest: { loopHandleConnectRequest(buffer, len, remoteAddr, remotePort); @@ -385,7 +411,9 @@ void IpDataLinkLayer::loop() //println("got Ack"); break; } + #endif + default: print("Unhandled service identifier: "); println(code, HEX); @@ -398,89 +426,107 @@ void IpDataLinkLayer::loopHandleSearchRequestExtended(uint8_t* buffer, uint16_t { KnxIpSearchRequestExtended searchRequest(buffer, length); - if(searchRequest.srpByProgMode) + if (searchRequest.srpByProgMode) { println("srpByProgMode"); - if(!knx.progMode()) return; + + if (!knx.progMode()) + return; } - if(searchRequest.srpByMacAddr) + 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]) + 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 - #ifdef KNX_TUNNELING - #define LEN_SERVICE_DIB (2 + 4 * LEN_SERVICE_FAMILIES) - #else - #define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) - #endif - #else - #ifdef KNX_TUNNELING - #define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) - #else - #define LEN_SERVICE_DIB (2 + 2 * LEN_SERVICE_FAMILIES) - #endif - #endif +#define LEN_SERVICE_FAMILIES 2 +#if MASK_VERSION == 0x091A +#ifdef KNX_TUNNELING +#define LEN_SERVICE_DIB (2 + 4 * LEN_SERVICE_FAMILIES) +#else +#define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) +#endif +#else +#ifdef KNX_TUNNELING +#define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) +#else +#define LEN_SERVICE_DIB (2 + 2 * LEN_SERVICE_FAMILIES) +#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) + if (searchRequest.srpByService) { println("srpByService"); uint8_t length = searchRequest.srpServiceFamilies[0]; - uint8_t *currentPos = searchRequest.srpServiceFamilies + 2; - for(int i = 0; i < (length-2)/2; i++) + uint8_t* currentPos = searchRequest.srpServiceFamilies + 2; + + for (int i = 0; i < (length - 2) / 2; i++) { - uint8_t serviceFamily = (currentPos + i*2)[0]; - uint8_t version = (currentPos + i*2)[1]; - switch(serviceFamily) + uint8_t serviceFamily = (currentPos + i * 2)[0]; + uint8_t version = (currentPos + i * 2)[1]; + + switch (serviceFamily) { case Core: - if(version > KNX_SERVICE_FAMILY_CORE) return; + if (version > KNX_SERVICE_FAMILY_CORE) + return; + break; + case DeviceManagement: - if(version > KNX_SERVICE_FAMILY_DEVICE_MANAGEMENT) return; + if (version > KNX_SERVICE_FAMILY_DEVICE_MANAGEMENT) + return; + break; + case Tunnelling: - if(version > KNX_SERVICE_FAMILY_TUNNELING) return; + if (version > KNX_SERVICE_FAMILY_TUNNELING) + return; + break; + case Routing: - if(version > KNX_SERVICE_FAMILY_ROUTING) return; + if (version > KNX_SERVICE_FAMILY_ROUTING) + return; + break; } } } - if(searchRequest.srpRequestDIBs) + if (searchRequest.srpRequestDIBs) { println("srpRequestDIBs"); - if(searchRequest.requestedDIB(IP_CONFIG)) + + if (searchRequest.requestedDIB(IP_CONFIG)) dibLength += LEN_IP_CONFIG_DIB; //16 - if(searchRequest.requestedDIB(IP_CUR_CONFIG)) + if (searchRequest.requestedDIB(IP_CUR_CONFIG)) dibLength += LEN_IP_CURRENT_CONFIG_DIB; //20 - if(searchRequest.requestedDIB(KNX_ADDRESSES)) - {uint16_t length = 0; + if (searchRequest.requestedDIB(KNX_ADDRESSES)) + { + uint16_t length = 0; _ipParameters.readPropertyLength(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, length); - dibLength += 4 + length*2; + dibLength += 4 + length * 2; } - if(searchRequest.requestedDIB(MANUFACTURER_DATA)) + if (searchRequest.requestedDIB(MANUFACTURER_DATA)) dibLength += 0; //4 + n - if(searchRequest.requestedDIB(TUNNELING_INFO)) + if (searchRequest.requestedDIB(TUNNELING_INFO)) { uint16_t length = 0; _ipParameters.readPropertyLength(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, length); - dibLength += 4 + length*4; + dibLength += 4 + length * 4; } } @@ -490,27 +536,27 @@ void IpDataLinkLayer::loopHandleSearchRequestExtended(uint8_t* buffer, uint16_t searchResponse.setSupportedServices(); //DescriptionTypeCode::SUPP_SVC_FAMILIES 2 searchResponse.setExtendedDeviceInfo(); //DescriptionTypeCode::EXTENDED_DEVICE_INFO 8 - if(searchRequest.srpRequestDIBs) + if (searchRequest.srpRequestDIBs) { - if(searchRequest.requestedDIB(IP_CONFIG)) + if (searchRequest.requestedDIB(IP_CONFIG)) searchResponse.setIpConfig(_ipParameters); - if(searchRequest.requestedDIB(IP_CUR_CONFIG)) + if (searchRequest.requestedDIB(IP_CUR_CONFIG)) searchResponse.setIpCurrentConfig(_ipParameters); - if(searchRequest.requestedDIB(KNX_ADDRESSES)) + if (searchRequest.requestedDIB(KNX_ADDRESSES)) searchResponse.setKnxAddresses(_ipParameters, _deviceObject); - if(searchRequest.requestedDIB(MANUFACTURER_DATA)) + if (searchRequest.requestedDIB(MANUFACTURER_DATA)) { //println("requested MANUFACTURER_DATA but not implemented"); } - if(searchRequest.requestedDIB(TUNNELING_INFO)) + if (searchRequest.requestedDIB(TUNNELING_INFO)) searchResponse.setTunnelingInfo(_ipParameters, _deviceObject, tunnels); } - if(searchResponse.totalLength() > 150) + if (searchResponse.totalLength() > 150) { println("skipped response cause length is not plausible"); return; @@ -526,25 +572,30 @@ void IpDataLinkLayer::loopHandleConnectRequest(uint8_t* buffer, uint16_t length, KnxIpConnectRequest connRequest(buffer, length); #ifdef KNX_LOG_TUNNELING println("Got Connect Request!"); - switch(connRequest.cri().type()) + + switch (connRequest.cri().type()) { case DEVICE_MGMT_CONNECTION: println("Device Management Connection"); break; + case TUNNEL_CONNECTION: println("Tunnel Connection"); break; + case REMLOG_CONNECTION: println("RemLog Connection"); break; + case REMCONF_CONNECTION: println("RemConf Connection"); break; + case OBJSVR_CONNECTION: println("ObjectServer Connection"); break; } - + print("Data Endpoint: "); uint32_t ip = connRequest.hpaiData().ipAddress(); print(ip >> 24); @@ -570,7 +621,7 @@ void IpDataLinkLayer::loopHandleConnectRequest(uint8_t* buffer, uint16_t length, #endif //We only support 0x03 and 0x04! - if(connRequest.cri().type() != TUNNEL_CONNECTION && connRequest.cri().type() != DEVICE_MGMT_CONNECTION) + if (connRequest.cri().type() != TUNNEL_CONNECTION && connRequest.cri().type() != DEVICE_MGMT_CONNECTION) { #ifdef KNX_LOG_TUNNELING println("Only Tunnel/DeviceMgmt Connection ist supported!"); @@ -580,11 +631,11 @@ void IpDataLinkLayer::loopHandleConnectRequest(uint8_t* buffer, uint16_t length, return; } - if(connRequest.cri().type() == TUNNEL_CONNECTION && connRequest.cri().layer() != 0x02) //LinkLayer + 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); _platform.sendBytesUniCast(connRequest.hpaiCtrl().ipAddress(), connRequest.hpaiCtrl().ipPortNumber(), connRes.data(), connRes.totalLength()); @@ -593,51 +644,60 @@ void IpDataLinkLayer::loopHandleConnectRequest(uint8_t* buffer, uint16_t length, // 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 + // 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) + 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]; + uint8_t addrbuffer[KNX_TUNNELING * 2]; addresses = (uint8_t*)addrbuffer; - for(int i = 0; i < KNX_TUNNELING; i++) + + for (int i = 0; i < KNX_TUNNELING; i++) { - addrbuffer[i*2+1] = i+1; - addrbuffer[i*2] = _deviceObject.individualAddress() / 0x0100; + 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); #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; - if(propCount == KNX_TUNNELING) + const uint8_t* tunCtrlBytes = nullptr; + + 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; - if(propCount == KNX_TUNNELING) + const uint8_t* tunCtrlIp = nullptr; + + if (propCount == KNX_TUNNELING) tunCtrlIp = _ipParameters.propertyData(PID_CUSTOM_RESERVED_TUNNELS_IP); - + bool resTunActive = (tunCtrlBytes && tunCtrlIp); #ifdef KNX_LOG_TUNNELING - if(resTunActive) println("Reserved Tunnel Feature active"); - if(tunCtrlBytes) - printHex("tunCtrlBytes", tunCtrlBytes, KNX_TUNNELING); - if(tunCtrlIp) - printHex("tunCtrlIp", tunCtrlIp, KNX_TUNNELING*4); + if (resTunActive) + println("Reserved Tunnel Feature active"); + + if (tunCtrlBytes) + printHex("tunCtrlBytes", tunCtrlBytes, KNX_TUNNELING); + + if (tunCtrlIp) + printHex("tunCtrlIp", tunCtrlIp, KNX_TUNNELING * 4); + #endif // check if there is a reserved tunnel for the source @@ -646,71 +706,75 @@ void IpDataLinkLayer::loopHandleConnectRequest(uint8_t* buffer, uint16_t length, int firstResAndOccTunnel = -1; bool tunnelResActive[KNX_TUNNELING]; uint8_t tunnelResOptions[KNX_TUNNELING]; - for(int i = 0; i < KNX_TUNNELING; i++) + + for (int i = 0; i < KNX_TUNNELING; i++) { - if(resTunActive) + if (resTunActive) { - tunnelResActive[i] = *(tunCtrlBytes+i) & 0x80; - tunnelResOptions[i] = (*(tunCtrlBytes+i) & 0x60) >> 5; + 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 +#ifdef KNX_LOG_TUNNELING print("tunnel reserve feature active for this tunnel: "); print(tunnelResActive[i]); print(" options: "); println(tunnelResOptions[i]); - #endif - +#endif + uint32_t rIP = 0; - popInt(rIP, tunCtrlIp+4*i); - if(srcIP == rIP && connRequest.cri().type() == TUNNEL_CONNECTION) + 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 (tunnels[i].ChannelId == 0) // check if it is free { - if(firstResAndFreeTunnel < 0) + if (firstResAndFreeTunnel < 0) firstResAndFreeTunnel = i; } else { - if(firstResAndOccTunnel < 0) + if (firstResAndOccTunnel < 0) firstResAndOccTunnel = i; } } } else { - if(tunnels[i].ChannelId == 0 && firstFreeTunnel < 0) + 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; - if(resTunActive & (firstResAndFreeTunnel >= 0 || firstResAndOccTunnel >= 0)) // tunnel reserve feature active (for this src) + + if (resTunActive & (firstResAndFreeTunnel >= 0 || firstResAndOccTunnel >= 0)) // tunnel reserve feature active (for this src) { - if(firstResAndFreeTunnel >= 0) + if (firstResAndFreeTunnel >= 0) { tunIdx = firstResAndFreeTunnel; } - else if(firstResAndOccTunnel >= 0) + else if (firstResAndOccTunnel >= 0) { - if(tunnelResOptions[firstResAndOccTunnel] == 1) // decline req + 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 + else if (tunnelResOptions[firstResAndOccTunnel] == 2) // close current tunnel connection on this tunnel and assign to this request { KnxIpDisconnectRequest discReq; discReq.channelId(tunnels[firstResAndOccTunnel].ChannelId); @@ -724,53 +788,57 @@ void IpDataLinkLayer::loopHandleConnectRequest(uint8_t* buffer, uint16_t length, tunIdx = firstResAndOccTunnel; } - else if(tunnelResOptions[firstResAndOccTunnel] == 3) // use the first unreserved tunnel (if one) + else if (tunnelResOptions[firstResAndOccTunnel] == 3) // use the first unreserved tunnel (if one) { - if(firstFreeTunnel >= 0) + if (firstFreeTunnel >= 0) tunIdx = firstFreeTunnel; else ; // do nothing => decline } + //else - // should not happen - // do nothing => decline - } - //else // should not happen // do nothing => decline + } + + //else + // should not happen + // do nothing => decline } else { - if(firstFreeTunnel >= 0) + if (firstFreeTunnel >= 0) tunIdx = firstFreeTunnel; + //else // do nothing => decline } - KnxIpTunnelConnection *tun = nullptr; - if(tunIdx != 0xFF) + KnxIpTunnelConnection* tun = nullptr; + + if (tunIdx != 0xFF) { tun = &tunnels[tunIdx]; uint16_t tunPa = 0; - popWord(tunPa, addresses + (tunIdx*2)); + 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) + 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; } - + tun->IndividualAddress = tunPa; } - if(tun == nullptr) + if (tun == nullptr) { println("no free tunnel availible"); KnxIpConnectResponse connRes(0x00, E_NO_MORE_CONNECTIONS); @@ -778,29 +846,31 @@ void IpDataLinkLayer::loopHandleConnectRequest(uint8_t* buffer, uint16_t length, return; } - if(connRequest.cri().type() == DEVICE_MGMT_CONNECTION) + 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; + do { _lastChannelId++; channelIdInUse = false; - for(int x = 0; x < KNX_TUNNELING; x++) - if(tunnels[x].ChannelId == _lastChannelId) + + for (int x = 0; x < KNX_TUNNELING; x++) + if (tunnels[x].ChannelId == _lastChannelId) channelIdInUse = true; - } - while(channelIdInUse); + } while (channelIdInUse); tun->ChannelId = _lastChannelId; tun->lastHeartbeat = millis(); - if(_lastChannelId == 255) + + if (_lastChannelId == 255) _lastChannelId = 0; tun->IpAddress = srcIP; tun->PortData = srcPort; - tun->PortCtrl = connRequest.hpaiCtrl().ipPortNumber()?connRequest.hpaiCtrl().ipPortNumber():srcPort; + tun->PortCtrl = connRequest.hpaiCtrl().ipPortNumber() ? connRequest.hpaiCtrl().ipPortNumber() : srcPort; print("New Tunnel-Connection["); print(tunIdx); @@ -823,16 +893,19 @@ void IpDataLinkLayer::loopHandleConnectRequest(uint8_t* buffer, uint16_t length, print(tun->IpAddress & 0xFF); print(":"); print(tun->PortData); - if(tun->PortData != tun->PortCtrl) + + if (tun->PortData != tun->PortCtrl) { print(" (Ctrlport: "); print(tun->PortCtrl); print(")"); } - if(tun->IsConfig) + + if (tun->IsConfig) { print(" (Config-Channel)"); } + println(); @@ -844,17 +917,18 @@ void IpDataLinkLayer::loopHandleConnectionStateRequest(uint8_t* buffer, uint16_t { KnxIpStateRequest stateRequest(buffer, length); - KnxIpTunnelConnection *tun = nullptr; - for(int i = 0; i < KNX_TUNNELING; i++) + KnxIpTunnelConnection* tun = nullptr; + + for (int i = 0; i < KNX_TUNNELING; i++) { - if(tunnels[i].ChannelId == stateRequest.channelId()) + 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: "); @@ -878,23 +952,24 @@ void IpDataLinkLayer::loopHandleConnectionStateRequest(uint8_t* buffer, uint16_t void IpDataLinkLayer::loopHandleDisconnectRequest(uint8_t* buffer, uint16_t length) { KnxIpDisconnectRequest discReq(buffer, length); - + #ifdef KNX_LOG_TUNNELING print(">>> Disconnect Channel ID: "); println(discReq.channelId()); #endif - - KnxIpTunnelConnection *tun = nullptr; - for(int i = 0; i < KNX_TUNNELING; i++) + + KnxIpTunnelConnection* tun = nullptr; + + for (int i = 0; i < KNX_TUNNELING; i++) { - if(tunnels[i].ChannelId == discReq.channelId()) + 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: "); @@ -921,18 +996,19 @@ void IpDataLinkLayer::loopHandleDescriptionRequest(uint8_t* buffer, uint16_t len void IpDataLinkLayer::loopHandleDeviceConfigurationRequest(uint8_t* buffer, uint16_t length) { KnxIpConfigRequest confReq(buffer, length); - - KnxIpTunnelConnection *tun = nullptr; - for(int i = 0; i < KNX_TUNNELING; i++) + + KnxIpTunnelConnection* tun = nullptr; + + for (int i = 0; i < KNX_TUNNELING; i++) { - if(tunnels[i].ChannelId == confReq.connectionHeader().channelId()) + if (tunnels[i].ChannelId == confReq.connectionHeader().channelId()) { tun = &tunnels[i]; break; } } - if(tun == nullptr) + if (tun == nullptr) { print("Channel ID nicht gefunden: "); println(confReq.connectionHeader().channelId()); @@ -957,17 +1033,18 @@ void IpDataLinkLayer::loopHandleTunnelingRequest(uint8_t* buffer, uint16_t lengt { KnxIpTunnelingRequest tunnReq(buffer, length); - KnxIpTunnelConnection *tun = nullptr; - for(int i = 0; i < KNX_TUNNELING; i++) + KnxIpTunnelConnection* tun = nullptr; + + for (int i = 0; i < KNX_TUNNELING; i++) { - if(tunnels[i].ChannelId == tunnReq.connectionHeader().channelId()) + 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: "); @@ -979,7 +1056,8 @@ void IpDataLinkLayer::loopHandleTunnelingRequest(uint8_t* buffer, uint16_t lengt } uint8_t sequence = tunnReq.connectionHeader().sequenceCounter(); - if(sequence == tun->SequenceCounter_R) + + if (sequence == tun->SequenceCounter_R) { #ifdef KNX_LOG_TUNNELING print("Received SequenceCounter again: "); @@ -994,7 +1072,9 @@ void IpDataLinkLayer::loopHandleTunnelingRequest(uint8_t* buffer, uint16_t lengt tunnAck.connectionHeader().status(E_NO_ERROR); _platform.sendBytesUniCast(tun->IpAddress, tun->PortData, tunnAck.data(), tunnAck.totalLength()); return; - } else if((uint8_t)(sequence - 1) != tun->SequenceCounter_R) { + } + else if ((uint8_t)(sequence - 1) != tun->SequenceCounter_R) + { #ifdef KNX_LOG_TUNNELING print("Wrong SequenceCounter: got "); print(tunnReq.connectionHeader().sequenceCounter()); @@ -1004,7 +1084,7 @@ void IpDataLinkLayer::loopHandleTunnelingRequest(uint8_t* buffer, uint16_t lengt //Dont handle it return; } - + KnxIpTunnelingAck tunnAck; tunnAck.connectionHeader().length(4); tunnAck.connectionHeader().channelId(tun->ChannelId); @@ -1014,7 +1094,7 @@ void IpDataLinkLayer::loopHandleTunnelingRequest(uint8_t* buffer, uint16_t lengt tun->SequenceCounter_R = tunnReq.connectionHeader().sequenceCounter(); - if(tunnReq.frame().sourceAddress() == 0) + if (tunnReq.frame().sourceAddress() == 0) tunnReq.frame().sourceAddress(tun->IndividualAddress); _cemiServer->frameReceived(tunnReq.frame()); @@ -1023,8 +1103,8 @@ void IpDataLinkLayer::loopHandleTunnelingRequest(uint8_t* buffer, uint16_t lengt void IpDataLinkLayer::enabled(bool value) { -// _print("own address: "); -// _println(_deviceObject.individualAddress()); + // _print("own address: "); + // _println(_deviceObject.individualAddress()); if (value && !_enabled) { _platform.setupMultiCast(_ipParameters.propertyValue(PID_ROUTING_MULTICAST_ADDRESS), KNXIP_MULTICAST_PORT); @@ -1032,7 +1112,7 @@ void IpDataLinkLayer::enabled(bool value) return; } - if(!value && _enabled) + if (!value && _enabled) { _platform.closeMultiCast(); _enabled = false; @@ -1063,32 +1143,38 @@ bool IpDataLinkLayer::isSendLimitReached() uint32_t curTime = millis() / 100; // check if the countbuffer must be adjusted - if(_frameCountTimeBase >= curTime) + if (_frameCountTimeBase >= curTime) { uint32_t timeBaseDiff = _frameCountTimeBase - curTime; - if(timeBaseDiff > 10) + + if (timeBaseDiff > 10) timeBaseDiff = 10; - for(uint32_t i = 0; i < timeBaseDiff ; i++) + + 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++) + for (int i = 0; i < 10 ; i++) _frameCount[i] = 0; + _frameCountBase = 0; _frameCountTimeBase = curTime; } //check if we are over the limit uint16_t sum = 0; - for(int i = 0; i < 10 ; i++) + + for (int i = 0; i < 10 ; i++) sum += _frameCount[i]; - if(sum > 50) + + if (sum > 50) { println("Dropping packet due to 50p/s limit"); return true; // drop packet diff --git a/src/knx/ip_data_link_layer.h b/src/knx/ip_data_link_layer.h index 128f59f8..033632f5 100644 --- a/src/knx/ip_data_link_layer.h +++ b/src/knx/ip_data_link_layer.h @@ -11,50 +11,50 @@ class IpDataLinkLayer : public DataLinkLayer { - using DataLinkLayer::_deviceObject; + using DataLinkLayer::_deviceObject; - public: - IpDataLinkLayer(DeviceObject& devObj, IpParameterObject& ipParam, NetworkLayerEntity& netLayerEntity, - Platform& platform, BusAccessUnit& busAccessUnit, DataLinkLayerCallbacks* dllcb = nullptr); + public: + IpDataLinkLayer(DeviceObject& devObj, IpParameterObject& ipParam, NetworkLayerEntity& netLayerEntity, + Platform& platform, BusAccessUnit& busAccessUnit, 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; - bool isSentToTunnel(uint16_t address, bool isGrpAddr); + void dataRequestToTunnel(CemiFrame& frame) override; + void dataConfirmationToTunnel(CemiFrame& frame) override; + void dataIndicationToTunnel(CemiFrame& frame) override; + bool isTunnelAddress(uint16_t addr) override; + bool isSentToTunnel(uint16_t address, bool isGrpAddr); #endif - private: - bool _enabled = false; - 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 loopHandleDescriptionRequest(uint8_t* buffer, uint16_t length); - void loopHandleDeviceConfigurationRequest(uint8_t* buffer, uint16_t length); - void loopHandleTunnelingRequest(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 loopHandleDescriptionRequest(uint8_t* buffer, uint16_t length); + void loopHandleDeviceConfigurationRequest(uint8_t* buffer, uint16_t length); + void loopHandleTunnelingRequest(uint8_t* buffer, uint16_t length); #endif #if KNX_SERVICE_FAMILY_CORE >= 2 - void loopHandleSearchRequestExtended(uint8_t* buffer, uint16_t length); + void loopHandleSearchRequestExtended(uint8_t* buffer, uint16_t length); #endif - bool sendBytes(uint8_t* buffer, uint16_t length); - bool isSendLimitReached(); + bool sendBytes(uint8_t* buffer, uint16_t length); + bool isSendLimitReached(); - IpParameterObject& _ipParameters; - DataLinkLayerCallbacks* _dllcb; + IpParameterObject& _ipParameters; + DataLinkLayerCallbacks* _dllcb; #ifdef KNX_TUNNELING - KnxIpTunnelConnection tunnels[KNX_TUNNELING]; - uint8_t _lastChannelId = 1; + KnxIpTunnelConnection tunnels[KNX_TUNNELING]; + uint8_t _lastChannelId = 1; #endif }; #endif \ No newline at end of file diff --git a/src/knx/ip_host_protocol_address_information.h b/src/knx/ip_host_protocol_address_information.h index bcf04949..c46b1b23 100644 --- a/src/knx/ip_host_protocol_address_information.h +++ b/src/knx/ip_host_protocol_address_information.h @@ -16,18 +16,18 @@ enum HostProtocolCode : uint8_t 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); + 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; + private: + uint8_t* _data; }; #endif \ No newline at end of file diff --git a/src/knx/ip_parameter_object.cpp b/src/knx/ip_parameter_object.cpp index 59807831..0109f0aa 100644 --- a/src/knx/ip_parameter_object.cpp +++ b/src/knx/ip_parameter_object.cpp @@ -17,23 +17,23 @@ IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platf 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 + [](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t + { + if (start == 0) { - 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); + uint16_t currentNoOfElements = 1; + pushWord(currentNoOfElements, data); return 1; - }, - [](IpParameterObject* io, uint16_t start, uint8_t count, const uint8_t* data) -> uint8_t - { - io->_deviceObject.individualAddress(getWord(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; + }), #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) @@ -43,88 +43,88 @@ IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platf 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) - { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); - return 1; - } - - pushInt(htonl(io->_platform.currentIpAddress()), data); + [](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; - }), - 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); - return 1; - } + } - pushInt(htonl(io->_platform.currentSubnetMask()), data); + 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); 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) - { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); - return 1; - } + } - pushInt(htonl(io->_platform.currentDefaultGateway()), data); + 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) + { + 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; - } - - io->_platform.macAddress(data); + [](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; - }), - 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) - { - uint16_t currentNoOfElements = 1; - pushWord(currentNoOfElements, data); - return 1; - } + } - pushInt(DEFAULT_MULTICAST_ADDR, data); + 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) + { + 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); + [](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); diff --git a/src/knx/ip_parameter_object.h b/src/knx/ip_parameter_object.h index 0115be6c..6fba0080 100644 --- a/src/knx/ip_parameter_object.h +++ b/src/knx/ip_parameter_object.h @@ -10,11 +10,11 @@ class IpParameterObject : public InterfaceObject { - public: - IpParameterObject(DeviceObject& deviceObject, Platform& platform); + public: + IpParameterObject(DeviceObject& deviceObject, Platform& platform); - private: - DeviceObject& _deviceObject; - Platform& _platform; + private: + DeviceObject& _deviceObject; + Platform& _platform; }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_ch.h b/src/knx/knx_ip_ch.h index 5277928d..5300c76d 100644 --- a/src/knx/knx_ip_ch.h +++ b/src/knx/knx_ip_ch.h @@ -10,19 +10,19 @@ // 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; + 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; }; #endif diff --git a/src/knx/knx_ip_config_dib.cpp b/src/knx/knx_ip_config_dib.cpp index e603de0a..096d1a23 100644 --- a/src/knx/knx_ip_config_dib.cpp +++ b/src/knx/knx_ip_config_dib.cpp @@ -44,7 +44,9 @@ void KnxIpConfigDIB::gateway(uint32_t addr) uint32_t KnxIpConfigDIB::dhcp() { - if(!_isCurrent) return 0; + if (!_isCurrent) + return 0; + uint32_t addr = 0; popInt(addr, _data + 14); return addr; @@ -52,13 +54,15 @@ uint32_t KnxIpConfigDIB::dhcp() void KnxIpConfigDIB::dhcp(uint32_t addr) { - if(!_isCurrent) return; + if (!_isCurrent) + return; + pushInt(addr, _data + 14); } uint8_t KnxIpConfigDIB::info1() { - if(_isCurrent) + if (_isCurrent) return _data[14]; else return _data[18]; @@ -66,7 +70,7 @@ uint8_t KnxIpConfigDIB::info1() void KnxIpConfigDIB::info1(uint8_t addr) { - if(_isCurrent) + if (_isCurrent) _data[14] = addr; else _data[18] = addr; @@ -74,7 +78,7 @@ void KnxIpConfigDIB::info1(uint8_t addr) uint8_t KnxIpConfigDIB::info2() { - if(_isCurrent) + if (_isCurrent) return _data[15]; else return _data[19]; @@ -82,7 +86,7 @@ uint8_t KnxIpConfigDIB::info2() void KnxIpConfigDIB::info2(uint8_t addr) { - if(_isCurrent) + if (_isCurrent) _data[15] = addr; else _data[19] = addr; diff --git a/src/knx/knx_ip_config_dib.h b/src/knx/knx_ip_config_dib.h index 717bab5c..a67bbd1c 100644 --- a/src/knx/knx_ip_config_dib.h +++ b/src/knx/knx_ip_config_dib.h @@ -8,21 +8,21 @@ 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; + 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; }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_config_request.h b/src/knx/knx_ip_config_request.h index d7d6d1ca..3ffe35b9 100644 --- a/src/knx/knx_ip_config_request.h +++ b/src/knx/knx_ip_config_request.h @@ -6,12 +6,12 @@ #ifdef USE_IP class KnxIpConfigRequest : public KnxIpFrame { - public: - KnxIpConfigRequest(uint8_t* data, uint16_t length); - CemiFrame& frame(); - KnxIpCH& connectionHeader(); - private: - CemiFrame _frame; - KnxIpCH _ch; + public: + KnxIpConfigRequest(uint8_t* data, uint16_t length); + CemiFrame& frame(); + KnxIpCH& connectionHeader(); + private: + CemiFrame _frame; + KnxIpCH _ch; }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_connect_request.cpp b/src/knx/knx_ip_connect_request.cpp index a1f64c0b..322c6813 100644 --- a/src/knx/knx_ip_connect_request.cpp +++ b/src/knx/knx_ip_connect_request.cpp @@ -1,7 +1,7 @@ #include "knx_ip_connect_request.h" #ifdef USE_IP 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) + : KnxIpFrame(data, length), _hpaiCtrl(data + LEN_KNXIP_HEADER), _hpaiData(data + LEN_KNXIP_HEADER + LEN_IPHPAI), _cri(data + LEN_KNXIP_HEADER + 2 * LEN_IPHPAI) { } diff --git a/src/knx/knx_ip_connect_request.h b/src/knx/knx_ip_connect_request.h index 23e398fa..76e75fce 100644 --- a/src/knx/knx_ip_connect_request.h +++ b/src/knx/knx_ip_connect_request.h @@ -6,14 +6,14 @@ #ifdef USE_IP 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; + public: + KnxIpConnectRequest(uint8_t* data, uint16_t length); + IpHostProtocolAddressInformation& hpaiCtrl(); + IpHostProtocolAddressInformation& hpaiData(); + KnxIpCRI& cri(); + private: + IpHostProtocolAddressInformation _hpaiCtrl; + IpHostProtocolAddressInformation _hpaiData; + KnxIpCRI _cri; }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_connect_response.cpp b/src/knx/knx_ip_connect_response.cpp index 11eb705b..2706341b 100644 --- a/src/knx/knx_ip_connect_response.cpp +++ b/src/knx/knx_ip_connect_response.cpp @@ -9,7 +9,7 @@ KnxIpConnectResponse::KnxIpConnectResponse(IpParameterObject& parameters, uint16 serviceTypeIdentifier(ConnectResponse); _data[LEN_KNXIP_HEADER] = channel; - + _controlEndpoint.length(LEN_IPHPAI); _controlEndpoint.code(IPV4_UDP); _controlEndpoint.ipAddress(parameters.propertyValue(PID_CURRENT_IP_ADDRESS)); diff --git a/src/knx/knx_ip_connect_response.h b/src/knx/knx_ip_connect_response.h index ecf1d8fd..fffa33c3 100644 --- a/src/knx/knx_ip_connect_response.h +++ b/src/knx/knx_ip_connect_response.h @@ -10,36 +10,36 @@ enum KnxIpConnectionRequestErrorCodes { - E_NO_ERROR = 0, + 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_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_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 }; 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; + 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; }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_crd.h b/src/knx/knx_ip_crd.h index c7e613b6..1f95e795 100644 --- a/src/knx/knx_ip_crd.h +++ b/src/knx/knx_ip_crd.h @@ -7,17 +7,17 @@ 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); + 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; }; #endif diff --git a/src/knx/knx_ip_cri.h b/src/knx/knx_ip_cri.h index 6c1377a3..c8e2fadb 100644 --- a/src/knx/knx_ip_cri.h +++ b/src/knx/knx_ip_cri.h @@ -10,27 +10,27 @@ //TODO vervollständigen enum ConnectionType : uint8_t { - DEVICE_MGMT_CONNECTION = 3, - TUNNEL_CONNECTION = 4, - REMLOG_CONNECTION = 6, - REMCONF_CONNECTION = 7, - OBJSVR_CONNECTION = 8 + 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); + 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; }; #endif diff --git a/src/knx/knx_ip_description_request.h b/src/knx/knx_ip_description_request.h index 39327e25..f3e0e8d9 100644 --- a/src/knx/knx_ip_description_request.h +++ b/src/knx/knx_ip_description_request.h @@ -6,10 +6,10 @@ #ifdef USE_IP class KnxIpDescriptionRequest : public KnxIpFrame { - public: - KnxIpDescriptionRequest(uint8_t* data, uint16_t length); - IpHostProtocolAddressInformation& hpaiCtrl(); - private: - IpHostProtocolAddressInformation _hpaiCtrl; + public: + KnxIpDescriptionRequest(uint8_t* data, uint16_t length); + IpHostProtocolAddressInformation& hpaiCtrl(); + private: + IpHostProtocolAddressInformation _hpaiCtrl; }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_description_response.cpp b/src/knx/knx_ip_description_response.cpp index 6df1c130..25c3dbda 100644 --- a/src/knx/knx_ip_description_response.cpp +++ b/src/knx/knx_ip_description_response.cpp @@ -3,17 +3,17 @@ #define LEN_SERVICE_FAMILIES 2 #if MASK_VERSION == 0x091A -#ifdef KNX_TUNNELING -#define LEN_SERVICE_DIB (2 + 4 * LEN_SERVICE_FAMILIES) + #ifdef KNX_TUNNELING + #define LEN_SERVICE_DIB (2 + 4 * LEN_SERVICE_FAMILIES) + #else + #define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) + #endif #else -#define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) -#endif -#else -#ifdef KNX_TUNNELING -#define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) -#else -#define LEN_SERVICE_DIB (2 + 2 * LEN_SERVICE_FAMILIES) -#endif + #ifdef KNX_TUNNELING + #define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) + #else + #define LEN_SERVICE_DIB (2 + 2 * LEN_SERVICE_FAMILIES) + #endif #endif KnxIpDescriptionResponse::KnxIpDescriptionResponse(IpParameterObject& parameters, DeviceObject& deviceObject) @@ -41,7 +41,7 @@ KnxIpDescriptionResponse::KnxIpDescriptionResponse(IpParameterObject& parameters 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); diff --git a/src/knx/knx_ip_description_response.h b/src/knx/knx_ip_description_response.h index f9d1055a..efeaafea 100644 --- a/src/knx/knx_ip_description_response.h +++ b/src/knx/knx_ip_description_response.h @@ -9,13 +9,13 @@ class KnxIpDescriptionResponse : public KnxIpFrame { - public: - KnxIpDescriptionResponse(IpParameterObject& parameters, DeviceObject& deviceObj); - KnxIpDeviceInformationDIB& deviceInfo(); - KnxIpSupportedServiceDIB& supportedServices(); - private: - KnxIpDeviceInformationDIB _deviceInfo; - KnxIpSupportedServiceDIB _supportedServices; + public: + KnxIpDescriptionResponse(IpParameterObject& parameters, DeviceObject& deviceObj); + KnxIpDeviceInformationDIB& deviceInfo(); + KnxIpSupportedServiceDIB& supportedServices(); + private: + KnxIpDeviceInformationDIB _deviceInfo; + KnxIpSupportedServiceDIB _supportedServices; }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_device_information_dib.h b/src/knx/knx_ip_device_information_dib.h index 32f24ba0..cc8de4bc 100644 --- a/src/knx/knx_ip_device_information_dib.h +++ b/src/knx/knx_ip_device_information_dib.h @@ -9,24 +9,24 @@ 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); + 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); }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_dib.h b/src/knx/knx_ip_dib.h index cb848cfc..190fe090 100644 --- a/src/knx/knx_ip_dib.h +++ b/src/knx/knx_ip_dib.h @@ -20,15 +20,15 @@ enum DescriptionTypeCode : uint8_t 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); + 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; }; #endif diff --git a/src/knx/knx_ip_disconnect_request.h b/src/knx/knx_ip_disconnect_request.h index 560441d3..a90eccb4 100644 --- a/src/knx/knx_ip_disconnect_request.h +++ b/src/knx/knx_ip_disconnect_request.h @@ -5,13 +5,13 @@ #ifdef USE_IP 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; + public: + KnxIpDisconnectRequest(uint8_t* data, uint16_t length); + KnxIpDisconnectRequest(); + IpHostProtocolAddressInformation& hpaiCtrl(); + uint8_t channelId(); + void channelId(uint8_t channelId); + private: + IpHostProtocolAddressInformation _hpaiCtrl; }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_disconnect_response.cpp b/src/knx/knx_ip_disconnect_response.cpp index d232539f..a82cae26 100644 --- a/src/knx/knx_ip_disconnect_response.cpp +++ b/src/knx/knx_ip_disconnect_response.cpp @@ -7,6 +7,6 @@ KnxIpDisconnectResponse::KnxIpDisconnectResponse(uint8_t channel, uint8_t status serviceTypeIdentifier(DisconnectResponse); _data[LEN_KNXIP_HEADER] = channel; - _data[LEN_KNXIP_HEADER+1] = status; + _data[LEN_KNXIP_HEADER + 1] = status; } #endif diff --git a/src/knx/knx_ip_disconnect_response.h b/src/knx/knx_ip_disconnect_response.h index 26ef8757..553f72c4 100644 --- a/src/knx/knx_ip_disconnect_response.h +++ b/src/knx/knx_ip_disconnect_response.h @@ -5,9 +5,9 @@ class KnxIpDisconnectResponse : public KnxIpFrame { - public: - KnxIpDisconnectResponse(uint8_t channel, uint8_t status); - private: + public: + KnxIpDisconnectResponse(uint8_t channel, uint8_t status); + private: }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_extended_device_information_dib.h b/src/knx/knx_ip_extended_device_information_dib.h index df46f5ef..923c4d4b 100644 --- a/src/knx/knx_ip_extended_device_information_dib.h +++ b/src/knx/knx_ip_extended_device_information_dib.h @@ -6,14 +6,14 @@ 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); + 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); }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_frame.h b/src/knx/knx_ip_frame.h index c6c1c518..2c10e0fc 100644 --- a/src/knx/knx_ip_frame.h +++ b/src/knx/knx_ip_frame.h @@ -35,23 +35,23 @@ enum KnxIpServiceType 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); - uint16_t serviceTypeIdentifier() const; - void serviceTypeIdentifier(uint16_t identifier); - uint16_t totalLength() const; - void totalLength(uint16_t length); - uint8_t* data(); + 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); + uint16_t serviceTypeIdentifier() const; + void serviceTypeIdentifier(uint16_t identifier); + uint16_t totalLength() const; + void totalLength(uint16_t length); + uint8_t* data(); - protected: - bool _freeData = false; - uint8_t* _data = 0; - uint16_t _dataLength; + protected: + bool _freeData = false; + uint8_t* _data = 0; + uint16_t _dataLength; }; #endif diff --git a/src/knx/knx_ip_knx_addresses_dib.h b/src/knx/knx_ip_knx_addresses_dib.h index c0905525..757dcb32 100644 --- a/src/knx/knx_ip_knx_addresses_dib.h +++ b/src/knx/knx_ip_knx_addresses_dib.h @@ -6,12 +6,12 @@ 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; + public: + KnxIpKnxAddressesDIB(uint8_t* data); + uint16_t individualAddress(); + void individualAddress(uint16_t addr); + void additional(uint16_t addr); + private: + uint8_t* currentPos = 0; }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_routing_indication.cpp b/src/knx/knx_ip_routing_indication.cpp index 74863653..0504570e 100644 --- a/src/knx/knx_ip_routing_indication.cpp +++ b/src/knx/knx_ip_routing_indication.cpp @@ -8,8 +8,8 @@ CemiFrame& KnxIpRoutingIndication::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()) { } diff --git a/src/knx/knx_ip_routing_indication.h b/src/knx/knx_ip_routing_indication.h index 3de7975e..38cef413 100644 --- a/src/knx/knx_ip_routing_indication.h +++ b/src/knx/knx_ip_routing_indication.h @@ -6,11 +6,11 @@ class KnxIpRoutingIndication : public KnxIpFrame { - public: - KnxIpRoutingIndication(uint8_t* data, uint16_t length); - KnxIpRoutingIndication(CemiFrame frame); - CemiFrame& frame(); - private: - CemiFrame _frame; + public: + KnxIpRoutingIndication(uint8_t* data, uint16_t length); + KnxIpRoutingIndication(CemiFrame frame); + CemiFrame& frame(); + private: + CemiFrame _frame; }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_search_request.h b/src/knx/knx_ip_search_request.h index e51ae468..eea049fd 100644 --- a/src/knx/knx_ip_search_request.h +++ b/src/knx/knx_ip_search_request.h @@ -5,10 +5,10 @@ #ifdef USE_IP class KnxIpSearchRequest : public KnxIpFrame { - public: - KnxIpSearchRequest(uint8_t* data, uint16_t length); - IpHostProtocolAddressInformation& hpai(); - private: - IpHostProtocolAddressInformation _hpai; + public: + KnxIpSearchRequest(uint8_t* data, uint16_t length); + IpHostProtocolAddressInformation& hpai(); + private: + IpHostProtocolAddressInformation _hpai; }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_search_request_extended.cpp b/src/knx/knx_ip_search_request_extended.cpp index c8387163..19fc7e4f 100644 --- a/src/knx/knx_ip_search_request_extended.cpp +++ b/src/knx/knx_ip_search_request_extended.cpp @@ -6,12 +6,14 @@ 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 + if (length == LEN_KNXIP_HEADER + LEN_IPHPAI) + return; //we dont have SRPs int currentPos = LEN_KNXIP_HEADER + LEN_IPHPAI; - while(currentPos < length) + + while (currentPos < length) { - switch(data[currentPos+1]) + switch (data[currentPos + 1]) { case 0x01: srpByProgMode = true; @@ -29,18 +31,24 @@ KnxIpSearchRequestExtended::KnxIpSearchRequestExtended(uint8_t* data, uint16_t l case 0x04: srpRequestDIBs = true; - for(int i = 0; i < data[currentPos]-2; i++) + + for (int i = 0; i < data[currentPos] - 2; i++) { - if(data[currentPos+i+2] == 0) continue; - if(data[currentPos+i+2] > REQUESTED_DIBS_MAX) + 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; } + currentPos += data[currentPos]; }; } @@ -52,7 +60,9 @@ IpHostProtocolAddressInformation& KnxIpSearchRequestExtended::hpai() bool KnxIpSearchRequestExtended::requestedDIB(uint8_t code) { - if(code > REQUESTED_DIBS_MAX) return false; + if (code > REQUESTED_DIBS_MAX) + return false; + return requestedDIBs[code]; } #endif diff --git a/src/knx/knx_ip_search_request_extended.h b/src/knx/knx_ip_search_request_extended.h index 6d019d4f..91ca7023 100644 --- a/src/knx/knx_ip_search_request_extended.h +++ b/src/knx/knx_ip_search_request_extended.h @@ -8,19 +8,19 @@ #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 + 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 }; #endif #endif \ No newline at end of file diff --git a/src/knx/knx_ip_search_response.cpp b/src/knx/knx_ip_search_response.cpp index 508617d1..2a76610a 100644 --- a/src/knx/knx_ip_search_response.cpp +++ b/src/knx/knx_ip_search_response.cpp @@ -3,17 +3,17 @@ #define LEN_SERVICE_FAMILIES 2 #if MASK_VERSION == 0x091A -#ifdef KNX_TUNNELING -#define LEN_SERVICE_DIB (2 + 4 * LEN_SERVICE_FAMILIES) + #ifdef KNX_TUNNELING + #define LEN_SERVICE_DIB (2 + 4 * LEN_SERVICE_FAMILIES) + #else + #define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) + #endif #else -#define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) -#endif -#else -#ifdef KNX_TUNNELING -#define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) -#else -#define LEN_SERVICE_DIB (2 + 2 * LEN_SERVICE_FAMILIES) -#endif + #ifdef KNX_TUNNELING + #define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) + #else + #define LEN_SERVICE_DIB (2 + 2 * LEN_SERVICE_FAMILIES) + #endif #endif KnxIpSearchResponse::KnxIpSearchResponse(IpParameterObject& parameters, DeviceObject& deviceObject) @@ -46,7 +46,7 @@ KnxIpSearchResponse::KnxIpSearchResponse(IpParameterObject& parameters, DeviceOb 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); diff --git a/src/knx/knx_ip_search_response.h b/src/knx/knx_ip_search_response.h index 056f9755..33bda870 100644 --- a/src/knx/knx_ip_search_response.h +++ b/src/knx/knx_ip_search_response.h @@ -10,15 +10,15 @@ class KnxIpSearchResponse : public KnxIpFrame { - public: - KnxIpSearchResponse(IpParameterObject& parameters, DeviceObject& deviceObj); - IpHostProtocolAddressInformation& controlEndpoint(); - KnxIpDeviceInformationDIB& deviceInfo(); - KnxIpSupportedServiceDIB& supportedServices(); - private: - IpHostProtocolAddressInformation _controlEndpoint; - KnxIpDeviceInformationDIB _deviceInfo; - KnxIpSupportedServiceDIB _supportedServices; + public: + KnxIpSearchResponse(IpParameterObject& parameters, DeviceObject& deviceObj); + IpHostProtocolAddressInformation& controlEndpoint(); + KnxIpDeviceInformationDIB& deviceInfo(); + KnxIpSupportedServiceDIB& supportedServices(); + private: + IpHostProtocolAddressInformation _controlEndpoint; + KnxIpDeviceInformationDIB _deviceInfo; + KnxIpSupportedServiceDIB _supportedServices; }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_search_response_extended.cpp b/src/knx/knx_ip_search_response_extended.cpp index eae2182f..c6245321 100644 --- a/src/knx/knx_ip_search_response_extended.cpp +++ b/src/knx/knx_ip_search_response_extended.cpp @@ -5,17 +5,17 @@ #define LEN_SERVICE_FAMILIES 2 #if MASK_VERSION == 0x091A -#ifdef KNX_TUNNELING -#define LEN_SERVICE_DIB (2 + 4 * LEN_SERVICE_FAMILIES) + #ifdef KNX_TUNNELING + #define LEN_SERVICE_DIB (2 + 4 * LEN_SERVICE_FAMILIES) + #else + #define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) + #endif #else -#define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) -#endif -#else -#ifdef KNX_TUNNELING -#define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) -#else -#define LEN_SERVICE_DIB (2 + 2 * LEN_SERVICE_FAMILIES) -#endif + #ifdef KNX_TUNNELING + #define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) + #else + #define LEN_SERVICE_DIB (2 + 2 * LEN_SERVICE_FAMILIES) + #endif #endif KnxIpSearchResponseExtended::KnxIpSearchResponseExtended(IpParameterObject& parameters, DeviceObject& deviceObject, int dibLength) @@ -54,7 +54,7 @@ void KnxIpSearchResponseExtended::setDeviceInfo(IpParameterObject& parameters, D 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); @@ -122,12 +122,12 @@ void KnxIpSearchResponseExtended::setKnxAddresses(IpParameterObject& parameters, uint16_t length = 0; parameters.readPropertyLength(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, length); - const uint8_t *addresses = parameters.propertyData(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES); + const uint8_t* addresses = parameters.propertyData(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES); - for(int i = 0; i < length; i++) + for (int i = 0; i < length; i++) { uint16_t additional = 0; - popWord(additional, addresses + i*2); + popWord(additional, addresses + i * 2); _knxAddresses.additional(additional); } @@ -144,43 +144,49 @@ void KnxIpSearchResponseExtended::setTunnelingInfo(IpParameterObject& parameters uint16_t length = 0; parameters.readPropertyLength(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, length); - - const uint8_t *addresses; - if(length == KNX_TUNNELING) + + const uint8_t* addresses; + + if (length == KNX_TUNNELING) { addresses = parameters.propertyData(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES); - } else { - uint8_t addrbuffer[KNX_TUNNELING*2]; + } + else + { + uint8_t addrbuffer[KNX_TUNNELING * 2]; addresses = (uint8_t*)addrbuffer; - for(int i = 0; i < KNX_TUNNELING; i++) + + for (int i = 0; i < KNX_TUNNELING; i++) { - addrbuffer[i*2+1] = i+1; - addrbuffer[i*2] = deviceObject.individualAddress() / 0x0100; + addrbuffer[i * 2 + 1] = i + 1; + addrbuffer[i * 2] = deviceObject.individualAddress() / 0x0100; } } - for(int i = 0; i < length; i++) + for (int i = 0; i < length; i++) { uint16_t additional = 0; - popWord(additional, addresses + i*2); + popWord(additional, addresses + i * 2); uint16_t flags = 0; uint8_t doubleCounter = 0; bool used = false; - for(int i = 0; i < KNX_TUNNELING; i++) + + for (int i = 0; i < KNX_TUNNELING; i++) { - if(tunnels[i].IndividualAddress == additional) + if (tunnels[i].IndividualAddress == additional) { doubleCounter += 1; - if(tunnels[i].ChannelId != 0) + + if (tunnels[i].ChannelId != 0) used = true; } } - if(doubleCounter > 1 && used) + if (doubleCounter > 1 && used) flags |= 1 << 2; //Slot is not usable; double PA is already used - if(used) + if (used) { flags |= 1 << 2; //Slot is not usable; PA is already used flags |= 1; //Slot is not free @@ -213,7 +219,7 @@ IpHostProtocolAddressInformation& KnxIpSearchResponseExtended::controlEndpoint() } -uint8_t *KnxIpSearchResponseExtended::DIBs() +uint8_t* KnxIpSearchResponseExtended::DIBs() { return _data + LEN_KNXIP_HEADER + LEN_IPHPAI; } diff --git a/src/knx/knx_ip_search_response_extended.h b/src/knx/knx_ip_search_response_extended.h index c7d37935..e0d8f8b3 100644 --- a/src/knx/knx_ip_search_response_extended.h +++ b/src/knx/knx_ip_search_response_extended.h @@ -17,21 +17,21 @@ 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; + 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; }; #endif diff --git a/src/knx/knx_ip_state_request.h b/src/knx/knx_ip_state_request.h index 26cab9bf..99e74d22 100644 --- a/src/knx/knx_ip_state_request.h +++ b/src/knx/knx_ip_state_request.h @@ -6,12 +6,12 @@ #ifdef USE_IP class KnxIpStateRequest : public KnxIpFrame { - public: - KnxIpStateRequest(uint8_t* data, uint16_t length); - IpHostProtocolAddressInformation& hpaiCtrl(); - uint8_t channelId(); - private: - IpHostProtocolAddressInformation _hpaiCtrl; + public: + KnxIpStateRequest(uint8_t* data, uint16_t length); + IpHostProtocolAddressInformation& hpaiCtrl(); + uint8_t channelId(); + private: + IpHostProtocolAddressInformation _hpaiCtrl; }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_state_response.cpp b/src/knx/knx_ip_state_response.cpp index bfb8871f..8f7b286a 100644 --- a/src/knx/knx_ip_state_response.cpp +++ b/src/knx/knx_ip_state_response.cpp @@ -3,17 +3,17 @@ #define LEN_SERVICE_FAMILIES 2 #if MASK_VERSION == 0x091A -#ifdef KNX_TUNNELING -#define LEN_SERVICE_DIB (2 + 4 * LEN_SERVICE_FAMILIES) + #ifdef KNX_TUNNELING + #define LEN_SERVICE_DIB (2 + 4 * LEN_SERVICE_FAMILIES) + #else + #define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) + #endif #else -#define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) -#endif -#else -#ifdef KNX_TUNNELING -#define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) -#else -#define LEN_SERVICE_DIB (2 + 2 * LEN_SERVICE_FAMILIES) -#endif + #ifdef KNX_TUNNELING + #define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES) + #else + #define LEN_SERVICE_DIB (2 + 2 * LEN_SERVICE_FAMILIES) + #endif #endif KnxIpStateResponse::KnxIpStateResponse(uint8_t channelId, uint8_t errorCode) diff --git a/src/knx/knx_ip_state_response.h b/src/knx/knx_ip_state_response.h index 253de4d8..d8829be6 100644 --- a/src/knx/knx_ip_state_response.h +++ b/src/knx/knx_ip_state_response.h @@ -5,9 +5,9 @@ class KnxIpStateResponse : public KnxIpFrame { - public: - KnxIpStateResponse(uint8_t channelId, uint8_t errorCode); - private: + public: + KnxIpStateResponse(uint8_t channelId, uint8_t errorCode); + private: }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_supported_service_dib.cpp b/src/knx/knx_ip_supported_service_dib.cpp index a4afbd4b..4647ca80 100644 --- a/src/knx/knx_ip_supported_service_dib.cpp +++ b/src/knx/knx_ip_supported_service_dib.cpp @@ -15,6 +15,7 @@ uint8_t KnxIpSupportedServiceDIB::serviceVersion(ServiceFamily family) if (*it == family) return it[1]; } + return 0; } diff --git a/src/knx/knx_ip_supported_service_dib.h b/src/knx/knx_ip_supported_service_dib.h index 97cd974e..c7b57c01 100644 --- a/src/knx/knx_ip_supported_service_dib.h +++ b/src/knx/knx_ip_supported_service_dib.h @@ -15,9 +15,9 @@ enum ServiceFamily : uint8_t class KnxIpSupportedServiceDIB : public KnxIpDIB { - public: - KnxIpSupportedServiceDIB(uint8_t* data); - uint8_t serviceVersion(ServiceFamily family); - void serviceVersion(ServiceFamily family, uint8_t version); + public: + KnxIpSupportedServiceDIB(uint8_t* data); + uint8_t serviceVersion(ServiceFamily family); + void serviceVersion(ServiceFamily family, uint8_t version); }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_tunnel_connection.h b/src/knx/knx_ip_tunnel_connection.h index e1323adf..6196e320 100644 --- a/src/knx/knx_ip_tunnel_connection.h +++ b/src/knx/knx_ip_tunnel_connection.h @@ -5,20 +5,20 @@ 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; + 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 diff --git a/src/knx/knx_ip_tunneling_ack.cpp b/src/knx/knx_ip_tunneling_ack.cpp index b17ae356..9e9981d5 100644 --- a/src/knx/knx_ip_tunneling_ack.cpp +++ b/src/knx/knx_ip_tunneling_ack.cpp @@ -2,8 +2,8 @@ #include #ifdef USE_IP -KnxIpTunnelingAck::KnxIpTunnelingAck(uint8_t* data, - uint16_t length) : KnxIpFrame(data, length), _ch(_data + LEN_KNXIP_HEADER) +KnxIpTunnelingAck::KnxIpTunnelingAck(uint8_t* data, + uint16_t length) : KnxIpFrame(data, length), _ch(_data + LEN_KNXIP_HEADER) { } diff --git a/src/knx/knx_ip_tunneling_ack.h b/src/knx/knx_ip_tunneling_ack.h index 8ef0983a..da2fc6ba 100644 --- a/src/knx/knx_ip_tunneling_ack.h +++ b/src/knx/knx_ip_tunneling_ack.h @@ -7,11 +7,11 @@ class KnxIpTunnelingAck : public KnxIpFrame { - public: - KnxIpTunnelingAck(uint8_t* data, uint16_t length); - KnxIpTunnelingAck(); - KnxIpCH& connectionHeader(); - private: - KnxIpCH _ch; + public: + KnxIpTunnelingAck(uint8_t* data, uint16_t length); + KnxIpTunnelingAck(); + KnxIpCH& connectionHeader(); + private: + KnxIpCH _ch; }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_tunneling_info_dib.cpp b/src/knx/knx_ip_tunneling_info_dib.cpp index ef5b4ef1..daafa60e 100644 --- a/src/knx/knx_ip_tunneling_info_dib.cpp +++ b/src/knx/knx_ip_tunneling_info_dib.cpp @@ -11,13 +11,13 @@ KnxIpTunnelingInfoDIB::KnxIpTunnelingInfoDIB(uint8_t* data) : KnxIpDIB(data) uint16_t KnxIpTunnelingInfoDIB::apduLength() { uint16_t addr = 0; - popWord(addr, _data+2); + popWord(addr, _data + 2); return addr; } void KnxIpTunnelingInfoDIB::apduLength(uint16_t addr) { - pushWord(addr, _data+2); + pushWord(addr, _data + 2); } void KnxIpTunnelingInfoDIB::tunnelingSlot(uint16_t addr, uint16_t state) diff --git a/src/knx/knx_ip_tunneling_info_dib.h b/src/knx/knx_ip_tunneling_info_dib.h index 77d63fd6..10aa55cd 100644 --- a/src/knx/knx_ip_tunneling_info_dib.h +++ b/src/knx/knx_ip_tunneling_info_dib.h @@ -8,13 +8,13 @@ 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; + 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; }; #endif #endif \ No newline at end of file diff --git a/src/knx/knx_ip_tunneling_request.cpp b/src/knx/knx_ip_tunneling_request.cpp index 452fbfcc..c7b35641 100644 --- a/src/knx/knx_ip_tunneling_request.cpp +++ b/src/knx/knx_ip_tunneling_request.cpp @@ -2,8 +2,8 @@ #include #ifdef USE_IP -KnxIpTunnelingRequest::KnxIpTunnelingRequest(uint8_t* data, - uint16_t length) : KnxIpFrame(data, length), _ch(_data + headerLength()), _frame(data + LEN_CH + headerLength(), length - LEN_CH - headerLength()) +KnxIpTunnelingRequest::KnxIpTunnelingRequest(uint8_t* data, + uint16_t length) : KnxIpFrame(data, length), _ch(_data + headerLength()), _frame(data + LEN_CH + headerLength(), length - LEN_CH - headerLength()) { } diff --git a/src/knx/knx_ip_tunneling_request.h b/src/knx/knx_ip_tunneling_request.h index 1373eb7a..5ac8099e 100644 --- a/src/knx/knx_ip_tunneling_request.h +++ b/src/knx/knx_ip_tunneling_request.h @@ -7,13 +7,13 @@ class KnxIpTunnelingRequest : public KnxIpFrame { - public: - KnxIpTunnelingRequest(uint8_t* data, uint16_t length); - KnxIpTunnelingRequest(CemiFrame frame); - CemiFrame& frame(); - KnxIpCH& connectionHeader(); - private: - CemiFrame _frame; - KnxIpCH _ch; + public: + KnxIpTunnelingRequest(uint8_t* data, uint16_t length); + KnxIpTunnelingRequest(CemiFrame frame); + CemiFrame& frame(); + KnxIpCH& connectionHeader(); + private: + CemiFrame _frame; + KnxIpCH _ch; }; #endif \ No newline at end of file diff --git a/src/knx/knx_types.h b/src/knx/knx_types.h index ecbbd970..9e8afead 100644 --- a/src/knx/knx_types.h +++ b/src/knx/knx_types.h @@ -50,14 +50,14 @@ enum MessageCode M_PropInfo_ind = 0xF7, // 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) + 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) - // Further cEMI servies - M_Reset_req = 0xF1, - M_Reset_ind = 0xF0, + // Further cEMI servies + M_Reset_req = 0xF1, + M_Reset_ind = 0xF0, }; enum cEmiErrorCode @@ -140,7 +140,7 @@ enum TpduType enum ApduType { - // Application Layer services on Multicast Communication Mode + // Application Layer services on Multicast Communication Mode GroupValueRead = 0x000, GroupValueResponse = 0x040, GroupValueWrite = 0x080, @@ -165,7 +165,7 @@ enum ApduType DomainAddressSerialNumberRead = 0x3ec, DomainAddressSerialNumberResponse = 0x3ed, DomainAddressSerialNumberWrite = 0x3ee, - + // 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, diff --git a/src/knx/knx_value.cpp b/src/knx/knx_value.cpp index 3ab14f92..b671d119 100644 --- a/src/knx/knx_value.cpp +++ b/src/knx/knx_value.cpp @@ -126,7 +126,7 @@ KNXValue::operator double() const return doubleValue(); } -KNXValue::operator const char*() const +KNXValue::operator const char* () const { return stringValue(); } @@ -226,6 +226,7 @@ bool KNXValue::boolValue() const { case BoolType: return _value.boolValue; + case UCharType: case UShortType: case UIntType: @@ -236,11 +237,14 @@ bool KNXValue::boolValue() const 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; } + return 0; } @@ -250,12 +254,14 @@ uint8_t KNXValue::ucharValue() const { 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: @@ -264,6 +270,7 @@ uint8_t KNXValue::ucharValue() const case StringType: return (uint8_t)longValue(); } + return 0; } @@ -273,12 +280,14 @@ uint16_t KNXValue::ushortValue() const { 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: @@ -287,6 +296,7 @@ uint16_t KNXValue::ushortValue() const case StringType: return (uint16_t)longValue(); } + return 0; } @@ -296,12 +306,14 @@ uint32_t KNXValue::uintValue() const { 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: @@ -310,6 +322,7 @@ uint32_t KNXValue::uintValue() const case StringType: return (uint32_t)longValue(); } + return 0; } @@ -319,29 +332,40 @@ uint64_t KNXValue::ulongValue() const { case ULongType: return _value.ulongValue; + case BoolType: return _value.boolValue ? 1 : 0; + case UCharType: return (uint64_t)_value.ucharValue; + case UShortType: return (uint64_t)_value.ushortValue; + case UIntType: return (uint64_t)_value.uintValue; + case TimeType: { struct tm* timeptr = const_cast(&_value.timeValue); return (uint64_t)mktime(timeptr); } + case CharType: return (uint64_t)_value.charValue; + case ShortType: return (uint64_t)_value.shortValue; + case IntType: return (uint64_t)_value.intValue; + case LongType: return (uint64_t)_value.longValue; + case DoubleType: return (uint64_t)_value.doubleValue; + case StringType: #ifndef KNX_NO_STRTOx_CONVERSION return (uint64_t)strtoul(_value.stringValue, NULL, 0); @@ -349,6 +373,7 @@ uint64_t KNXValue::ulongValue() const return 0; #endif } + return 0; } @@ -358,6 +383,7 @@ int8_t KNXValue::charValue() const { case CharType: return _value.charValue; + case BoolType: case UCharType: case UShortType: @@ -365,6 +391,7 @@ int8_t KNXValue::charValue() const case ULongType: case TimeType: return (int8_t)ulongValue(); + case ShortType: case IntType: case LongType: @@ -372,6 +399,7 @@ int8_t KNXValue::charValue() const case StringType: return (int8_t)longValue(); } + return 0; } @@ -381,6 +409,7 @@ int16_t KNXValue::shortValue() const { case ShortType: return _value.shortValue; + case BoolType: case UCharType: case UShortType: @@ -388,6 +417,7 @@ int16_t KNXValue::shortValue() const case ULongType: case TimeType: return (int16_t)ulongValue(); + case CharType: case IntType: case LongType: @@ -395,6 +425,7 @@ int16_t KNXValue::shortValue() const case StringType: return (int16_t)longValue(); } + return 0; } @@ -404,6 +435,7 @@ int32_t KNXValue::intValue() const { case IntType: return _value.ulongValue; + case BoolType: case UCharType: case UShortType: @@ -411,6 +443,7 @@ int32_t KNXValue::intValue() const case ULongType: case TimeType: return (int32_t)ulongValue(); + case CharType: case ShortType: case LongType: @@ -418,6 +451,7 @@ int32_t KNXValue::intValue() const case StringType: return (int32_t)longValue(); } + return 0; } @@ -427,26 +461,37 @@ int64_t KNXValue::longValue() const { case LongType: return _value.longValue; + case BoolType: return _value.boolValue ? 1 : 0; + case UCharType: return (int64_t)_value.ucharValue; + case UShortType: return (int64_t)_value.ushortValue; + case UIntType: return (int64_t)_value.uintValue; + case ULongType: return (int64_t)_value.uintValue; + case TimeType: return (int64_t)ulongValue(); + case CharType: return (int64_t)_value.charValue; + case ShortType: return (int64_t)_value.shortValue; + case IntType: return (int64_t)_value.intValue; + case DoubleType: return (int64_t)_value.doubleValue; + case StringType: #ifndef KNX_NO_STRTOx_CONVERSION return strtol(_value.stringValue, NULL, 0); @@ -454,6 +499,7 @@ int64_t KNXValue::longValue() const return 0; #endif } + return 0; } @@ -463,26 +509,37 @@ double KNXValue::doubleValue() const { case DoubleType: return _value.doubleValue; - case BoolType: + + case BoolType: return _value.boolValue ? 1 : 0; + case UCharType: return _value.ucharValue; + case UShortType: return _value.ushortValue; + case UIntType: return _value.uintValue; + case ULongType: return _value.uintValue; + case TimeType: return ulongValue(); + case CharType: return _value.charValue; + case ShortType: return _value.shortValue; + case IntType: return _value.intValue; + case LongType: return _value.longValue; + case StringType: #ifndef KNX_NO_STRTOx_CONVERSION return strtod(_value.stringValue, NULL); @@ -490,6 +547,7 @@ double KNXValue::doubleValue() const return 0; #endif } + return 0; } @@ -509,9 +567,11 @@ const char* KNXValue::stringValue() const case IntType: case LongType: return ""; // we would have to manage the memory for the string otherwise. Maybe later. + case StringType: return _value.stringValue; } + return 0; } @@ -521,6 +581,7 @@ struct tm KNXValue::timeValue() const { case TimeType: return _value.timeValue; + case BoolType: case UCharType: case UShortType: @@ -539,7 +600,9 @@ struct tm KNXValue::timeValue() const return timeStruct; } } + struct tm tmp = {0}; + return tmp; } diff --git a/src/knx/knx_value.h b/src/knx/knx_value.h index b59c6cfa..34435633 100644 --- a/src/knx/knx_value.h +++ b/src/knx/knx_value.h @@ -5,95 +5,95 @@ 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); + 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; + ValueType _type; + Value _value; }; \ No newline at end of file diff --git a/src/knx/memory.cpp b/src/knx/memory.cpp index 2cedf476..a09eb55c 100644 --- a/src/knx/memory.cpp +++ b/src/knx/memory.cpp @@ -17,6 +17,7 @@ void Memory::readMemory() uint8_t* flashStart = _platform.getNonVolatileMemoryStart(); size_t flashSize = _platform.getNonVolatileMemorySize(); + if (flashStart == nullptr) { println("no user flash available;"); @@ -44,24 +45,26 @@ void Memory::readMemory() VersionCheckResult versionCheck = FlashAllInvalid; // first check correct format of deviceObject-API - if (_deviceObject.apiVersion == apiVersion) + if (_deviceObject.apiVersion == apiVersion) { - if (_versionCheckCallback != 0) { + 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) + memcmp(_deviceObject.hardwareType(), hardwareType, LEN_HARDWARE_TYPE) == 0) { - if (_deviceObject.version() == version) { + if (_deviceObject.version() == version) + { versionCheck = FlashValid; - } + } else { versionCheck = FlashTablesInvalid; } - } - else + } + else { println("manufacturerId or hardwareType are different"); print("expexted manufacturerId: "); @@ -74,8 +77,8 @@ void Memory::readMemory() printHex("", hardwareType, LEN_HARDWARE_TYPE); println(""); } - } - else + } + else { println("DataObject api changed, any data stored in flash is invalid."); print("expexted DataObject api version: "); @@ -93,20 +96,25 @@ void Memory::readMemory() println("restoring data from flash..."); print("saverestores "); println(_saveCount); + for (int i = 0; i < _saveCount; i++) { println(flashStart - buffer); println("."); buffer = _saveRestores[i]->restore(buffer); } + println("restored saveRestores"); - if (versionCheck == FlashTablesInvalid) + + if (versionCheck == FlashTablesInvalid) { println("TableObjects are referring to an older firmware version and are not loaded"); return; } + print("tableObjs "); println(_tableObjCount); + for (int i = 0; i < _tableObjCount; i++) { println(flashStart - buffer); @@ -115,12 +123,14 @@ void Memory::readMemory() uint16_t memorySize = 0; buffer = popWord(memorySize, buffer); println(memorySize); + if (memorySize == 0) continue; // this works because TableObject saves a relative addr and restores it itself addNewUsedBlock(_tableObjects[i]->_data, memorySize); } + println("restored Tableobjects"); } @@ -128,12 +138,13 @@ void Memory::writeMemory() { // first get the necessary size of the writeBuffer uint16_t writeBufferSize = _metadataSize; + for (int i = 0; i < _saveCount; i++) writeBufferSize = MAX(writeBufferSize, _saveRestores[i]->saveSize()); for (int i = 0; i < _tableObjCount; i++) writeBufferSize = MAX(writeBufferSize, _tableObjects[i]->saveSize() + 2 /*for memory pos*/); - + uint8_t buffer[writeBufferSize]; uint32_t flashPos = 0; uint8_t* bufferPos = buffer; @@ -147,6 +158,7 @@ void Memory::writeMemory() print("save saveRestores "); println(_saveCount); + for (int i = 0; i < _saveCount; i++) { bufferPos = _saveRestores[i]->save(buffer); @@ -155,6 +167,7 @@ void Memory::writeMemory() print("save tableobjs "); println(_tableObjCount); + for (int i = 0; i < _tableObjCount; i++) { bufferPos = _tableObjects[i]->save(buffer); @@ -163,11 +176,13 @@ void Memory::writeMemory() if (_tableObjects[i]->_data != nullptr) { MemoryBlock* block = findBlockInList(_usedList, _tableObjects[i]->_data); + if (block == nullptr) { println("_data of TableObject not in _usedList"); _platform.fatalError(); } + bufferPos = pushWord(block->size, bufferPos); } else @@ -175,7 +190,7 @@ void Memory::writeMemory() flashPos = _platform.writeNonVolatileMemory(flashPos, buffer, bufferPos - buffer); } - + _platform.commitNonVolatileMemory(); } @@ -212,7 +227,7 @@ uint8_t* Memory::allocMemory(size_t size) MemoryBlock* freeBlock = _freeList; MemoryBlock* blockToUse = nullptr; - + // find the smallest possible block that is big enough while (freeBlock) { @@ -223,8 +238,10 @@ uint8_t* Memory::allocMemory(size_t size) else if (blockToUse == nullptr) blockToUse = freeBlock; } + freeBlock = freeBlock->next; } + if (!blockToUse) { println("No available non volatile memory!"); @@ -256,6 +273,7 @@ void Memory::freeMemory(uint8_t* ptr) { MemoryBlock* block = _usedList; MemoryBlock* found = nullptr; + while (block) { if (block->address == ptr) @@ -263,13 +281,16 @@ void Memory::freeMemory(uint8_t* ptr) found = block; break; } + block = block->next; } - if(!found) + + if (!found) { println("freeMemory for not used pointer called"); _platform.fatalError(); } + removeFromUsedList(block); addToFreeList(block); } @@ -313,6 +334,7 @@ MemoryBlock* Memory::removeFromList(MemoryBlock* head, MemoryBlock* item) bool found = false; MemoryBlock* block = head; + while (block) { if (block->next == item) @@ -321,6 +343,7 @@ MemoryBlock* Memory::removeFromList(MemoryBlock* head, MemoryBlock* item) block->next = item->next; break; } + block = block->next; } @@ -329,6 +352,7 @@ MemoryBlock* Memory::removeFromList(MemoryBlock* head, MemoryBlock* item) println("tried to remove block from list not in it"); _platform.fatalError(); } + item->next = nullptr; return head; } @@ -362,6 +386,7 @@ void Memory::addToFreeList(MemoryBlock* block) // first insert free block in list MemoryBlock* current = _freeList; + while (current) { if (current->address <= block->address && (current->next == nullptr || block->address < current->next->address)) @@ -389,6 +414,7 @@ void Memory::addToFreeList(MemoryBlock* block) current = current->next; } + // now check if we can merge the blocks // first current an block if ((current->address + current->size) == block->address) @@ -400,7 +426,7 @@ void Memory::addToFreeList(MemoryBlock* block) block = current; } - // if block is the last one, we are done + // if block is the last one, we are done if (block->next == nullptr) return; @@ -417,7 +443,7 @@ 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); + return (size + pageSize - 1) & (-1 * pageSize); } MemoryBlock* Memory::findBlockInList(MemoryBlock* head, uint8_t* address) @@ -429,19 +455,21 @@ MemoryBlock* Memory::findBlockInList(MemoryBlock* head, uint8_t* address) head = head->next; } + return nullptr; } void Memory::addNewUsedBlock(uint8_t* address, size_t size) { MemoryBlock* smallerFreeBlock = _freeList; + // 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)) + (smallerFreeBlock->next != nullptr && smallerFreeBlock->next->address > address)) break; - + smallerFreeBlock = smallerFreeBlock->next; } diff --git a/src/knx/memory.h b/src/knx/memory.h index f0c2298b..6ac17574 100644 --- a/src/knx/memory.h +++ b/src/knx/memory.h @@ -10,18 +10,18 @@ #define MAXTABLEOBJ 4 #ifndef KNX_FLASH_SIZE -#define KNX_FLASH_SIZE 1024 + #define KNX_FLASH_SIZE 1024 #endif 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; + 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 @@ -35,50 +35,50 @@ typedef VersionCheckResult (*VersionCheckCallback)(uint16_t manufacturerId, uint class Memory { - friend class TableObject; + 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 }; diff --git a/src/knx/network_layer.cpp b/src/knx/network_layer.cpp index 05f8aac8..13847512 100644 --- a/src/knx/network_layer.cpp +++ b/src/knx/network_layer.cpp @@ -6,7 +6,7 @@ #include "bits.h" #include "apdu.h" -NetworkLayer::NetworkLayer(DeviceObject &deviceObj, TransportLayer& layer) : +NetworkLayer::NetworkLayer(DeviceObject& deviceObj, TransportLayer& layer) : _deviceObj(deviceObj), _transportLayer(layer) { @@ -26,6 +26,7 @@ bool NetworkLayer::isApciSystemBroadcast(APDU& apdu) case SystemNetworkParameterRead: case SystemNetworkParameterResponse: case SystemNetworkParameterWrite: + // Open media specific Application Layer Services on System Broadcast communication mode case DomainAddressSerialNumberRead: case DomainAddressSerialNumberResponse: @@ -35,9 +36,11 @@ bool NetworkLayer::isApciSystemBroadcast(APDU& apdu) case DomainAddressResponse: case DomainAddressWrite: return true; + default: return false; } + return false; } diff --git a/src/knx/network_layer.h b/src/knx/network_layer.h index e12c8460..28be8d61 100644 --- a/src/knx/network_layer.h +++ b/src/knx/network_layer.h @@ -11,36 +11,36 @@ 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) + 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) }; diff --git a/src/knx/network_layer_coupler.cpp b/src/knx/network_layer_coupler.cpp index bcfe68df..6583e83c 100644 --- a/src/knx/network_layer_coupler.cpp +++ b/src/knx/network_layer_coupler.cpp @@ -6,8 +6,8 @@ #include "cemi_frame.h" #include "bits.h" -NetworkLayerCoupler::NetworkLayerCoupler(DeviceObject &deviceObj, - TransportLayer& layer) : +NetworkLayerCoupler::NetworkLayerCoupler(DeviceObject& deviceObj, + TransportLayer& layer) : NetworkLayer(deviceObj, layer), _netLayerEntities { {*this, kPrimaryIfIndex}, {*this, kSecondaryIfIndex} } { @@ -62,25 +62,25 @@ void NetworkLayerCoupler::evaluateCouplerType() 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; - } -*/ + /* + 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; + return (_rtObjPrimary != nullptr) ? _rtObjPrimary->isGroupAddressInFilterTable(groupAddress) : false; else { return _rtObjSecondary->isGroupAddressInFilterTable(groupAddress); @@ -94,7 +94,7 @@ bool NetworkLayerCoupler::isRoutedGroupAddress(uint16_t groupAddress, uint8_t so Property* prop_lcgrpconfig; Property* prop_lcconfig; - if(sourceInterfaceIndex == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP) + if (sourceInterfaceIndex == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP) { prop_lcgrpconfig = _rtObjPrimary->property(PID_MAIN_LCGRPCONFIG); prop_lcconfig = _rtObjPrimary->property(PID_MAIN_LCCONFIG); @@ -104,31 +104,35 @@ bool NetworkLayerCoupler::isRoutedGroupAddress(uint16_t groupAddress, uint8_t so prop_lcgrpconfig = _rtObjPrimary->property(PID_SUB_LCGRPCONFIG); prop_lcconfig = _rtObjPrimary->property(PID_SUB_LCCONFIG); } - if(prop_lcgrpconfig) + + if (prop_lcgrpconfig) prop_lcgrpconfig->read(lcgrpconfig); - if(prop_lcconfig) + if (prop_lcconfig) prop_lcconfig->read(lcconfig); - if(groupAddress < 0x7000) // Main group 0-13 + if (groupAddress < 0x7000) // Main group 0-13 { // PID_SUB_LCGRPCONFIG Bit 0-1 - switch(lcgrpconfig & LCGRPCONFIG::GROUP_6FFF) + 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)) + if (isGroupAddressInFilterTable(groupAddress)) ;//send else { //printHex("2drop frame to 0x", (uint8_t*)destination, 2); return false;//drop } - break; + + break; + default: // LCGRPCONFIG::GROUP_6FFFUNLOCK ;//send } @@ -136,21 +140,24 @@ bool NetworkLayerCoupler::isRoutedGroupAddress(uint16_t groupAddress, uint8_t so else // Main group 14-31 { // PID_SUB_LCGRPCONFIG Bit 2-3 LCGRPCONFIG::GROUP_7000 - switch(lcgrpconfig & 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)) + if (isGroupAddressInFilterTable(groupAddress)) ;//send else { //printHex("4drop frame to 0x", (uint8_t*)destination, 2); return false;//drop } - break; + + break; + default: // LCGRPCONFIG::GROUP_7000UNLOCK ;//send } @@ -193,6 +200,7 @@ bool NetworkLayerCoupler::isRoutedIndividualAddress(uint16_t individualAddress, // IGNORE_TOTALLY return false; } + return true; } else if (srcIfIndex == kSecondaryIfIndex) // Sub line to main line routing @@ -250,7 +258,7 @@ bool NetworkLayerCoupler::isRoutedIndividualAddress(uint16_t individualAddress, } void NetworkLayerCoupler::sendMsgHopCount(AckType ack, AddressType addrType, uint16_t destination, NPDU& npdu, Priority priority, - SystemBroadcast broadcastType, uint8_t sourceInterfaceIndex, uint16_t source) + SystemBroadcast broadcastType, uint8_t sourceInterfaceIndex, uint16_t source) { uint8_t interfaceIndex = (sourceInterfaceIndex == kSecondaryIfIndex) ? kPrimaryIfIndex : kSecondaryIfIndex; @@ -259,7 +267,7 @@ void NetworkLayerCoupler::sendMsgHopCount(AckType ack, AddressType addrType, uin Property* prop_lcgrpconfig; Property* prop_lcconfig; - if(sourceInterfaceIndex == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP) + if (sourceInterfaceIndex == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP) { prop_lcgrpconfig = _rtObjPrimary->property(PID_MAIN_LCGRPCONFIG); prop_lcconfig = _rtObjPrimary->property(PID_MAIN_LCCONFIG); @@ -269,16 +277,17 @@ void NetworkLayerCoupler::sendMsgHopCount(AckType ack, AddressType addrType, uin prop_lcgrpconfig = _rtObjPrimary->property(PID_SUB_LCGRPCONFIG); prop_lcconfig = _rtObjPrimary->property(PID_SUB_LCCONFIG); } - if(prop_lcgrpconfig) + + if (prop_lcgrpconfig) prop_lcgrpconfig->read(lcgrpconfig); - if(prop_lcconfig) + if (prop_lcconfig) prop_lcconfig->read(lcconfig); - - - if(addrType == AddressType::GroupAddress && destination != 0) // destination == 0 means broadcast and must not be filtered with the GroupAddresses + + + if (addrType == AddressType::GroupAddress && destination != 0) // destination == 0 means broadcast and must not be filtered with the GroupAddresses { - if(!isRoutedGroupAddress(destination, sourceInterfaceIndex)) + if (!isRoutedGroupAddress(destination, sourceInterfaceIndex)) return; // drop; } @@ -287,9 +296,11 @@ void NetworkLayerCoupler::sendMsgHopCount(AckType ack, AddressType addrType, uin if ((_rtObjPrimary != nullptr) && (_rtObjSecondary != nullptr) && (sourceInterfaceIndex == kSecondaryIfIndex)) { DptMedium mediumType = getSecondaryInterface().mediumType(); + if (mediumType == DptMedium::KNX_RF) // Probably also KNX_PL110, but this is not specified, PL110 is also an open medium { uint16_t hopCount = 0; + if (_rtObjPrimary->property(PID_HOP_COUNT)->read(hopCount) == 1) { npdu.hopCount(hopCount); @@ -303,6 +314,7 @@ void NetworkLayerCoupler::sendMsgHopCount(AckType ack, AddressType addrType, uin // IGNORE_ACKED return; } + if (npdu.hopCount() < 7) { // ROUTE_DECREMENTED @@ -316,22 +328,27 @@ void NetworkLayerCoupler::sendMsgHopCount(AckType ack, AddressType addrType, uin // Use other interface #ifdef KNX_LOG_COUPLER + if (sourceInterfaceIndex == 0) print("Routing from P->S: "); else print("Routing from S->P: "); - print(source, HEX); print(" -> "); print(destination, HEX); + + 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))) + + 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; - + _netLayerEntities[interfaceIndex].sendDataRequest(npdu, ack, destination, source, priority, addrType, broadcastType, doNotRepeat); } @@ -344,7 +361,7 @@ void NetworkLayerCoupler::routeDataIndividual(AckType ack, uint16_t destination, //print(" own addr 0x"); //println(_deviceObj.individualAddress(), HEX); - if(destination == _deviceObj.individualAddress()) + if (destination == _deviceObj.individualAddress()) { // FORWARD_LOCALLY //println("NetworkLayerCoupler::routeDataIndividual locally"); @@ -358,12 +375,13 @@ void NetworkLayerCoupler::routeDataIndividual(AckType ack, uint16_t destination, { uint16_t netaddr; uint16_t Z; - if(_couplerType == CouplerType::BackboneCoupler) + + if (_couplerType == CouplerType::BackboneCoupler) { netaddr = _deviceObj.individualAddress() & 0xF000; Z = destination & 0xF000; } - else if(_couplerType == CouplerType::LineCoupler) + else if (_couplerType == CouplerType::LineCoupler) { netaddr = _deviceObj.individualAddress() & 0xFF00; Z = destination & 0xFF00; @@ -373,14 +391,16 @@ void NetworkLayerCoupler::routeDataIndividual(AckType ack, uint16_t destination, //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; #ifdef KNX_TUNNELING - if(destIfidx == kPrimaryIfIndex) - if(isTunnelAddress(destination)) + + if (destIfidx == kPrimaryIfIndex) + if (isTunnelAddress(destination)) destIfidx = kSecondaryIfIndex; + #endif //print("NetworkLayerCoupler::routeDataIndividual local to s or p: "); //println(destIfidx); @@ -390,20 +410,22 @@ void NetworkLayerCoupler::routeDataIndividual(AckType ack, uint16_t destination, 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) + + 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) + + if (prop_lcconfig) prop_lcconfig->read(lcconfig); - if((lcconfig & LCCONFIG::PHYS_FRAME) == LCCONFIG::PHYS_FRAME_LOCK) + 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) + else if ((lcconfig & LCCONFIG::PHYS_FRAME) == LCCONFIG::PHYS_FRAME_UNLOCK) { // ROUTE_XXX //println("NetworkLayerCoupler::routeDataIndividual unlocked"); @@ -412,7 +434,7 @@ void NetworkLayerCoupler::routeDataIndividual(AckType ack, uint16_t destination, } else // LCCONFIG::PHYS_FRAME_ROUTE or 0 { - if(isRoutedIndividualAddress(destination, srcIfIndex)) + if (isRoutedIndividualAddress(destination, srcIfIndex)) { //println("NetworkLayerCoupler::routeDataIndividual routed"); sendMsgHopCount(ack, AddressType::IndividualAddress, destination, npdu, priority, Broadcast, srcIfIndex, source); // ROUTE_XXX @@ -435,6 +457,7 @@ void NetworkLayerCoupler::dataIndication(AckType ack, AddressType addrType, uint 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 @@ -459,6 +482,7 @@ void NetworkLayerCoupler::dataConfirm(AckType ack, AddressType addrType, uint16_ _transportLayer.dataIndividualConfirm(ack, destination, hopType, priority, npdu.tpdu(), status); return; } + // else: we do not have any local group communication, so do not handle this } @@ -474,7 +498,7 @@ void NetworkLayerCoupler::broadcastIndication(AckType ack, FrameFormat format, N // for closed media like TP1 and IP if ( ((mediumType == DptMedium::KNX_TP1) || (mediumType == DptMedium::KNX_IP)) && - isApciSystemBroadcast(npdu.tpdu().apdu())) + isApciSystemBroadcast(npdu.tpdu().apdu())) { npdu.frame().systemBroadcast(SysBroadcast); _transportLayer.dataSystemBroadcastIndication(hopType, priority, source, npdu.tpdu()); @@ -486,15 +510,17 @@ void NetworkLayerCoupler::broadcastIndication(AckType ack, FrameFormat format, N 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) + + 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) + + if (prop_lcconfig) prop_lcconfig->read(lcconfig); // Route to other interface - if(!(lcconfig & LCCONFIG::BROADCAST_LOCK)) + if (!(lcconfig & LCCONFIG::BROADCAST_LOCK)) sendMsgHopCount(ack, GroupAddress, 0, npdu, priority, Broadcast, srcIfIdx, source); } @@ -505,8 +531,9 @@ void NetworkLayerCoupler::broadcastConfirm(AckType ack, FrameFormat format, Prio // 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); + _transportLayer.dataBroadcastConfirm(ack, hopType, priority, npdu.tpdu(), status); } + // Do not process the frame any further } @@ -517,18 +544,20 @@ void NetworkLayerCoupler::systemBroadcastIndication(AckType ack, FrameFormat for 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) + + 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) + + if (prop_lcconfig) prop_lcconfig->read(lcconfig); // Route to other interface - if(!(lcconfig & LCCONFIG::BROADCAST_LOCK)) + if (!(lcconfig & LCCONFIG::BROADCAST_LOCK)) sendMsgHopCount(ack, GroupAddress, 0, npdu, priority, SysBroadcast, srcIfIdx, source); } @@ -540,6 +569,7 @@ void NetworkLayerCoupler::systemBroadcastConfirm(AckType ack, FrameFormat format HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; _transportLayer.dataSystemBroadcastConfirm(ack, hopType, npdu.tpdu(), priority, status); } + // Do not process the frame any further } @@ -574,6 +604,7 @@ void NetworkLayerCoupler::dataGroupRequest(AckType ack, uint16_t destination, Ho { _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); } diff --git a/src/knx/network_layer_coupler.h b/src/knx/network_layer_coupler.h index 23f714be..75f1694d 100644 --- a/src/knx/network_layer_coupler.h +++ b/src/knx/network_layer_coupler.h @@ -12,69 +12,69 @@ 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); + 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; }; diff --git a/src/knx/network_layer_device.cpp b/src/knx/network_layer_device.cpp index 53e6266f..105003e2 100644 --- a/src/knx/network_layer_device.cpp +++ b/src/knx/network_layer_device.cpp @@ -4,7 +4,7 @@ #include "cemi_frame.h" #include "bits.h" -NetworkLayerDevice::NetworkLayerDevice(DeviceObject &deviceObj, TransportLayer& layer) : +NetworkLayerDevice::NetworkLayerDevice(DeviceObject& deviceObj, TransportLayer& layer) : NetworkLayer(deviceObj, layer), _netLayerEntities { {*this, kInterfaceIndex} } { @@ -96,11 +96,13 @@ void NetworkLayerDevice::dataIndication(AckType ack, AddressType addrType, uint1 void NetworkLayerDevice::dataConfirm(AckType ack, AddressType addressType, uint16_t destination, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) { HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + if (addressType == IndividualAddress) { _transportLayer.dataIndividualConfirm(ack, destination, hopType, priority, npdu.tpdu(), status); return; } + // group-address type if (destination != 0) { @@ -119,7 +121,7 @@ void NetworkLayerDevice::broadcastIndication(AckType ack, FrameFormat format, NP // 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())) + isApciSystemBroadcast(npdu.tpdu().apdu())) { npdu.frame().systemBroadcast(SysBroadcast); _transportLayer.dataSystemBroadcastIndication(hopType, priority, source, npdu.tpdu()); diff --git a/src/knx/network_layer_device.h b/src/knx/network_layer_device.h index 3fdd6b2a..4833dd0e 100644 --- a/src/knx/network_layer_device.h +++ b/src/knx/network_layer_device.h @@ -11,34 +11,34 @@ 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; + 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; }; diff --git a/src/knx/network_layer_entity.cpp b/src/knx/network_layer_entity.cpp index 389f765c..925dd525 100644 --- a/src/knx/network_layer_entity.cpp +++ b/src/knx/network_layer_entity.cpp @@ -4,7 +4,7 @@ #include "data_link_layer.h" #include "bits.h" -NetworkLayerEntity::NetworkLayerEntity(NetworkLayer &netLayer, uint8_t entityIndex) : _netLayer(netLayer), _entityIndex(entityIndex) +NetworkLayerEntity::NetworkLayerEntity(NetworkLayer& netLayer, uint8_t entityIndex) : _netLayer(netLayer), _entityIndex(entityIndex) { } @@ -63,7 +63,7 @@ void NetworkLayerEntity::systemBroadcastConfirm(AckType ack, FrameFormat format, _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) +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; diff --git a/src/knx/network_layer_entity.h b/src/knx/network_layer_entity.h index 22599e4e..0c579c18 100644 --- a/src/knx/network_layer_entity.h +++ b/src/knx/network_layer_entity.h @@ -9,36 +9,36 @@ 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; + 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; }; diff --git a/src/knx/npdu.h b/src/knx/npdu.h index 72f6164d..bfa52ca2 100644 --- a/src/knx/npdu.h +++ b/src/knx/npdu.h @@ -7,21 +7,21 @@ class TPDU; class NPDU { - friend class CemiFrame; + 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(); + 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(); - protected: - NPDU(uint8_t* data, CemiFrame& frame); + protected: + NPDU(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/platform.cpp b/src/knx/platform.cpp index 51b2d03a..a98d2e9c 100644 --- a/src/knx/platform.cpp +++ b/src/knx/platform.cpp @@ -21,12 +21,12 @@ void Platform::setupSpi() void Platform::closeSpi() {} -int Platform::readWriteSpi(uint8_t *data, size_t len) +int Platform::readWriteSpi(uint8_t* data, size_t len) { return 0; } -size_t Platform::readBytesUart(uint8_t *buffer, size_t length) +size_t Platform::readBytesUart(uint8_t* buffer, size_t length) { return 0; } @@ -36,7 +36,7 @@ int Platform::readUart() return -1; } -size_t Platform::writeUart(const uint8_t *buffer, size_t size) +size_t Platform::writeUart(const uint8_t* buffer, size_t size) { return 0; } @@ -80,7 +80,7 @@ uint32_t Platform::currentDefaultGateway() return 0; } -void Platform::macAddress(uint8_t *data) +void Platform::macAddress(uint8_t* data) {} uint32_t Platform::uniqueSerialNumber() @@ -94,7 +94,7 @@ void Platform::setupMultiCast(uint32_t addr, uint16_t port) void Platform::closeMultiCast() {} -bool Platform::sendBytesMultiCast(uint8_t *buffer, uint16_t len) +bool Platform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) { return false; } @@ -104,7 +104,7 @@ bool Platform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, u return false; } -int Platform::readBytesMultiCast(uint8_t *buffer, uint16_t maxLen) +int Platform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) { return 0; } @@ -125,7 +125,7 @@ size_t Platform::flashPageSize() return 4; } -uint8_t *Platform::userFlashStart() +uint8_t* Platform::userFlashStart() { return nullptr; } @@ -141,7 +141,7 @@ void Platform::flashErase(uint16_t eraseBlockNum) void Platform::flashWritePage(uint16_t pageNumber, uint8_t* data) {} -uint8_t * Platform::getEepromBuffer(uint32_t size) +uint8_t* Platform::getEepromBuffer(uint32_t size) { return nullptr; } @@ -151,11 +151,13 @@ void Platform::commitToEeprom() uint8_t* Platform::getNonVolatileMemoryStart() { - if(_memoryType == Flash) + if (_memoryType == Flash) return userFlashStart(); + #ifdef KNX_FLASH_CALLBACK - else if(_memoryType == Callback) + else if (_memoryType == Callback) return _callbackFlashRead(); + #endif else return getEepromBuffer(KNX_FLASH_SIZE); @@ -163,11 +165,13 @@ uint8_t* Platform::getNonVolatileMemoryStart() size_t Platform::getNonVolatileMemorySize() { - if(_memoryType == Flash) + if (_memoryType == Flash) return userFlashSizeEraseBlocks() * flashEraseBlockSize() * flashPageSize(); + #ifdef KNX_FLASH_CALLBACK - else if(_memoryType == Callback) + else if (_memoryType == Callback) return _callbackFlashSize(); + #endif else return KNX_FLASH_SIZE; @@ -175,20 +179,22 @@ size_t Platform::getNonVolatileMemorySize() void Platform::commitNonVolatileMemory() { - if(_memoryType == Flash) + if (_memoryType == Flash) { - if(_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) + if (_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) { writeBufferedEraseBlock(); - + free(_eraseblockBuffer); _eraseblockBuffer = nullptr; _bufferedEraseblockNumber = -1; // does that make sense? } } + #ifdef KNX_FLASH_CALLBACK - else if(_memoryType == Callback) + else if (_memoryType == Callback) return _callbackFlashCommit(); + #endif else { @@ -205,7 +211,7 @@ uint32_t Platform::writeNonVolatileMemory(uint32_t relativeAddress, uint8_t* buf println(size); #endif - if(_memoryType == Flash) + if (_memoryType == Flash) { while (size > 0) { @@ -215,8 +221,10 @@ uint32_t Platform::writeNonVolatileMemory(uint32_t relativeAddress, uint8_t* buf uint32_t offset = relativeAddress - start; uint32_t length = end - relativeAddress; - if(length > size) + + if (length > size) length = size; + memcpy(_eraseblockBuffer + offset, buffer, length); _bufferedEraseblockDirty = true; @@ -224,16 +232,19 @@ uint32_t Platform::writeNonVolatileMemory(uint32_t relativeAddress, uint8_t* buf buffer += length; size -= length; } + return relativeAddress; } + #ifdef KNX_FLASH_CALLBACK - else if(_memoryType == Callback) + else if (_memoryType == Callback) return _callbackFlashWrite(relativeAddress, buffer, size); + #endif else { - memcpy(getEepromBuffer(KNX_FLASH_SIZE)+relativeAddress, buffer, size); - return relativeAddress+size; + memcpy(getEepromBuffer(KNX_FLASH_SIZE) + relativeAddress, buffer, size); + return relativeAddress + size; } } @@ -246,32 +257,34 @@ uint32_t Platform::readNonVolatileMemory(uint32_t relativeAddress, uint8_t* buff println(size); #endif - if(_memoryType == Flash) + if (_memoryType == Flash) { uint32_t offset = 0; + while (size > 0) { // bufferd block is "left" of requested memory, read until the end and return - if(_bufferedEraseblockNumber < getEraseBlockNumberOf(relativeAddress)) + if (_bufferedEraseblockNumber < getEraseBlockNumberOf(relativeAddress)) { - memcpy(buffer+offset, userFlashStart()+relativeAddress, size); + memcpy(buffer + offset, userFlashStart() + relativeAddress, size); return relativeAddress + size; } // bufferd block is "right" of requested memory, and may interfere - else if(_bufferedEraseblockNumber > getEraseBlockNumberOf(relativeAddress)) + 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); - if(_bufferedEraseblockNumber > eraseblockNumberEnd) + int32_t eraseblockNumberEnd = getEraseBlockNumberOf(relativeAddress + size - 1); + + if (_bufferedEraseblockNumber > eraseblockNumberEnd) { - memcpy(buffer+offset, userFlashStart()+relativeAddress, size); + 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); + memcpy(buffer + offset, userFlashStart() + relativeAddress, sizeToRead); relativeAddress += sizeToRead; size -= sizeToRead; offset += sizeToRead; @@ -281,11 +294,12 @@ uint32_t Platform::readNonVolatileMemory(uint32_t relativeAddress, uint8_t* buff 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) + int32_t eraseblockNumberEnd = getEraseBlockNumberOf(relativeAddress + size - 1); + + if (_bufferedEraseblockNumber == eraseblockNumberEnd) { uint8_t* start = _eraseblockBuffer + (relativeAddress - _bufferedEraseblockNumber * flashEraseBlockSize()); - memcpy(buffer+offset, start, size); + memcpy(buffer + offset, start, size); return relativeAddress + size; } // if not, read until the end of the buffered block and loop through while again @@ -294,19 +308,20 @@ uint32_t Platform::readNonVolatileMemory(uint32_t relativeAddress, uint8_t* buff uint32_t offsetInBufferedBlock = relativeAddress - _bufferedEraseblockNumber * flashEraseBlockSize(); uint8_t* start = _eraseblockBuffer + offsetInBufferedBlock; uint32_t sizeToRead = flashEraseBlockSize() - offsetInBufferedBlock; - memcpy(buffer+offset, start, sizeToRead); + 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; + memcpy(buffer, getEepromBuffer(KNX_FLASH_SIZE) + relativeAddress, size); + return relativeAddress + size; } } @@ -314,7 +329,7 @@ uint32_t Platform::readNonVolatileMemory(uint32_t relativeAddress, uint8_t* buff // returns next free relativeAddress uint32_t Platform::writeNonVolatileMemory(uint32_t relativeAddress, uint8_t value, size_t repeat) { - if(_memoryType == Flash) + if (_memoryType == Flash) { while (repeat > 0) { @@ -324,26 +339,30 @@ uint32_t Platform::writeNonVolatileMemory(uint32_t relativeAddress, uint8_t valu uint32_t offset = relativeAddress - start; uint32_t length = end - relativeAddress; - if(length > repeat) + + if (length > repeat) length = repeat; + memset(_eraseblockBuffer + offset, value, length); _bufferedEraseblockDirty = true; relativeAddress += length; repeat -= length; } + return relativeAddress; } else { - memset(getEepromBuffer(KNX_FLASH_SIZE)+relativeAddress, value, repeat); - return relativeAddress+repeat; + memset(getEepromBuffer(KNX_FLASH_SIZE) + relativeAddress, value, repeat); + return relativeAddress + repeat; } } void Platform::loadEraseblockContaining(uint32_t relativeAddress) { int32_t blockNum = getEraseBlockNumberOf(relativeAddress); + if (blockNum < 0) { println("loadEraseblockContaining could not get valid eraseblock number"); @@ -364,15 +383,17 @@ int32_t Platform::getEraseBlockNumberOf(uint32_t relativeAddress) void Platform::writeBufferedEraseBlock() { - if(_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) + if (_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) { flashErase(_bufferedEraseblockNumber); - for(uint32_t i = 0; i < flashEraseBlockSize(); i++) - { + + for (uint32_t i = 0; i < flashEraseBlockSize(); i++) + { int32_t pageNumber = _bufferedEraseblockNumber * flashEraseBlockSize() + i; - uint8_t *data = _eraseblockBuffer + flashPageSize() * i; + uint8_t* data = _eraseblockBuffer + flashPageSize() * i; flashWritePage(pageNumber, data); } + _bufferedEraseblockDirty = false; } } @@ -380,13 +401,14 @@ void Platform::writeBufferedEraseBlock() void Platform::bufferEraseBlock(int32_t eraseBlockNumber) { - if(_bufferedEraseblockNumber == eraseBlockNumber) + if (_bufferedEraseblockNumber == eraseBlockNumber) return; - - if(_eraseblockBuffer == nullptr) + + if (_eraseblockBuffer == nullptr) { _eraseblockBuffer = (uint8_t*)malloc(flashEraseBlockSize() * flashPageSize()); } + memcpy(_eraseblockBuffer, userFlashStart() + eraseBlockNumber * flashEraseBlockSize() * flashPageSize(), flashEraseBlockSize() * flashPageSize()); _bufferedEraseblockNumber = eraseBlockNumber; @@ -400,30 +422,30 @@ void Platform::registerFlashCallbacks( FlashCallbackRead callbackFlashRead, FlashCallbackWrite callbackFlashWrite, FlashCallbackCommit callbackFlashCommit) - { - println("Set Callback"); - _memoryType = Callback; - _callbackFlashSize = callbackFlashSize; - _callbackFlashRead = callbackFlashRead; - _callbackFlashWrite = callbackFlashWrite; - _callbackFlashCommit = callbackFlashCommit; - _callbackFlashSize(); - } +{ + println("Set Callback"); + _memoryType = Callback; + _callbackFlashSize = callbackFlashSize; + _callbackFlashRead = callbackFlashRead; + _callbackFlashWrite = callbackFlashWrite; + _callbackFlashCommit = callbackFlashCommit; + _callbackFlashSize(); +} FlashCallbackSize Platform::callbackFlashSize() { - return _callbackFlashSize; + return _callbackFlashSize; } FlashCallbackRead Platform::callbackFlashRead() { - return _callbackFlashRead; + return _callbackFlashRead; } FlashCallbackWrite Platform::callbackFlashWrite() { - return _callbackFlashWrite; + return _callbackFlashWrite; } FlashCallbackCommit Platform::callbackFlashCommit() { - return _callbackFlashCommit; + return _callbackFlashCommit; } #endif diff --git a/src/knx/platform.h b/src/knx/platform.h index 29c46f1b..d60af19a 100644 --- a/src/knx/platform.h +++ b/src/knx/platform.h @@ -5,20 +5,20 @@ #include "save_restore.h" #ifndef KNX_FLASH_CALLBACK -#ifndef KNX_FLASH_SIZE -#define KNX_FLASH_SIZE 1024 -#pragma warning "KNX_FLASH_SIZE not defined, using 1024" -#endif + #ifndef KNX_FLASH_SIZE + #define KNX_FLASH_SIZE 1024 + #pragma warning "KNX_FLASH_SIZE not defined, using 1024" + #endif #endif #ifdef KNX_FLASH_CALLBACK -#ifndef KNX_FLASH_SIZE -#define KNX_FLASH_SIZE 0 -#endif -typedef uint32_t (*FlashCallbackSize)(); -typedef uint8_t* (*FlashCallbackRead)(); -typedef uint32_t (*FlashCallbackWrite)(uint32_t relativeAddress, uint8_t* buffer, size_t len); -typedef void (*FlashCallbackCommit)(); + #ifndef KNX_FLASH_SIZE + #define KNX_FLASH_SIZE 0 + #endif + typedef uint32_t (*FlashCallbackSize)(); + typedef uint8_t* (*FlashCallbackRead)(); + typedef uint32_t (*FlashCallbackWrite)(uint32_t relativeAddress, uint8_t* buffer, size_t len); + typedef void (*FlashCallbackCommit)(); #endif enum NvMemoryType @@ -30,123 +30,123 @@ enum NvMemoryType 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(); - + 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 }; diff --git a/src/knx/property.cpp b/src/knx/property.cpp index e9900e1f..55184df0 100644 --- a/src/knx/property.cpp +++ b/src/knx/property.cpp @@ -41,6 +41,7 @@ uint8_t Property::ElementSize() const case PDT_ENUM8: case PDT_SCALING: return 1; + case PDT_GENERIC_02: case PDT_INT: case PDT_KNX_FLOAT: @@ -48,6 +49,7 @@ uint8_t Property::ElementSize() const case PDT_VERSION: case PDT_BITSET16: return 2; + case PDT_DATE: case PDT_ESCAPE: case PDT_FUNCTION: @@ -58,48 +60,66 @@ uint8_t Property::ElementSize() const 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; } @@ -118,7 +138,7 @@ uint8_t Property::read(uint8_t& value) const { if (ElementSize() != 1) return 0; - + return read(1, 1, &value); } @@ -130,10 +150,12 @@ uint8_t Property::read(uint16_t& value) const uint8_t data[2]; uint8_t count = read(1, 1, data); + if (count > 0) { popWord(value, data); } + return count; } @@ -145,10 +167,12 @@ uint8_t Property::read(uint32_t& value) const uint8_t data[4]; uint8_t count = read(1, 1, data); + if (count > 0) { popInt(value, data); } + return count; } @@ -212,7 +236,7 @@ void Property::command(uint8_t* data, uint8_t length, uint8_t* resultData, uint8 resultLength = 0; } -void Property::state(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t &resultLength) +void Property::state(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) { (void)data; (void)length; diff --git a/src/knx/property.h b/src/knx/property.h index 09a964c1..816c89c1 100644 --- a/src/knx/property.h +++ b/src/knx/property.h @@ -31,7 +31,7 @@ enum PropertyDataType 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_VARIABLE_LENGTH = 0x10, PDT_GENERIC_01 = 0x11, //!< length: 1 PDT_GENERIC_02 = 0x12, //!< length: 2 PDT_GENERIC_03 = 0x13, //!< length: 3 @@ -88,7 +88,7 @@ enum PropertyID 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, @@ -213,7 +213,7 @@ enum LoadEvents LE_UNLOAD = 4 }; -// 20.011 DPT_ErrorClass_System +// 20.011 DPT_ErrorClass_System enum ErrorCode { E_NO_FAULT = 0, @@ -261,32 +261,32 @@ struct PropertyDescription 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; + 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; }; diff --git a/src/knx/rf_data_link_layer.cpp b/src/knx/rf_data_link_layer.cpp index 3e0baab4..cc900541 100644 --- a/src/knx/rf_data_link_layer.cpp +++ b/src/knx/rf_data_link_layer.cpp @@ -2,9 +2,9 @@ #ifdef USE_RF #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 "rf_data_link_layer.h" @@ -23,7 +23,7 @@ void RfDataLinkLayer::loop() if (!_enabled) return; - _rfPhy.loop(); + _rfPhy.loop(); } bool RfDataLinkLayer::sendFrame(CemiFrame& frame) @@ -78,7 +78,7 @@ bool RfDataLinkLayer::sendFrame(CemiFrame& frame) } RfDataLinkLayer::RfDataLinkLayer(DeviceObject& devObj, RfMediumObject& rfMediumObj, - NetworkLayerEntity &netLayerEntity, Platform& platform, BusAccessUnit& busAccessUnit) + NetworkLayerEntity& netLayerEntity, Platform& platform, BusAccessUnit& busAccessUnit) : DataLinkLayer(devObj, netLayerEntity, platform, busAccessUnit), _rfMediumObj(rfMediumObj), _rfPhy(*this, platform) @@ -99,34 +99,34 @@ void RfDataLinkLayer::frameBytesReceived(uint8_t* rfPacketBuf, uint16_t length) } #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 -#else + // 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)) -#endif + (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 + // 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]; + 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; @@ -134,10 +134,12 @@ void RfDataLinkLayer::frameBytesReceived(uint8_t* rfPacketBuf, uint16_t length) // 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) { // Copy only the payload without the checksums @@ -148,6 +150,7 @@ void RfDataLinkLayer::frameBytesReceived(uint8_t* rfPacketBuf, uint16_t length) crcOk = false; break; } + pBuffer += 16; pRfPacketBuf += 18; newLength += 16; @@ -156,33 +159,33 @@ void RfDataLinkLayer::frameBytesReceived(uint8_t* rfPacketBuf, uint16_t length) // Now process the last block blockCrc = pRfPacketBuf[bytesLeft - 2] << 8 | pRfPacketBuf[bytesLeft - 1]; - crcOk = crcOk && (crc16Dnp(&pRfPacketBuf[0], bytesLeft -2) == blockCrc); + crcOk = crcOk && (crc16Dnp(&pRfPacketBuf[0], bytesLeft - 2) == blockCrc); // If all checksums were ok, then... if (crcOk) { // Copy rest of the received packet without checksum - memcpy(pBuffer, pRfPacketBuf, bytesLeft -2); - newLength += bytesLeft -2; + 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 + // 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 + // 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; + 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; + 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 @@ -208,22 +211,22 @@ void RfDataLinkLayer::frameBytesReceived(uint8_t* rfPacketBuf, uint16_t length) 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.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); -*/ + /* + print("RX LFN: "); + print(lfn); + print(" len: "); + print(newLength); + + print(" data: "); + printHex(" data: ", _buffer, newLength); + */ frameReceived(frame); } } @@ -241,9 +244,10 @@ void RfDataLinkLayer::enabled(bool value) } else { - _enabled = false; + _enabled = false; println("ERROR, RF transceiver not responding"); } + return; } @@ -271,8 +275,8 @@ void RfDataLinkLayer::fillRfFrame(CemiFrame& frame, uint8_t* data) 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[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 @@ -286,8 +290,9 @@ void RfDataLinkLayer::fillRfFrame(CemiFrame& frame, uint8_t* data) // Create a checksum for each block of full 16 bytes uint16_t bytesLeft = length; - uint8_t *pBuffer = &_buffer[0]; - uint8_t *pData = &data[12]; + uint8_t* pBuffer = &_buffer[0]; + uint8_t* pData = &data[12]; + while (bytesLeft > 16) { memcpy(pData, pBuffer, 16); @@ -326,15 +331,16 @@ void RfDataLinkLayer::addFrameTxQueue(CemiFrame& frame) // Prepare the raw RF frame fillRfFrame(frame, tx_frame->data); -/* - print("TX LFN: "); - print(frame.rfLfn()); - print(" len: "); - print(totalLength); + /* + print("TX LFN: "); + print(frame.rfLfn()); + + print(" len: "); + print(totalLength); - printHex(" data:", tx_frame->data, totalLength); -*/ + printHex(" data:", tx_frame->data, totalLength); + */ if (_tx_queue.back == NULL) { _tx_queue.front = _tx_queue.back = tx_frame; @@ -352,6 +358,7 @@ bool RfDataLinkLayer::isTxQueueEmpty() { return true; } + return false; } @@ -361,6 +368,7 @@ void RfDataLinkLayer::loadNextTxFrame(uint8_t** sendBuffer, uint16_t* sendBuffer { return; } + _tx_queue_frame_t* tx_frame = _tx_queue.front; *sendBuffer = tx_frame->data; *sendBufferLength = tx_frame->length; @@ -370,6 +378,7 @@ void RfDataLinkLayer::loadNextTxFrame(uint8_t** sendBuffer, uint16_t* sendBuffer { _tx_queue.back = NULL; } + delete tx_frame; } diff --git a/src/knx/rf_data_link_layer.h b/src/knx/rf_data_link_layer.h index 93ed1e5e..fd6ef1f8 100644 --- a/src/knx/rf_data_link_layer.h +++ b/src/knx/rf_data_link_layer.h @@ -13,55 +13,55 @@ class RfMediumObject; class RfDataLinkLayer : public DataLinkLayer { #if defined(DeviceFamily_CC13X0) - friend class RfPhysicalLayerCC1310; + friend class RfPhysicalLayerCC1310; #else - friend class RfPhysicalLayerCC1101; -#endif - using DataLinkLayer::_deviceObject; - using DataLinkLayer::_platform; + friend class RfPhysicalLayerCC1101; +#endif + using DataLinkLayer::_deviceObject; + using DataLinkLayer::_platform; - public: - RfDataLinkLayer(DeviceObject& devObj, RfMediumObject& rfMediumObj, NetworkLayerEntity& netLayerEntity, - Platform& platform, BusAccessUnit& busAccessUnit); + public: + RfDataLinkLayer(DeviceObject& devObj, RfMediumObject& rfMediumObj, NetworkLayerEntity& netLayerEntity, + Platform& platform, BusAccessUnit& busAccessUnit); - 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); }; #endif diff --git a/src/knx/rf_medium_object.cpp b/src/knx/rf_medium_object.cpp index 5416649e..8ccebd99 100644 --- a/src/knx/rf_medium_object.cpp +++ b/src/knx/rf_medium_object.cpp @@ -16,32 +16,32 @@ RfMediumObject::RfMediumObject() 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) - { - }), */ + 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); } diff --git a/src/knx/rf_medium_object.h b/src/knx/rf_medium_object.h index 8a1500aa..3e03b531 100644 --- a/src/knx/rf_medium_object.h +++ b/src/knx/rf_medium_object.h @@ -7,13 +7,13 @@ class RfMediumObject: public InterfaceObject { -public: - RfMediumObject(); - const uint8_t* rfDomainAddress(); - void rfDomainAddress(const uint8_t* value); + 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,}; }; #endif diff --git a/src/knx/rf_physical_layer.h b/src/knx/rf_physical_layer.h index 6b2828b3..f9b63899 100644 --- a/src/knx/rf_physical_layer.h +++ b/src/knx/rf_physical_layer.h @@ -14,17 +14,17 @@ class RfDataLinkLayer; class RfPhysicalLayer { - public: - RfPhysicalLayer(RfDataLinkLayer& rfDataLinkLayer, Platform& platform) - : _rfDataLinkLayer(rfDataLinkLayer), _platform(platform) {} + 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; }; #endif diff --git a/src/knx/rf_physical_layer_cc1101.cpp b/src/knx/rf_physical_layer_cc1101.cpp index 38134f28..daa96aae 100644 --- a/src/knx/rf_physical_layer_cc1101.cpp +++ b/src/knx/rf_physical_layer_cc1101.cpp @@ -14,40 +14,42 @@ // 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 + 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 + 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) @@ -76,99 +78,100 @@ const uint8_t RfPhysicalLayerCC1101::manchDecodeTab[16] = {0xFF, // Manchester // 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 +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}; +//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) +void RfPhysicalLayerCC1101::manchEncode(uint8_t* uncodedData, uint8_t* encodedData) { - uint8_t data0, data1; + uint8_t data0, data1; - // - Shift to get 4-bit data values - data1 = (((*uncodedData) >> 4) & 0x0F); - data0 = ((*uncodedData) & 0x0F); + // - Shift to get 4-bit data values + data1 = (((*uncodedData) >> 4) & 0x0F); + data0 = ((*uncodedData) & 0x0F); - // - Perform Manchester encoding - - *encodedData = (manchEncodeTab[data1]); - *(encodedData + 1) = manchEncodeTab[data0]; + // - Perform Manchester encoding - + *encodedData = (manchEncodeTab[data1]); + *(encodedData + 1) = manchEncodeTab[data0]; } -bool RfPhysicalLayerCC1101::manchDecode(uint8_t *encodedData, uint8_t *decodedData) +bool RfPhysicalLayerCC1101::manchDecode(uint8_t* encodedData, uint8_t* decodedData) { - uint8_t data0, data1, data2, data3; - - // - Shift to get 4 bit data and decode - data3 = ((*encodedData >> 4) & 0x0F); - data2 = ( *encodedData & 0x0F); - data1 = ((*(encodedData + 1) >> 4) & 0x0F); - data0 = ((*(encodedData + 1)) & 0x0F); - - // Check for invalid Manchester encoding - if ( (manchDecodeTab[data3] == 0xFF ) | (manchDecodeTab[data2] == 0xFF ) | - (manchDecodeTab[data1] == 0xFF ) | (manchDecodeTab[data0] == 0xFF ) ) - { - return false; - } - - // Shift result into a byte - *decodedData = (manchDecodeTab[data3] << 6) | (manchDecodeTab[data2] << 4) | - (manchDecodeTab[data1] << 2) | manchDecodeTab[data0]; - - return true; + uint8_t data0, data1, data2, data3; + + // - Shift to get 4 bit data and decode + data3 = ((*encodedData >> 4) & 0x0F); + data2 = ( *encodedData & 0x0F); + data1 = ((*(encodedData + 1) >> 4) & 0x0F); + data0 = ((*(encodedData + 1)) & 0x0F); + + // Check for invalid Manchester encoding + if ( (manchDecodeTab[data3] == 0xFF ) | (manchDecodeTab[data2] == 0xFF ) | + (manchDecodeTab[data1] == 0xFF ) | (manchDecodeTab[data0] == 0xFF ) ) + { + return false; + } + + // Shift result into a byte + *decodedData = (manchDecodeTab[data3] << 6) | (manchDecodeTab[data2] << 4) | + (manchDecodeTab[data1] << 2) | manchDecodeTab[data0]; + + return true; } uint8_t RfPhysicalLayerCC1101::sIdle() @@ -180,7 +183,8 @@ uint8_t RfPhysicalLayerCC1101::sIdle() marcState = 0xFF; //set unknown/dummy state value timeStart = millis(); - while((marcState != MARCSTATE_IDLE) && ((millis() - timeStart) < CC1101_TIMEOUT)) //0x01 = sidle + + 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 } @@ -188,7 +192,7 @@ uint8_t RfPhysicalLayerCC1101::sIdle() //print("marcstate: 0x"); //println(marcState, HEX); - if(marcState != MARCSTATE_IDLE) + if (marcState != MARCSTATE_IDLE) { println("Timeout when trying to set idle state."); return false; @@ -206,7 +210,8 @@ uint8_t RfPhysicalLayerCC1101::sReceive() marcState = 0xFF; //set unknown/dummy state value timeStart = millis(); - while((marcState != MARCSTATE_RX) && ((millis() - timeStart) < CC1101_TIMEOUT)) //0x0D = RX + + 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 } @@ -214,7 +219,7 @@ uint8_t RfPhysicalLayerCC1101::sReceive() //print("marcstate: 0x"); //println(marcState, HEX); - if(marcState != MARCSTATE_RX) + if (marcState != MARCSTATE_RX) { println("Timeout when trying to set receive state."); return false; @@ -225,67 +230,70 @@ uint8_t RfPhysicalLayerCC1101::sReceive() 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); + 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); } 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; + 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; } 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]; + 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]; } -void RfPhysicalLayerCC1101::spiReadBurst(uint8_t spi_instr, uint8_t *pArr, uint8_t len) +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); - for (uint8_t i=0; i abort - if(version == 0x00 || version == 0xFF) + if (version == 0x00 || version == 0xFF) { println("No CC11xx found!"); stopChip(); return false; } - print("Partnumber: 0x"); + print("Partnumber: 0x"); println(partnum, HEX); print("Version : 0x"); println(version, HEX); // Set modulation mode 2FSK, 32768kbit/s - spiWriteBurst(WRITE_BURST,cc1101_2FSK_32_7_kb,CFG_REGISTER); + spiWriteBurst(WRITE_BURST, cc1101_2FSK_32_7_kb, CFG_REGISTER); - // Set PA table + // Set PA table spiWriteBurst(PATABLE_BURST, paTablePower868, 8); // Set ISM band to 868.3MHz - spiWriteRegister(FREQ2,0x21); - spiWriteRegister(FREQ1,0x65); - spiWriteRegister(FREQ0,0x6A); + spiWriteRegister(FREQ2, 0x21); + spiWriteRegister(FREQ1, 0x65); + spiWriteRegister(FREQ0, 0x6A); // Set channel 0 in ISM band spiWriteRegister(CHANNR, 0); @@ -391,8 +407,8 @@ void RfPhysicalLayerCC1101::showRegisterSettings() uint8_t config_reg_verify[CFG_REGISTER]; uint8_t Patable_verify[CFG_REGISTER]; - 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 + 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 println("Config Register:"); printHex("", config_reg_verify, CFG_REGISTER); @@ -411,16 +427,16 @@ void RfPhysicalLayerCC1101::loop() 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 + // 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); + spiWriteRegister(IOCFG2, 0x02); // Set GDO0 to be packet transmitted signal - spiWriteRegister(IOCFG0, 0x06); + spiWriteRegister(IOCFG0, 0x06); // Flush TX FIFO spiWriteStrobe(SFTX); @@ -428,6 +444,7 @@ void RfPhysicalLayerCC1101::loop() // 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)) { @@ -435,37 +452,40 @@ void RfPhysicalLayerCC1101::loop() break; } - // Manchester encoded data takes twice the space plus + // 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 + // Last byte of synchronization word buffer[0] = 0x96; - // Manchester encode packet + + // Manchester encode packet for (int i = 0; i < pktLen; i++) { - manchEncode(&sendBuffer[i], &buffer[1 + i*2]); + manchEncode(&sendBuffer[i], &buffer[1 + i * 2]); } + // Append the postamble sequence buffer[1 + bytesLeft - 1] = 0x55; // 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); + spiWriteRegister(PKTLEN, fixedLength); + spiWriteRegister(PKTCTRL0, 0x02); fixedLengthMode = false; } - uint8_t bytesToWrite = MIN(64, bytesLeft); + uint8_t bytesToWrite = MIN(64, bytesLeft); spiWriteBurst(TXFIFO_BURST, pByteIndex, bytesToWrite); pByteIndex += bytesToWrite; bytesLeft -= bytesToWrite; @@ -475,8 +495,9 @@ void RfPhysicalLayerCC1101::loop() _loopState = TX_ACTIVE; } + // Fall through - + case TX_ACTIVE: { // Check if we have an incomplete packet transmission @@ -491,12 +512,13 @@ void RfPhysicalLayerCC1101::loop() // Detect falling edge 1->0 on GDO2 statusGDO2 = digitalRead(GPIO_GDO2_PIN); - if(prevStatusGDO2 != statusGDO2) + + if (prevStatusGDO2 != statusGDO2) { 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) + if (statusGDO2 == 0) { // - TX FIFO half full detected (< 33 bytes) // Write data fragment to TX FIFO @@ -514,9 +536,10 @@ void RfPhysicalLayerCC1101::loop() } } - // Detect falling edge 1->0 on GDO0 + // Detect falling edge 1->0 on GDO0 statusGDO0 = digitalRead(GPIO_GDO0_PIN); - if(prevStatusGDO0 != statusGDO0) + + if (prevStatusGDO0 != statusGDO0) { prevStatusGDO0 = statusGDO0; @@ -525,12 +548,14 @@ void RfPhysicalLayerCC1101::loop() { // There might be an TX FIFO underflow uint8_t chipStatusBytes = spiWriteStrobe(SNOP); + if ((chipStatusBytes & CHIPSTATUS_STATE_BITMASK) == CHIPSTATUS_STATE_TX_UNDERFLOW) { println("TX FIFO underflow!"); - // Set transceiver to IDLE (no RX or TX) - sIdle(); + // Set transceiver to IDLE (no RX or TX) + sIdle(); } + _loopState = TX_END; } else @@ -570,13 +595,13 @@ void RfPhysicalLayerCC1101::loop() spiWriteRegister(SYNC1, 0x76); spiWriteRegister(SYNC0, 0x96); // Set GDO2 to be RX FIFO threshold signal - spiWriteRegister(IOCFG2, 0x00); + spiWriteRegister(IOCFG2, 0x00); // Set GDO0 to be packet received signal - spiWriteRegister(IOCFG0, 0x06); + spiWriteRegister(IOCFG0, 0x06); // Set RX FIFO threshold to 4 bytes spiWriteRegister(FIFOTHR, 0x40); // Set infinite pktlen mode - spiWriteRegister(PKTCTRL0, 0x02); + spiWriteRegister(PKTCTRL0, 0x02); // Flush RX FIFO spiWriteStrobe(SFRX); // Start RX @@ -609,33 +634,35 @@ void RfPhysicalLayerCC1101::loop() // Detect rising edge 0->1 on GDO2 statusGDO2 = digitalRead(GPIO_GDO2_PIN); - if(prevStatusGDO2 != statusGDO2) + + if (prevStatusGDO2 != statusGDO2) { prevStatusGDO2 = statusGDO2; // Check if signal GDO2 is asserted (RX FIFO is equal to or above threshold of 4 bytes) - if(statusGDO2 == 1) + if (statusGDO2 == 1) { if (packetStart) { - // - RX FIFO 4 bytes detected - + // - 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); + 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; + _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 - + // - Length mode - if (pktLen < 256) { // Set fixed packet length mode is less than 256 bytes @@ -648,19 +675,19 @@ void RfPhysicalLayerCC1101::loop() // Infinite packet length mode is more than 255 bytes // Calculate the PKTLEN value uint8_t fixedLength = pktLen % 256; - spiWriteRegister(PKTLEN, fixedLength); - } - + spiWriteRegister(PKTLEN, fixedLength); + } + pByteIndex += 2; bytesLeft = pktLen - 2; - + // Set RX FIFO threshold to 32 bytes packetStart = false; spiWriteRegister(FIFOTHR, 0x47); } else { - // - RX FIFO Half Full detected - + // - RX FIFO Half Full detected - // Read out the RX FIFO and set fixed mode if less // than 255 bytes to receive @@ -668,13 +695,13 @@ void RfPhysicalLayerCC1101::loop() // Set fixed packet length mode if less than 256 bytes if ((bytesLeft < 256 ) && !fixedLengthMode) { - spiWriteRegister(PKTCTRL0, 0x00); // Set fixed pktlen mode + 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); + spiReadBurst(RXFIFO_BURST, pByteIndex, 32 - 1); bytesLeft -= (32 - 1); pByteIndex += (32 - 1); @@ -682,9 +709,10 @@ void RfPhysicalLayerCC1101::loop() } } - // Detect falling edge 1->0 on GDO0 + // Detect falling edge 1->0 on GDO0 statusGDO0 = digitalRead(GPIO_GDO0_PIN); - if(prevStatusGDO0 != statusGDO0) + + if (prevStatusGDO0 != statusGDO0) { prevStatusGDO0 = statusGDO0; @@ -693,10 +721,11 @@ void RfPhysicalLayerCC1101::loop() { // There might be an RX FIFO overflow uint8_t chipStatusBytes = spiWriteStrobe(SNOP); + if ((chipStatusBytes & CHIPSTATUS_STATE_BITMASK) == CHIPSTATUS_STATE_RX_OVERFLOW) { println("RX FIFO overflow!"); - _loopState = RX_START; + _loopState = RX_START; break; } @@ -705,7 +734,7 @@ void RfPhysicalLayerCC1101::loop() { // Complete packet received // Read out remaining bytes in the RX FIFO - spiReadBurst(RXFIFO_BURST, pByteIndex, bytesLeft); + spiReadBurst(RXFIFO_BURST, pByteIndex, bytesLeft); _loopState = RX_END; } } @@ -727,10 +756,11 @@ void RfPhysicalLayerCC1101::loop() 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 (!manchDecode(&buffer[i * 2], &packet[i])) { println("Could not decode packet: manchester code violation"); decodeOk = false; diff --git a/src/knx/rf_physical_layer_cc1101.h b/src/knx/rf_physical_layer_cc1101.h index 76065d35..02b53ce5 100644 --- a/src/knx/rf_physical_layer_cc1101.h +++ b/src/knx/rf_physical_layer_cc1101.h @@ -10,13 +10,13 @@ #include "rf_physical_layer.h" /*----------------------------------[standard]--------------------------------*/ -#define CC1101_TIMEOUT 2000 // Time to wait for a response from CC1101 +#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); + extern void delayMicroseconds (unsigned int howLong); #endif /*----------------------[CC1101 - misc]---------------------------------------*/ @@ -167,14 +167,14 @@ extern void delayMicroseconds (unsigned int howLong); #define CHIPSTATUS_STATE_BITMASK 0x70 #define CHIPSTATUS_FIFO_BYTES_AVAILABLE_BITMASK 0x0F // Chip states - #define CHIPSTATUS_STATE_IDLE 0x00 - #define CHIPSTATUS_STATE_RX 0x10 - #define CHIPSTATUS_STATE_TX 0x20 - #define CHIPSTATUS_STATE_FSTXON 0x30 - #define CHIPSTATUS_STATE_CALIBRATE 0x40 - #define CHIPSTATUS_STATE_SETTLING 0x50 - #define CHIPSTATUS_STATE_RX_OVERFLOW 0x60 - #define CHIPSTATUS_STATE_TX_UNDERFLOW 0x70 +#define CHIPSTATUS_STATE_IDLE 0x00 +#define CHIPSTATUS_STATE_RX 0x10 +#define CHIPSTATUS_STATE_TX 0x20 +#define CHIPSTATUS_STATE_FSTXON 0x30 +#define CHIPSTATUS_STATE_CALIBRATE 0x40 +#define CHIPSTATUS_STATE_SETTLING 0x50 +#define CHIPSTATUS_STATE_RX_OVERFLOW 0x60 +#define CHIPSTATUS_STATE_TX_UNDERFLOW 0x70 // loop states #define RX_START 0 @@ -188,55 +188,55 @@ 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}; + 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 // USE_RF diff --git a/src/knx/rf_physical_layer_cc1310.cpp b/src/knx/rf_physical_layer_cc1310.cpp index 2016b953..18c28089 100644 --- a/src/knx/rf_physical_layer_cc1310.cpp +++ b/src/knx/rf_physical_layer_cc1310.cpp @@ -25,14 +25,14 @@ #define RX_MAX_BUFFER_LENGTH 256 #define RF_TERMINATION_EVENT_MASK (RF_EventLastCmdDone | RF_EventLastFGCmdDone | RF_EventCmdAborted | RF_EventCmdStopped | RF_EventCmdCancelled) -#define DEBUG_DUMP_PACKETS +#define DEBUG_DUMP_PACKETS 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 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! @@ -69,10 +69,11 @@ static void RxCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) // 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; + 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]))) + (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 */); @@ -89,13 +90,14 @@ static void RxCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) //RF_runImmediateCmd(rfHandle, (uint32_t*)&RF_cmdPropSetLen); // for length > 255 RF_Stat status = RF_runDirectCmd(rfHandle, (uint32_t)&RF_cmdPropSetLen); + if (status != RF_StatCmdDoneSuccess) { println("RF CMD_PROP_SET_LEN failed!"); } } } - else if (e & RF_TERMINATION_EVENT_MASK) + else if (e & RF_TERMINATION_EVENT_MASK) { if (e & RF_EventCmdAborted) { @@ -114,39 +116,43 @@ static void RxCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) RfPhysicalLayerCC1310::RfPhysicalLayerCC1310(RfDataLinkLayer& rfDataLinkLayer, Platform& platform) : RfPhysicalLayer(rfDataLinkLayer, platform) -{ +{ } void RfPhysicalLayerCC1310::setOutputPowerLevel(int8_t dBm) { - RF_TxPowerTable_Entry *rfPowerTable = NULL; + 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); - if(newValue.rawValue != RF_TxPowerTable_INVALID_VALUE) + 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; + 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 (CCFG_FORCE_VDDR_HH != 0x1) - if((newValue.paType == RF_TxPowerTable_DefaultPA) && - (dBm == rfPowerTable[rfPowerTableSize-2].power)) + + 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); - if(rfStatus == RF_StatSuccess) + + if (rfStatus == RF_StatSuccess) { print("Successfully set TX output power to: "); println(newValue.rawValue); @@ -178,8 +184,8 @@ bool RfPhysicalLayerCC1310::InitChip() // 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.pQueue = &dataQueue; + // Set the output buffer for RX packet statistics RF_cmdPropRxAdv.pOutput = (uint8_t*)&rxStatistics; // Request access to the radio @@ -202,9 +208,9 @@ void RfPhysicalLayerCC1310::loop() { switch (_loopState) { - case TX_START: + case TX_START: { - uint8_t *sendBuffer {nullptr}; + uint8_t* sendBuffer {nullptr}; uint16_t sendBufferLength {0}; //println("TX_START..."); @@ -213,20 +219,23 @@ void RfPhysicalLayerCC1310::loop() 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])); + print("Error TX: SendBuffer[0]="); + println(sendBuffer[0]); + print("Error TX: SendBufferLength="); + println(sendBufferLength); + print("Error TX: PACKET_SIZE="); + println(PACKET_SIZE(sendBuffer[0])); } // Calculate total number of bytes in the KNX RF packet from L-field // Check for valid length - if ((pktLen == 0) || (pktLen > 290)) + if ((pktLen == 0) || (pktLen > 290)) { println("TX packet length error!"); break; } - if (pktLen > 255) + if (pktLen > 255) { println("Unhandled: TX packet > 255"); break; @@ -243,9 +252,10 @@ void RfPhysicalLayerCC1310::loop() #endif delete sendBuffer; - if (result != RF_EventLastCmdDone) + if (result != RF_EventLastCmdDone) { - print("Unexpected result command: ");println(result, HEX); + print("Unexpected result command: "); + println(result, HEX); } //println("Restart RX..."); @@ -262,25 +272,30 @@ void RfPhysicalLayerCC1310::loop() pDataEntry->status = DATA_ENTRY_PENDING; rxCommandHandle = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdPropRxAdv, RF_PriorityNormal, &RxCallback, RF_EventNDataWritten | RF_EventRxAborted); - if (rxCommandHandle == RF_ALLOC_ERROR) + + if (rxCommandHandle == RF_ALLOC_ERROR) { println("Error: nRF_pendCmd() failed"); return; } + _loopState = RX_ACTIVE; } break; case RX_ACTIVE: { - if (!_rfDataLinkLayer.isTxQueueEmpty()) + if (!_rfDataLinkLayer.isTxQueueEmpty()) { RF_cancelCmd(rfHandle, rxCommandHandle, RF_ABORT_GRACEFULLY); RF_pendCmd(rfHandle, rxCommandHandle, RF_TERMINATION_EVENT_MASK); + if (RF_cmdPropTx.status != PROP_DONE_OK) { - print("Unexpected RF_cmdPropTx.status after stopping RX: ");println(RF_cmdPropTx.status, HEX); + print("Unexpected RF_cmdPropTx.status after stopping RX: "); + println(RF_cmdPropTx.status, HEX); } + _loopState = TX_START; break; } @@ -301,34 +316,39 @@ void RfPhysicalLayerCC1310::loop() _loopState = RX_START; break; } - else if (rfDone) + else if (rfDone) { RF_EventMask result = RF_pendCmd(rfHandle, rxCommandHandle, RF_TERMINATION_EVENT_MASK); - if ((result & RF_EventCmdCancelled) || (result & RF_EventCmdStopped) || (result & RF_EventCmdAborted)) + + 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) + else if ((result & RF_EventLastCmdDone) != RF_EventLastCmdDone) { - print("Unexpected Rx result command: ");println(result, HEX); + print("Unexpected Rx result command: "); + println(result, HEX); } - else if (rfErr) + else if (rfErr) { println("Rx is no KNX frame"); - } - else if ((result & RF_EventLastCmdDone) == RF_EventLastCmdDone) + } + 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; + 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)) + if (packetLength != (pDataEntry->nextIndex - 1)) { println("Mismatch between packetLength and pDataEntry->nextIndex: "); - print("packetLength = ");print(packetLength); - print(", pDataEntry->nextIndex = ");println(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 @@ -339,10 +359,12 @@ void RfPhysicalLayerCC1310::loop() #if defined(DEBUG_DUMP_PACKETS) printHex("RX: ", packetDataPointer, packetLength, false); - print ("- RSSI: ");println(rxStatistics.lastRssi); -#endif + print ("- RSSI: "); + println(rxStatistics.lastRssi); +#endif _rfDataLinkLayer.frameBytesReceived(packetDataPointer, packetLength); } + _loopState = RX_START; } } diff --git a/src/knx/rf_physical_layer_cc1310.h b/src/knx/rf_physical_layer_cc1310.h index 4dbc2e64..9c79e964 100644 --- a/src/knx/rf_physical_layer_cc1310.h +++ b/src/knx/rf_physical_layer_cc1310.h @@ -23,17 +23,17 @@ class RfDataLinkLayer; class RfPhysicalLayerCC1310 : public RfPhysicalLayer { - public: - RfPhysicalLayerCC1310(RfDataLinkLayer& rfDataLinkLayer, Platform& platform); + public: + RfPhysicalLayerCC1310(RfDataLinkLayer& rfDataLinkLayer, Platform& platform); - bool InitChip() override; - void stopChip() override; - void loop() override; + bool InitChip() override; + void stopChip() override; + void loop() override; - void setOutputPowerLevel(int8_t dBm); + void setOutputPowerLevel(int8_t dBm); - private: - uint8_t _loopState = RX_START; + private: + uint8_t _loopState = RX_START; }; #endif // USE_RF diff --git a/src/knx/router_object.cpp b/src/knx/router_object.cpp index 70fab47b..36ebb3a1 100644 --- a/src/knx/router_object.cpp +++ b/src/knx/router_object.cpp @@ -69,7 +69,7 @@ void RouterObject::initialize(CouplerModel model, uint8_t objIndex, DptMedium me // 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_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*); @@ -86,14 +86,14 @@ void RouterObject::initialize(CouplerModel model, uint8_t objIndex, DptMedium me 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); - }) + // 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[] = @@ -140,7 +140,8 @@ void RouterObject::initialize(CouplerModel model, uint8_t objIndex, DptMedium me { memcpy(&allProperties[i], tableProperties, sizeof(tableProperties)); i += tablePropertiesCount; - if((model == CouplerModel::Model_20)) + + if ((model == CouplerModel::Model_20)) { memcpy(&allProperties[i], tableProperties20, sizeof(tableProperties20)); i += tableProperties20Count; @@ -150,26 +151,30 @@ void RouterObject::initialize(CouplerModel model, uint8_t objIndex, DptMedium me 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); - }); + // 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); - }); + // 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); + }); } if (useTable) @@ -196,7 +201,7 @@ void RouterObject::commandClearSetRoutingTable(bool bitIsSet) for (uint16_t i = 0; i < kFilterTableSize; i++) { - _memory.writeMemory(relptr+i, 1, &fillbyte); + _memory.writeMemory(relptr + i, 1, &fillbyte); } } @@ -206,11 +211,13 @@ bool RouterObject::statusClearSetRoutingTable(bool bitIsSet) print("RouterObject::statusClearSetRoutingTable "); println(bitIsSet); #endif + for (uint16_t i = 0; i < kFilterTableSize; i++) { if (data()[i] != (bitIsSet ? 0xFF : 0x00)) return false; } + return true; } @@ -243,6 +250,7 @@ void RouterObject::commandClearSetGroupAddress(uint16_t startAddress, uint16_t e else octetData &= ~(1 << bitPos); } + _memory.writeMemory(relptr, 1, &octetData); return; } @@ -252,6 +260,7 @@ void RouterObject::commandClearSetGroupAddress(uint16_t startAddress, uint16_t e uint32_t relptr = _memory.toRelative(data()) + i; uint8_t octetData = 0; _memory.readMemory(relptr, 1, &octetData); + if (i == startOctet) { for (uint8_t bitPos = startBitPosition; bitPos <= 7; bitPos++) @@ -279,6 +288,7 @@ void RouterObject::commandClearSetGroupAddress(uint16_t startAddress, uint16_t e else octetData = 0x00; } + _memory.writeMemory(relptr, 1, &octetData); } } @@ -314,6 +324,7 @@ bool RouterObject::statusClearSetGroupAddress(uint16_t startAddress, uint16_t en return false; } } + return true; } @@ -382,7 +393,8 @@ void RouterObject::functionRouteTableControl(bool isCommand, uint8_t* data, uint resultLength = 2; return; } - switch(srvId) + + switch (srvId) { case ClearRoutingTable: commandClearSetRoutingTable(false); @@ -390,12 +402,14 @@ void RouterObject::functionRouteTableControl(bool isCommand, uint8_t* data, uint 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; @@ -410,6 +424,7 @@ void RouterObject::functionRouteTableControl(bool isCommand, uint8_t* data, uint resultLength = 6; return; } + case SetGroupAddress: { uint16_t startAddress; @@ -428,18 +443,20 @@ void RouterObject::functionRouteTableControl(bool isCommand, uint8_t* data, uint } else { - switch(srvId) + switch (srvId) { 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; @@ -453,6 +470,7 @@ void RouterObject::functionRouteTableControl(bool isCommand, uint8_t* data, uint resultLength = 6; return; } + case SetGroupAddress: { uint16_t startAddress; @@ -530,6 +548,7 @@ void RouterObject::beforeStateChange(LoadState& newState) #ifdef KNX_LOG_COUPLER println("RouterObject::beforeStateChange"); #endif + if (newState != LS_LOADED) return; } @@ -557,20 +576,21 @@ bool RouterObject::isGroupAddressInFilterTable(uint16_t groupAddress) 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) // 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 ((filterTableUse&0x01) == 1) + 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; - - if(filterTable) + + if (filterTable) return (filterTable[octetAddress] & (1 << bitPosition)) == (1 << bitPosition); else { diff --git a/src/knx/router_object.h b/src/knx/router_object.h index 467835bd..7f9194dc 100644 --- a/src/knx/router_object.h +++ b/src/knx/router_object.h @@ -22,37 +22,37 @@ enum RouterObjectType class RouterObject : public TableObject { -public: - RouterObject(Memory& memory, uint32_t staticTableAdr = 0, uint32_t staticTableSize = 0); + 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); + 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 isGroupAddressInFilterTable(uint16_t groupAddress); - bool isRfSbcRoutingEnabled(); - bool isIpSbcRoutingEnabled(); + bool isRfSbcRoutingEnabled(); + bool isIpSbcRoutingEnabled(); - void masterReset(EraseCode eraseCode, uint8_t channel) override; + void masterReset(EraseCode eraseCode, uint8_t channel) override; - 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: - // 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); + 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); + 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; + bool _rfSbcRoutingEnabled = false; + bool _ipSbcRoutingEnabled = false; + CouplerModel _model = CouplerModel::Model_20; }; diff --git a/src/knx/save_restore.h b/src/knx/save_restore.h index d4f9f290..12d07174 100644 --- a/src/knx/save_restore.h +++ b/src/knx/save_restore.h @@ -2,42 +2,42 @@ #include /** - * Interface for classes that can save and restore data from a 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; - } - - /** - * @return The maximum number of bytes the object needs to save its state. - */ - virtual uint16_t saveSize() - { - return 0; - } + 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; + } + + /** + * @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/secure_application_layer.cpp b/src/knx/secure_application_layer.cpp index 7913c78f..315f5cca 100644 --- a/src/knx/secure_application_layer.cpp +++ b/src/knx/secure_application_layer.cpp @@ -23,14 +23,14 @@ 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): +SecureApplicationLayer::SecureApplicationLayer(DeviceObject& deviceObj, SecurityInterfaceObject& secIfObj, BusAccessUnit& bau): ApplicationLayer(bau), _secIfObj(secIfObj), _deviceObj(deviceObj) { } -void SecureApplicationLayer::groupAddressTable(AddressTableObject &addrTable) +void SecureApplicationLayer::groupAddressTable(AddressTableObject& addrTable) { _addrTab = &addrTable; } @@ -53,12 +53,14 @@ void SecureApplicationLayer::dataGroupIndication(HopCountType hopType, Priority // 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::dataGroupIndication(hopType, priority, tsap, plainFrame.apdu(), secCtrl); } + return; } @@ -84,12 +86,14 @@ void SecureApplicationLayer::dataGroupConfirm(AckType ack, HopCountType hopType, // 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); } + return; } @@ -109,12 +113,14 @@ void SecureApplicationLayer::dataBroadcastIndication(HopCountType hopType, Prior // 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); } + return; } @@ -140,14 +146,17 @@ void SecureApplicationLayer::dataBroadcastConfirm(AckType ack, HopCountType hopT // 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::dataBroadcastConfirm(ack, hopType, priority, plainFrame.apdu(), secCtrl, status); } + return; } + ApplicationLayer::dataBroadcastConfirm(ack, hopType, priority, apdu, status); } @@ -164,12 +173,14 @@ void SecureApplicationLayer::dataSystemBroadcastIndication(HopCountType hopType, // 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); } + return; } @@ -195,12 +206,14 @@ void SecureApplicationLayer::dataSystemBroadcastConfirm(HopCountType hopType, Pr // 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; } @@ -220,12 +233,14 @@ void SecureApplicationLayer::dataIndividualIndication(HopCountType hopType, Prio // 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); } + return; } @@ -251,12 +266,14 @@ void SecureApplicationLayer::dataIndividualConfirm(AckType ack, HopCountType hop // 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); } + return; } else @@ -278,12 +295,14 @@ void SecureApplicationLayer::dataConnectedIndication(Priority priority, uint16_t // 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::dataConnectedIndication(priority, tsap, plainFrame.apdu(), secCtrl); } + return; } @@ -313,11 +332,13 @@ void SecureApplicationLayer::dataGroupRequest(AckType ack, HopCountType hopType, 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; } @@ -337,11 +358,13 @@ void SecureApplicationLayer::dataBroadcastRequest(AckType ack, HopCountType hopT 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); } + return; } @@ -361,11 +384,13 @@ void SecureApplicationLayer::dataSystemBroadcastRequest(AckType ack, HopCountTyp 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); } + return; } @@ -384,18 +409,20 @@ void SecureApplicationLayer::dataIndividualRequest(AckType ack, HopCountType hop 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::dataIndividualRequest(ack, hopType, priority, destination, secureFrame.apdu(), secCtrl); } + return; } ApplicationLayer::dataIndividualRequest(ack, hopType, priority, destination, apdu, secCtrl); } -void SecureApplicationLayer::dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu, const SecurityControl &secCtrl) +void SecureApplicationLayer::dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu, const SecurityControl& secCtrl) { println("dataConnectedRequest"); @@ -407,11 +434,13 @@ void SecureApplicationLayer::dataConnectedRequest(uint16_t tsap, Priority priori 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::dataConnectedRequest(tsap, priority, secureFrame.apdu(), secCtrl); } + return; } @@ -467,8 +496,8 @@ uint32_t SecureApplicationLayer::calcAuthOnlyMac(uint8_t* apdu, uint8_t apduLeng } uint32_t SecureApplicationLayer::calcConfAuthMac(uint8_t* associatedData, uint16_t associatedDataLength, - uint8_t* apdu, uint8_t apduLength, - const uint8_t* key, uint8_t* iv) + 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 @@ -520,6 +549,7 @@ 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; + return _addrTab->getTsap(groupAddr); } @@ -528,12 +558,14 @@ const uint8_t* SecureApplicationLayer::securityKey(uint16_t addr, bool isGroupAd if (isGroupAddress) { uint16_t gaIndex = groupAddressIndex(addr); + if (gaIndex > 0) return _secIfObj.groupKey(gaIndex); } else { uint16_t iaIndex = _secIfObj.indAddressIndex(addr); + if (iaIndex > 0) return _secIfObj.p2pKey(iaIndex); } @@ -570,6 +602,7 @@ uint64_t SecureApplicationLayer::lastValidSequenceNumber(bool toolAccess, uint16 // TODO: check if we really have to support multiple tools at the same time if (srcAddr == _deviceObj.individualAddress()) return _sequenceNumberToolAccess; + return _lastValidSequenceNumberTool; } else @@ -591,7 +624,7 @@ void SecureApplicationLayer::updateLastValidSequence(bool toolAccess, uint16_t r } } -void SecureApplicationLayer::sendSyncRequest(uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl &secCtrl, bool systemBcast) +void SecureApplicationLayer::sendSyncRequest(uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl& secCtrl, bool systemBcast) { if (secCtrl.dataSecurity != DataSecurity::AuthConf) { @@ -608,9 +641,10 @@ void SecureApplicationLayer::sendSyncRequest(uint16_t dstAddr, bool dstAddrIsGro sixBytesFromUInt64(challenge, &asdu[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! + // Note: additional TPCI byte is already handled internally! uint8_t tpci = 0; + if (!_syncReqBroadcastOutgoing) { if (isConnected()) @@ -618,10 +652,11 @@ void SecureApplicationLayer::sendSyncRequest(uint16_t dstAddr, bool dstAddrIsGro tpci |= 0x40 | _transportLayer->getTpciSeqNum(); // get next TPCI sequence number for MAC calculation from TL (T_DATA_CONNECTED) } } + print("sendSyncRequest: TPCI: "); println(tpci, HEX); - if(secure(request.data() + APDU_LPDU_DIFF, kSecureSyncRequest, _deviceObj.individualAddress(), dstAddr, dstAddrIsGroupAddr, tpci, asdu, sizeof(asdu), secCtrl, systemBcast)) + if (secure(request.data() + APDU_LPDU_DIFF, kSecureSyncRequest, _deviceObj.individualAddress(), dstAddr, dstAddrIsGroupAddr, tpci, asdu, sizeof(asdu), secCtrl, systemBcast)) { println("SyncRequest: "); request.apdu().printPDU(); @@ -653,7 +688,7 @@ void SecureApplicationLayer::sendSyncRequest(uint16_t dstAddr, bool dstAddrIsGro } } -void SecureApplicationLayer::sendSyncResponse(uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl &secCtrl, uint64_t remoteNextSeqNum, bool systemBcast) +void SecureApplicationLayer::sendSyncResponse(uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl& secCtrl, uint64_t remoteNextSeqNum, bool systemBcast) { if (secCtrl.dataSecurity != DataSecurity::AuthConf) { @@ -668,9 +703,10 @@ void SecureApplicationLayer::sendSyncResponse(uint16_t dstAddr, bool dstAddrIsGr sixBytesFromUInt64(remoteNextSeqNum, &asdu[6]); 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! + // Note: additional TPCI byte is already handled internally! uint8_t tpci = 0; + if (!_syncReqBroadcastIncoming) { if (isConnected()) @@ -678,10 +714,11 @@ void SecureApplicationLayer::sendSyncResponse(uint16_t dstAddr, bool dstAddrIsGr 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)) + if (secure(response.data() + APDU_LPDU_DIFF, kSecureSyncResponse, _deviceObj.individualAddress(), dstAddr, dstAddrIsGroupAddr, tpci, asdu, sizeof(asdu), secCtrl, systemBcast)) { _lastSyncRes = millis(); @@ -712,7 +749,7 @@ void SecureApplicationLayer::sendSyncResponse(uint16_t dstAddr, bool dstAddrIsGr } } -void SecureApplicationLayer::receivedSyncRequest(uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl &secCtrl, uint8_t* seqNum, uint64_t challenge, bool systemBcast) +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:"); @@ -735,7 +772,7 @@ void SecureApplicationLayer::receivedSyncRequest(uint16_t srcAddr, uint16_t dstA sendSyncResponse(toAddr, toIsGroupAddress, secCtrl, nextSeqNum, systemBcast); } -void SecureApplicationLayer::receivedSyncResponse(uint16_t remote, const SecurityControl &secCtrl, uint8_t* plainApdu) +void SecureApplicationLayer::receivedSyncResponse(uint16_t remote, const SecurityControl& secCtrl, uint8_t* plainApdu) { println("Received SyncResponse:"); @@ -762,6 +799,7 @@ void SecureApplicationLayer::receivedSyncResponse(uint16_t remote, const Securit uint64_t localSeq = sixBytesToUInt64(plainApdu + 6); 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); @@ -769,7 +807,9 @@ void SecureApplicationLayer::receivedSyncResponse(uint16_t remote, const Securit } uint64_t next = nextSequenceNumber(secCtrl.toolAccess); - if (localSeq > next) { + + if (localSeq > next) + { //logger.debug("sync.res update local next {} seq -> {}", toolAccess ? "tool access" : "p2p", localSeq); updateSequenceNumber(secCtrl.toolAccess, localSeq); } @@ -804,6 +844,7 @@ bool SecureApplicationLayer::decrypt(uint8_t* plainApdu, uint16_t plainApduLengt //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: "); @@ -838,7 +879,7 @@ bool SecureApplicationLayer::decrypt(uint8_t* plainApdu, uint16_t plainApduLengt } } } - else if(syncReq) + else if (syncReq) { pBuf = popByteArray(knxSerialNumber, 6, pBuf); remainingPlainApduLength -= 6; @@ -847,6 +888,7 @@ bool SecureApplicationLayer::decrypt(uint8_t* plainApdu, uint16_t plainApduLengt if (!memcmp(knxSerialNumber, _deviceObj.propertyData(PID_SERIAL_NUMBER), 6)) { uint8_t emptySerialNumber[6] = {0}; + if (systemBroadcast || dstAddr != _deviceObj.individualAddress() || !memcmp(knxSerialNumber, emptySerialNumber, 6)) return false; } @@ -860,7 +902,8 @@ bool SecureApplicationLayer::decrypt(uint8_t* plainApdu, uint16_t plainApduLengt else if (syncRes) { // fetch challenge depending on srcAddr to handle multiple requests - uint64_t *challenge = _pendingOutgoingSyncRequests.get(IndAddr(srcAddr)); + uint64_t* challenge = _pendingOutgoingSyncRequests.get(IndAddr(srcAddr)); + if (challenge == nullptr) { println("Cannot find matching challenge for source address!"); @@ -869,6 +912,7 @@ bool SecureApplicationLayer::decrypt(uint8_t* plainApdu, uint16_t plainApduLengt 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++) @@ -885,12 +929,12 @@ bool SecureApplicationLayer::decrypt(uint8_t* plainApdu, uint16_t plainApduLengt // 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"); -*/ + /* + 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 @@ -907,6 +951,7 @@ bool SecureApplicationLayer::decrypt(uint8_t* plainApdu, uint16_t plainApduLengt // Only check the MAC uint32_t calculatedMac = calcAuthOnlyMac(plainApdu, remainingPlainApduLength, key, iv, ctr0); + if (calculatedMac != mac) { // security failure @@ -946,16 +991,19 @@ bool SecureApplicationLayer::decrypt(uint8_t* plainApdu, uint16_t plainApduLengt // 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)); -*/ + + /* + 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 @@ -993,7 +1041,7 @@ bool SecureApplicationLayer::decrypt(uint8_t* plainApdu, uint16_t plainApduLengt print(" seq from "); print(srcAddr, HEX); print(" -> (+1) "); - println(receivedSeqNumber,HEX); + println(receivedSeqNumber, HEX); updateSequenceNumber(toolAccess, receivedSeqNumber + 1); } else @@ -1037,7 +1085,7 @@ bool SecureApplicationLayer::decodeSecureApdu(APDU& secureApdu, APDU& plainApdu, // 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)) + if (decrypt(plainApdu.frame().data() + APDU_LPDU_DIFF, plainApdu.length() + 1, srcAddress, dstAddress, isDstAddrGroupAddr, tpci, secureApdu.data() + 1, secCtrl, isSystemBroadcast)) { println("decodeSecureApdu: Plain APDU: "); plainApdu.frame().apdu().printPDU(); @@ -1061,6 +1109,7 @@ bool SecureApplicationLayer::secure(uint8_t* buffer, uint16_t service, uint16_t println("Error: tool access requires auth+conf security"); return false; } + if (dstAddrIsGroupAddr && dstAddr != 0) { println("Error: tool access requires individual address"); @@ -1069,6 +1118,7 @@ bool SecureApplicationLayer::secure(uint8_t* buffer, uint16_t service, uint16_t } const uint8_t* key = toolAccess ? _secIfObj.toolKey() : securityKey(dstAddr, dstAddrIsGroupAddr); + if (key == nullptr) { print("Error: No key found. toolAccess: "); @@ -1094,17 +1144,20 @@ bool SecureApplicationLayer::secure(uint8_t* buffer, uint16_t service, uint16_t pBuf = pushByte(scf, pBuf); // SCF uint64_t seqSend = nextSequenceNumber(toolAccess); + if (seqSend == 0) println("0 is not a valid sequence number"); uint8_t seq[6]; sixBytesFromUInt64(seqSend, seq); + if (!syncRes) pBuf = pushByteArray(seq, 6, pBuf); // Sequence Number // Prepare associated data depending on service (SyncRequest, SyncResponse or just DataService) uint8_t associatedData[syncReq ? 7 : 1]; associatedData[0] = scf; + if (syncReq) { // TODO: NYI lookup serial number of target device for SBC sync.req @@ -1123,7 +1176,8 @@ bool SecureApplicationLayer::secure(uint8_t* buffer, uint16_t service, uint16_t Addr remote = _syncReqBroadcastIncoming ? (Addr)GrpAddr(0) : (Addr)IndAddr(dstAddr); // Get challenge from sync.req - uint64_t *challenge = _pendingIncomingSyncRequests.get(remote); + uint64_t* challenge = _pendingIncomingSyncRequests.get(remote); + if (challenge == nullptr) { println("Cannot send sync.res without corresponding sync.req"); @@ -1133,6 +1187,7 @@ bool SecureApplicationLayer::secure(uint8_t* buffer, uint16_t service, uint16_t { _pendingIncomingSyncRequests.erase(remote); } + uint8_t challengeSixBytes[6]; sixBytesFromUInt64(*challenge, challengeSixBytes); //printHex("Decrypted challenge: ", challengeSixBytes, 6); @@ -1140,10 +1195,12 @@ bool SecureApplicationLayer::secure(uint8_t* buffer, uint16_t service, uint16_t // 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); } @@ -1153,12 +1210,12 @@ bool SecureApplicationLayer::secure(uint8_t* buffer, uint16_t service, uint16_t // 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"); -*/ + /* + 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 @@ -1169,11 +1226,11 @@ bool SecureApplicationLayer::secure(uint8_t* buffer, uint16_t service, uint16_t if (confidentiality) { // Do calculations for Auth+Conf -/* - printHex("APDU--------->", apdu, apduLength); - printHex("Key---------->", key, 16); - printHex("ASSOC-------->", associatedData, sizeof(associatedData)); -*/ + /* + printHex("APDU--------->", apdu, apduLength); + printHex("Key---------->", key, 16); + printHex("ASSOC-------->", associatedData, sizeof(associatedData)); + */ uint32_t mac = calcConfAuthMac(associatedData, sizeof(associatedData), apdu, apduLength, key, iv); uint8_t tmpBuffer[4 + apduLength]; @@ -1215,10 +1272,12 @@ bool SecureApplicationLayer::createSecureApdu(APDU& plainApdu, APDU& secureApdu, bool isDstAddrGroupAddr = plainApdu.frame().addressType() == GroupAddress; bool isSystemBroadcast = plainApdu.frame().systemBroadcast(); uint8_t tpci = 0x00; + if (isConnected()) { tpci |= 0x40 | _transportLayer->getTpciSeqNum(); // get next TPCI sequence number for MAC calculation from TL (T_DATA_CONNECTED) } + print("createSecureApdu: TPCI: "); println(tpci, HEX); // Note: @@ -1232,14 +1291,14 @@ bool SecureApplicationLayer::createSecureApdu(APDU& plainApdu, APDU& secureApdu, // 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)) + 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); + println(nextSequenceNumber(secCtrl.toolAccess), HEX); updateSequenceNumber(secCtrl.toolAccess, nextSequenceNumber(secCtrl.toolAccess) + 1); println("createSecureApdu: Secure APDU: "); @@ -1264,7 +1323,7 @@ void SecureApplicationLayer::loop() bool SecureApplicationLayer::isSyncService(APDU& secureApdu) { - uint8_t scf = *(secureApdu.data()+1); + 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)) diff --git a/src/knx/secure_application_layer.h b/src/knx/secure_application_layer.h index 5b213b33..d89d82f1 100644 --- a/src/knx/secure_application_layer.h +++ b/src/knx/secure_application_layer.h @@ -14,136 +14,149 @@ 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 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 - { - 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 + 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 { - println("Unknown address type detected!"); - return false; + if ((cmpAddr.addrType == AddrType::unknown) || (addrType == AddrType::unknown)) + { + println("Unknown address type detected!"); + return false; + } + + return (cmpAddr.addr == addr) && (cmpAddr.addrType == addrType); } - return (cmpAddr.addr == addr) && (cmpAddr.addrType == addrType); - } - }; + }; - struct GrpAddr : Addr - { - GrpAddr() {addrType = AddrType::group;} - GrpAddr(uint8_t addr) : Addr{addr} {addrType = AddrType::group;} - }; + struct GrpAddr : Addr + { + 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} { addrType = AddrType::individual; } - }; + struct IndAddr : Addr + { + 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; }; diff --git a/src/knx/security_interface_object.cpp b/src/knx/security_interface_object.cpp index bf0cdde9..69e9558f 100644 --- a/src/knx/security_interface_object.cpp +++ b/src/knx/security_interface_object.cpp @@ -20,136 +20,149 @@ 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) - 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); + // 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; - if (serviceId != 0) - { - resultData[0] = ReturnCodes::InvalidCommand; - resultLength = 1; - return; - } - if (length == 3) - { - uint8_t mode = data[2]; - if (mode > 1) - { - resultData[0] = ReturnCodes::DataVoid; - resultLength = 1; - return; - } - obj->setSecurityMode(mode == 1); - resultData[0] = ReturnCodes::Success; - resultData[1] = serviceId; - resultLength = 2; - return; - } - resultData[0] = ReturnCodes::GenericError; + // 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; - }, - // 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) + return; + } + if (length == 3) + { + uint8_t mode = data[2]; + + if (mode > 1) { - resultData[0] = ReturnCodes::InvalidCommand; + resultData[0] = ReturnCodes::DataVoid; 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; + + 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 (id == 0 && info == 0) - { - obj->clearFailureLog(); - resultData[0] = ReturnCodes::Success; - resultData[1] = id; - resultLength = 2; - return; - } - resultData[0] = ReturnCodes::GenericError; + // 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; - }, - // 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]; + return; + } + uint8_t id = data[1]; + uint8_t info = data[2]; - // failure counters - if (id == 0 && info == 0) + 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; + resultLength = 1; + return; + } + uint8_t id = data[1]; + uint8_t info = data[2]; + + // 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] = info; - obj->getFailureCounters(&resultData[3]); // Put 8 bytes in the buffer - resultLength = 3 + 8; + resultData[2] = index; + resultLength += numBytes; + resultLength = 3 + numBytes; 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; - } - resultData[0] = ReturnCodes::DataVoid; - resultData[1] = id; - resultLength = 2; - return; - } - resultData[0] = ReturnCodes::GenericError; - resultLength = 1; - }), + + 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 @@ -236,15 +249,19 @@ void SecurityInterfaceObject::loadEvent(const uint8_t* data) 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; @@ -254,6 +271,7 @@ void SecurityInterfaceObject::loadEvent(const uint8_t* data) void SecurityInterfaceObject::loadEventUnloaded(const uint8_t* data) { uint8_t event = data[0]; + switch (event) { case LE_NOOP: @@ -261,9 +279,11 @@ void SecurityInterfaceObject::loadEventUnloaded(const uint8_t* data) 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); @@ -273,17 +293,21 @@ void SecurityInterfaceObject::loadEventUnloaded(const uint8_t* data) void SecurityInterfaceObject::loadEventLoading(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); @@ -294,21 +318,26 @@ void SecurityInterfaceObject::loadEventLoading(const uint8_t* data) void SecurityInterfaceObject::loadEventLoaded(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); @@ -318,6 +347,7 @@ void SecurityInterfaceObject::loadEventLoaded(const uint8_t* data) void SecurityInterfaceObject::loadEventError(const uint8_t* data) { uint8_t event = data[0]; + switch (event) { case LE_NOOP: @@ -325,9 +355,11 @@ void SecurityInterfaceObject::loadEventError(const uint8_t* data) 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); @@ -338,6 +370,7 @@ void SecurityInterfaceObject::loadState(LoadState newState) { if (newState == _state) return; + //beforeStateChange(newState); _state = newState; } @@ -381,14 +414,17 @@ const uint8_t* SecurityInterfaceObject::p2pKey(uint16_t addressIndex) // Search for address index uint8_t entry[elementSize]; // 2 bytes index + keysize (16 bytes) + 2 bytes(roles) = 20 bytes + for (int i = 1; i <= numElements; i++) { 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); @@ -413,14 +449,17 @@ const uint8_t* SecurityInterfaceObject::groupKey(uint16_t addressIndex) // Search for address index uint8_t entry[elementSize]; // 2 bytes index + keysize (16 bytes) = 18 bytes + for (int i = 1; i <= numElements; i++) { 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); @@ -442,10 +481,12 @@ uint16_t SecurityInterfaceObject::indAddressIndex(uint16_t indAddr) // Search for individual address uint8_t entry[elementSize]; // 2 bytes address + 6 bytes seqno = 8 bytes + for (int i = 1; i <= numElements; i++) { property(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE)->read(i, 1, entry); uint16_t addr = (entry[0] << 8) | entry[1]; + if (addr == indAddr) { return i; @@ -499,16 +540,19 @@ uint64_t SecurityInterfaceObject::getLastValidSequenceNumber(uint16_t deviceAddr // Search for individual address uint8_t entry[elementSize]; // 2 bytes address + 6 bytes seqno = 8 bytes + for (int i = 1; i <= numElements; i++) { 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; } @@ -523,10 +567,12 @@ void SecurityInterfaceObject::setLastValidSequenceNumber(uint16_t deviceAddr, ui // Search for individual address uint8_t entry[elementSize]; // 2 bytes address + 6 bytes seqno = 8 bytes + for (int i = 1; i <= numElements; i++) { 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]); diff --git a/src/knx/security_interface_object.h b/src/knx/security_interface_object.h index 9a328965..37f78f9a 100644 --- a/src/knx/security_interface_object.h +++ b/src/knx/security_interface_object.h @@ -8,57 +8,57 @@ class SecurityInterfaceObject: public InterfaceObject { -public: - SecurityInterfaceObject(); + 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[]; + // Our FDSK + static const uint8_t _fdsk[]; + static uint8_t _secReport[]; + static uint8_t _secReportCtrl[]; }; #endif diff --git a/src/knx/service_families.h b/src/knx/service_families.h index 5120e4f7..e4b49ed7 100644 --- a/src/knx/service_families.h +++ b/src/knx/service_families.h @@ -1,15 +1,15 @@ #ifndef KNX_SERVICE_FAMILY_CORE -#define KNX_SERVICE_FAMILY_CORE 1 + #define KNX_SERVICE_FAMILY_CORE 1 #endif #ifndef KNX_SERVICE_FAMILY_DEVICE_MANAGEMENT -#define KNX_SERVICE_FAMILY_DEVICE_MANAGEMENT 1 + #define KNX_SERVICE_FAMILY_DEVICE_MANAGEMENT 1 #endif #ifndef KNX_SERVICE_FAMILY_TUNNELING -#define KNX_SERVICE_FAMILY_TUNNELING 1 + #define KNX_SERVICE_FAMILY_TUNNELING 1 #endif #ifndef KNX_SERVICE_FAMILY_ROUTING -#define KNX_SERVICE_FAMILY_ROUTING 1 + #define KNX_SERVICE_FAMILY_ROUTING 1 #endif \ No newline at end of file diff --git a/src/knx/simple_map.h b/src/knx/simple_map.h index ff8df241..c04a79f0 100644 --- a/src/knx/simple_map.h +++ b/src/knx/simple_map.h @@ -11,121 +11,124 @@ template class Map { -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++) + 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 empty() + { + return (_validEntries == 0); + } - bool insert(K key, V value) - { - uint8_t index = getNextFreeIndex(); - if (index != noFreeEntryFoundIndex) + uint8_t size() { - keys[index] = key; - values[index] = value; + uint8_t size = 0; + + for (uint8_t i = 0; i < SIZE; i++) + { + size += (((_validEntries >> i) & 0x01) == 0x01) ? 1 : 0; + } - _validEntries |= 1 << index; - return true; + 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; - bool insertOrAssign(K key, V value) - { - // Try to find the key - for (uint8_t i = 0; i < SIZE; i++) + _validEntries |= 1 << index; + return true; + } + + // 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; }; diff --git a/src/knx/table_object.cpp b/src/knx/table_object.cpp index 993277c1..cef83bea 100644 --- a/src/knx/table_object.cpp +++ b/src/knx/table_object.cpp @@ -19,7 +19,7 @@ BeforeTablesUnloadCallback TableObject::beforeTablesUnloadCallback() return _beforeTablesUnload; } -TableObject::TableObject(Memory& memory, uint32_t staticTableAdr , uint32_t staticTableSize) +TableObject::TableObject(Memory& memory, uint32_t staticTableAdr, uint32_t staticTableSize) : _memory(memory) { _staticTableAdr = staticTableAdr; @@ -33,10 +33,14 @@ void TableObject::beforeStateChange(LoadState& newState) { if (newState == LS_LOADED && _tableUnloadCount > 0) _tableUnloadCount--; + if (_tableUnloadCount > 0) return; - if (newState == LS_UNLOADED) { + + if (newState == LS_UNLOADED) + { _tableUnloadCount++; + if (_beforeTablesUnload != 0) _beforeTablesUnload(); } @@ -51,6 +55,7 @@ void TableObject::loadState(LoadState newState) { if (newState == _state) return; + beforeStateChange(newState); _state = newState; } @@ -92,6 +97,7 @@ const uint8_t* TableObject::restore(const uint8_t* buffer) _data = _memory.toAbsolute(relativeAddress); else _data = 0; + //println((uint32_t)_data); return InterfaceObject::restore(buffer); } @@ -103,7 +109,7 @@ uint32_t TableObject::tableReference() bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte) { - if(_staticTableAdr) + if (_staticTableAdr) return false; if (_data) @@ -116,14 +122,16 @@ bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte) return true; _data = _memory.allocMemory(size); + if (!_data) return false; if (doFill) { uint32_t addr = _memory.toRelative(_data); - for(uint32_t i = 0; i < size;i++) - _memory.writeMemory(addr+i, 1, &fillByte); + + for (uint32_t i = 0; i < size; i++) + _memory.writeMemory(addr + i, 1, &fillByte); } _size = size; @@ -134,7 +142,7 @@ bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte) void TableObject::allocTableStatic() { - if(_staticTableAdr && !_data) + if (_staticTableAdr && !_data) { _data = _memory.toAbsolute(_staticTableAdr); _size = _staticTableSize; @@ -150,15 +158,19 @@ void TableObject::loadEvent(const uint8_t* data) 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; @@ -168,6 +180,7 @@ void TableObject::loadEvent(const uint8_t* data) void TableObject::loadEventUnloaded(const uint8_t* data) { uint8_t event = data[0]; + switch (event) { case LE_NOOP: @@ -175,9 +188,11 @@ void TableObject::loadEventUnloaded(const uint8_t* data) 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); @@ -187,21 +202,26 @@ void TableObject::loadEventUnloaded(const uint8_t* data) 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); @@ -211,30 +231,37 @@ void TableObject::loadEventLoading(const uint8_t* data) void TableObject::loadEventLoaded(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); + //free nv memory if (_data) { - if(!_staticTableAdr) + if (!_staticTableAdr) { _memory.freeMemory(_data); _data = 0; } } + break; + case LE_ADDITIONAL_LOAD_CONTROLS: loadState(LS_ERROR); errorCode(E_INVALID_OPCODE); break; + default: loadState(LS_ERROR); errorCode(E_GOT_UNDEF_LOAD_CMD); @@ -244,6 +271,7 @@ void TableObject::loadEventLoaded(const uint8_t* data) void TableObject::loadEventError(const uint8_t* data) { uint8_t event = data[0]; + switch (event) { case LE_NOOP: @@ -251,9 +279,11 @@ void TableObject::loadEventError(const uint8_t* data) 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); @@ -272,6 +302,7 @@ void TableObject::additionalLoadControls(const uint8_t* 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]; + if (!allocTable(size, doFill, fillByte)) { loadState(LS_ERROR); @@ -301,22 +332,22 @@ void TableObject::initializeProperties(size_t propertiesSize, Property** propert 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; - } - - data[0] = obj->_state; - return 1; - }, - [](TableObject* obj, uint16_t start, uint8_t count, const uint8_t* data) -> uint8_t { - obj->loadEvent(data); + [](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; - }) - }; + } + + 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; + }) + }; uint8_t ownPropertiesCount = sizeof(ownProperties) / sizeof(Property*); @@ -327,7 +358,7 @@ void TableObject::initializeProperties(size_t propertiesSize, Property** propert memcpy(allProperties, properties, propertiesSize); memcpy(allProperties + propertyCount, ownProperties, sizeof(ownProperties)); - if(_staticTableAdr) + if (_staticTableAdr) InterfaceObject::initializeProperties(sizeof(allProperties), allProperties); else initializeDynTableProperties(sizeof(allProperties), allProperties); @@ -338,37 +369,37 @@ void TableObject::initializeDynTableProperties(size_t propertiesSize, Property** 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); + [](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; - }), + [](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*); diff --git a/src/knx/table_object.h b/src/knx/table_object.h index 61520c62..914bb2e8 100644 --- a/src/knx/table_object.h +++ b/src/knx/table_object.h @@ -11,84 +11,84 @@ typedef void (*BeforeTablesUnloadCallback)(); */ class TableObject: public InterfaceObject { - friend class Memory; + 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); - - /** - * 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; + 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); - /** - * 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; + /** + * 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; }; diff --git a/src/knx/tp_frame.h b/src/knx/tp_frame.h index f1bbf766..7f576fe4 100644 --- a/src/knx/tp_frame.h +++ b/src/knx/tp_frame.h @@ -32,274 +32,278 @@ 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() - { - 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 = (uint8_t *)malloc(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 = (uint8_t *)malloc(_maxSize); - _size = 0; - } - - /* - * Free the data area - */ - ~TpFrame() - { - free(_data); - } - - /* - * Add a byte at end. - * Used for incoming parsing. - */ - inline void addByte(uint8_t byte) - { - if (!isFull()) + 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 = (uint8_t*)malloc(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() - { - return _size; - } - - /* - * Returns the assigned flags - */ - inline uint16_t flags() - { - return _flags; - } - - /* - * Adds one or more flags - */ - inline void addFlags(uint8_t flags) - { - _flags |= flags; - } - - /* - * Returns a pointer to the data - */ - inline uint8_t *data() - { - 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() - { - return (_data[0] & 0xD3) == 0x10; - } - - /* - * Returns the source - * Assumes that enough data has been imported. - */ - inline uint16_t source() - { - return isExtended() ? (_data[2] << 8) + _data[3] : (_data[1] << 8) + _data[2]; - } - - inline std::string humanSource() - { - uint16_t value = source(); - char buffer[10]; - sprintf(buffer, "%02i.%02i.%03i", (value >> 12 & 0b1111), (value >> 8 & 0b1111), (value & 0b11111111)); - return buffer; - } - - inline std::string humanDestination() - { - uint16_t value = destination(); - char buffer[10]; - if (isGroupAddress()) - sprintf(buffer, "%02i/%02i/%03i", (value >> 11 & 0b1111), (value >> 8 & 0b111), (value & 0b11111111)); - else + } + + /* + * Create a TpFrame with a reserved space. + * Used for incoming parsing. + */ + TpFrame(uint16_t maxSize = 263) + : _maxSize(maxSize) + { + _data = (uint8_t*)malloc(_maxSize); + _size = 0; + } + + /* + * Free the data area + */ + ~TpFrame() + { + free(_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() + { + return _size; + } + + /* + * Returns the assigned flags + */ + inline uint16_t flags() + { + return _flags; + } + + /* + * Adds one or more flags + */ + inline void addFlags(uint8_t flags) + { + _flags |= flags; + } + + /* + * Returns a pointer to the data + */ + inline uint8_t* data() + { + 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() + { + return (_data[0] & 0xD3) == 0x10; + } + + /* + * Returns the source + * Assumes that enough data has been imported. + */ + inline uint16_t source() + { + return isExtended() ? (_data[2] << 8) + _data[3] : (_data[1] << 8) + _data[2]; + } + + inline std::string humanSource() + { + uint16_t value = source(); + char buffer[10]; sprintf(buffer, "%02i.%02i.%03i", (value >> 12 & 0b1111), (value >> 8 & 0b1111), (value & 0b11111111)); + return buffer; + } - return buffer; - } - - /* - * Returns the destination - * Assumes that enough data has been imported. - */ - inline uint16_t destination() - { - 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() - { - 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 = (uint8_t *)malloc(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()) + inline std::string humanDestination() { - memcpy(cemiBuffer + 2, _data, fullSize() - 1); // -1 without CRC + uint16_t value = destination(); + char buffer[10]; + + if (isGroupAddress()) + sprintf(buffer, "%02i/%02i/%03i", (value >> 11 & 0b1111), (value >> 8 & 0b111), (value & 0b11111111)); + else + sprintf(buffer, "%02i.%02i.%03i", (value >> 12 & 0b1111), (value >> 8 & 0b1111), (value & 0b11111111)); + + return buffer; } - else + + /* + * Returns the destination + * Assumes that enough data has been imported. + */ + inline uint16_t destination() { - 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 isExtended() ? (_data[4] << 8) + _data[5] : (_data[3] << 8) + _data[4]; } - 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); - } + /* + * 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() + { + 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 = (uint8_t*)malloc(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); + } }; \ No newline at end of file diff --git a/src/knx/tpdu.cpp b/src/knx/tpdu.cpp index ae62db22..c5b2547d 100644 --- a/src/knx/tpdu.cpp +++ b/src/knx/tpdu.cpp @@ -41,28 +41,33 @@ void TPDU::type(TpduType type) { 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; + 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; } } @@ -115,13 +120,13 @@ CemiFrame& TPDU::frame() void TPDU::printPDU() { -/* print.print("TPDU: "); - print.print(type(), HEX, 2); - print.print(" "); - for (uint8_t i = 0; i < apdu().length() + 1; ++i) - { - if (i) print.print(" "); - print.print(_data[i], HEX, 2); - } - print.println()*/; + /* print.print("TPDU: "); + print.print(type(), HEX, 2); + print.print(" "); + for (uint8_t i = 0; i < apdu().length() + 1; ++i) + { + if (i) print.print(" "); + print.print(_data[i], HEX, 2); + } + print.println()*/; } \ No newline at end of file diff --git a/src/knx/tpdu.h b/src/knx/tpdu.h index b3fe7674..3dad00a3 100644 --- a/src/knx/tpdu.h +++ b/src/knx/tpdu.h @@ -7,30 +7,30 @@ class APDU; class TPDU { - friend class CemiFrame; + 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 printPDU(); + CemiFrame& frame(); + void printPDU(); - 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; }; diff --git a/src/knx/tpuart_data_link_layer.cpp b/src/knx/tpuart_data_link_layer.cpp index daab2173..b0eb7844 100644 --- a/src/knx/tpuart_data_link_layer.cpp +++ b/src/knx/tpuart_data_link_layer.cpp @@ -35,13 +35,13 @@ // Only on NCN51xx available #ifdef NCN5120 -#define U_CONFIGURE_REQ 0x18 -#define U_CONFIGURE_MARKER_REQ 0x1 -#define U_CONFIGURE_CRC_CCITT_REQ 0x2 -#define U_CONFIGURE_AUTO_POLLING_REQ 0x4 -#define U_SET_REPETITION_REQ 0xF2 + #define U_CONFIGURE_REQ 0x18 + #define U_CONFIGURE_MARKER_REQ 0x1 + #define U_CONFIGURE_CRC_CCITT_REQ 0x2 + #define U_CONFIGURE_AUTO_POLLING_REQ 0x4 + #define U_SET_REPETITION_REQ 0xF2 #else -#define U_MXRSTCNT 0x24 + #define U_MXRSTCNT 0x24 #endif // knx transmit data commands @@ -131,7 +131,7 @@ enum RX_AWAITING_ACK }; -void printFrame(TpFrame *tpframe) +void printFrame(TpFrame* tpframe) { print(tpframe->humanSource().c_str()); print(" -> "); @@ -305,6 +305,7 @@ void TpUartDataLinkLayer::processRxByte() _rxFrame->addFlags(TP_FRAME_FLAG_ACK); processRxFrameComplete(); } + // println("L_ACKN_IND"); } else if ((byte & L_DATA_CON_MASK) == L_DATA_CON) @@ -408,6 +409,7 @@ void TpUartDataLinkLayer::processRxFrameByte(uint8_t byte) { // Check whether I am responsible for the frame TPAckType ack = _cb.isAckRequired(_rxFrame->destination(), _rxFrame->isGroupAddress()); + if (_forceAck || ack) { /* @@ -431,6 +433,7 @@ void TpUartDataLinkLayer::processRxFrameByte(uint8_t byte) } #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)) { @@ -443,6 +446,7 @@ void TpUartDataLinkLayer::processRxFrameByte(uint8_t byte) } } } + #endif } } @@ -478,14 +482,16 @@ void TpUartDataLinkLayer::processRxFrameComplete() if (_txState == TX_FRAME) { // 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()) + 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 } + // 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) { @@ -499,6 +505,7 @@ void TpUartDataLinkLayer::processRxFrameComplete() _rxState = RX_AWAITING_ACK; return; } + _rxProcessdFrameCounter++; } else @@ -506,6 +513,7 @@ void TpUartDataLinkLayer::processRxFrameComplete() // Otherwise, discard the package and release the memory -> as it is not packed into the queue _rxIgnoredFrameCounter++; } + // And ready for control codes again _rxState = RX_IDLE; } @@ -545,7 +553,7 @@ void TpUartDataLinkLayer::clearTxFrameQueue() void TpUartDataLinkLayer::processTxFrameComplete(bool success) { - uint8_t *cemiData = _txFrame->cemiData(); + uint8_t* cemiData = _txFrame->cemiData(); CemiFrame cemiFrame(cemiData, _txFrame->cemiSize()); dataConReceived(cemiFrame, success); free(cemiData); @@ -557,9 +565,9 @@ void TpUartDataLinkLayer::processTxFrameComplete(bool success) /* * Puts the frame to be sent into a queue, as the TpUart may not yet be ready to send. */ -void TpUartDataLinkLayer::pushTxFrameQueue(TpFrame *tpFrame) +void TpUartDataLinkLayer::pushTxFrameQueue(TpFrame* tpFrame) { - knx_tx_queue_entry_t *entry = new knx_tx_queue_entry_t(tpFrame); + knx_tx_queue_entry_t* entry = new knx_tx_queue_entry_t(tpFrame); if (_txFrameQueue.back == nullptr) { @@ -585,7 +593,7 @@ void TpUartDataLinkLayer::setFrameRepetition(uint8_t nack, uint8_t busy) setRepetitions(nack, busy); } -bool TpUartDataLinkLayer::sendFrame(CemiFrame &cemiFrame) +bool TpUartDataLinkLayer::sendFrame(CemiFrame& cemiFrame) { _txFrameCounter++; @@ -600,7 +608,7 @@ bool TpUartDataLinkLayer::sendFrame(CemiFrame &cemiFrame) return false; } - TpFrame *tpFrame = new TpFrame(cemiFrame); + TpFrame* tpFrame = new TpFrame(cemiFrame); // printHex(" TP>: ", tpFrame->data(), tpFrame->size()); pushTxFrameQueue(tpFrame); return true; @@ -647,6 +655,7 @@ void TpUartDataLinkLayer::requestConfig() #ifdef NCN5120 if (markerMode()) _platform.writeUart(U_CONFIGURE_REQ | U_CONFIGURE_MARKER_REQ); + #endif // Deviating Config @@ -734,6 +743,7 @@ bool TpUartDataLinkLayer::reset() { _rxFrame->reset(); } + _rxState = RX_IDLE; _connected = false; _stopped = false; @@ -746,10 +756,12 @@ bool TpUartDataLinkLayer::reset() bool success = false; const uint32_t start = millis(); + // During startup answer took up to 2ms and normal 1ms do { const int byte = _platform.readUart(); + if (byte == -1) continue; // empty @@ -761,6 +773,7 @@ bool TpUartDataLinkLayer::reset() } while (!((millis() - start) >= 10)); connected(success); + if (success) { _lastStateRequest = 0; // Force @@ -848,7 +861,7 @@ void TpUartDataLinkLayer::processTxQueue() if (_txFrameQueue.front != nullptr) { - knx_tx_queue_entry_t *entry = _txFrameQueue.front; + knx_tx_queue_entry_t* entry = _txFrameQueue.front; _txFrameQueue.front = entry->next; if (_txFrameQueue.front == nullptr) @@ -943,16 +956,18 @@ void TpUartDataLinkLayer::loop() checkConnected(); } -void TpUartDataLinkLayer::rxFrameReceived(TpFrame *tpFrame) +void TpUartDataLinkLayer::rxFrameReceived(TpFrame* tpFrame) { - uint8_t *cemiData = tpFrame->cemiData(); + 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)); + #endif frameReceived(cemiFrame); @@ -971,6 +986,7 @@ DptMedium TpUartDataLinkLayer::mediumType() const 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 @@ -1011,19 +1027,21 @@ bool TpUartDataLinkLayer::processTxFrameBytes() } #ifdef KNX_ACTIVITYCALLBACK + 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, - BusAccessUnit& busAccessUnit, - ITpUartCallBacks &cb, - DataLinkLayerCallbacks *dllcb) +TpUartDataLinkLayer::TpUartDataLinkLayer(DeviceObject& devObj, + NetworkLayerEntity& netLayerEntity, + Platform& platform, + BusAccessUnit& busAccessUnit, + ITpUartCallBacks& cb, + DataLinkLayerCallbacks* dllcb) : DataLinkLayer(devObj, netLayerEntity, platform, busAccessUnit), _cb(cb), _dllcb(dllcb) @@ -1104,13 +1122,13 @@ bool TpUartDataLinkLayer::markerMode() return false; #ifdef NCN5120 - // return true; + // return true; #endif return false; } -void TpUartDataLinkLayer::processRxFrame(TpFrame *tpFrame) +void TpUartDataLinkLayer::processRxFrame(TpFrame* tpFrame) { if (_monitoring) { @@ -1136,6 +1154,7 @@ void TpUartDataLinkLayer::processRxFrame(TpFrame *tpFrame) printFrame(tpFrame); println(); #endif + if (!(tpFrame->flags() & TP_FRAME_FLAG_ECHO)) rxFrameReceived(tpFrame); } diff --git a/src/knx/tpuart_data_link_layer.h b/src/knx/tpuart_data_link_layer.h index 4fe8fe8d..a87d15bf 100644 --- a/src/knx/tpuart_data_link_layer.h +++ b/src/knx/tpuart_data_link_layer.h @@ -10,171 +10,171 @@ #define MAX_KNX_TELEGRAM_SIZE 263 #ifndef MAX_RX_QUEUE_BYTES -#define MAX_RX_QUEUE_BYTES MAX_KNX_TELEGRAM_SIZE + 50 + #define MAX_RX_QUEUE_BYTES MAX_KNX_TELEGRAM_SIZE + 50 #endif #ifndef MAX_TX_QUEUE -#define MAX_TX_QUEUE 50 + #define MAX_TX_QUEUE 50 #endif // __time_critical_func fallback #ifndef ARDUINO_ARCH_RP2040 -#define __time_critical_func(X) X -#define __isr + #define __time_critical_func(X) X + #define __isr #endif void printFrame(TpFrame* tpframe); class ITpUartCallBacks { - public: - virtual ~ITpUartCallBacks() = default; - virtual TPAckType isAckRequired(uint16_t address, bool isGrpAddr) = 0; + 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, BusAccessUnit& busAccessUnit, 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(); + using DataLinkLayer::_deviceObject; + using DataLinkLayer::_platform; + + public: + TpUartDataLinkLayer(DeviceObject& devObj, NetworkLayerEntity& netLayerEntity, + Platform& platform, BusAccessUnit& busAccessUnit, 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 { - } - }; - - // 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); + 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 + { + 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); + 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; + ITpUartCallBacks& _cb; + DataLinkLayerCallbacks* _dllcb; }; #endif diff --git a/src/knx/transport_layer.cpp b/src/knx/transport_layer.cpp index 78d7157e..55150363 100644 --- a/src/knx/transport_layer.cpp +++ b/src/knx/transport_layer.cpp @@ -18,7 +18,7 @@ void TransportLayer::networkLayer(NetworkLayer& layer) _networkLayer = &layer; } -void TransportLayer::groupAddressTable(AddressTableObject &addrTable) +void TransportLayer::groupAddressTable(AddressTableObject& addrTable) { _groupAddressTable = &addrTable; } @@ -34,332 +34,374 @@ void TransportLayer::dataIndividualIndication(uint16_t destination, HopCountType //} uint8_t sequenceNo = tpdu.sequenceNumber(); + switch (tpdu.type()) { - case DataInduvidual: - _applicationLayer.dataIndividualIndication(hopType, priority, source, tpdu.apdu()); - return; - case DataConnected: - if (source == _connectionAddress) - { - if (sequenceNo == _seqNoRecv) + case DataInduvidual: + _applicationLayer.dataIndividualIndication(hopType, priority, source, tpdu.apdu()); + return; + + case DataConnected: + if (source == _connectionAddress) { - //E4 - switch (_currentState) + if (sequenceNo == _seqNoRecv) { - case Closed: - //A0 nothing - break; - case OpenIdle: - case OpenWait: - A2(source, priority, tpdu.apdu()); - break; - case Connecting: - _currentState = Closed; - A6(destination); - break; + //E4 + switch (_currentState) + { + case Closed: + //A0 nothing + break; + + case OpenIdle: + case OpenWait: + A2(source, priority, tpdu.apdu()); + break; + + case Connecting: + _currentState = Closed; + A6(destination); + break; + } } - } - else if(sequenceNo == ((_seqNoRecv -1) & 0xF)) - { - //E5 - switch (_currentState) + else if (sequenceNo == ((_seqNoRecv - 1) & 0xF)) + { + //E5 + switch (_currentState) + { + case Closed: + //A0 + break; + + case OpenIdle: + case OpenWait: + case Connecting: + A3(source, priority, tpdu); + break; + } + } + else { - case Closed: - //A0 - break; - case OpenIdle: - case OpenWait: - case Connecting: - A3(source, priority, tpdu); - break; + //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); - break; - case Connecting: - A6(destination); - break; + case Closed: + case OpenIdle: + case OpenWait: + //A0 + break; + + case Connecting: + 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; - case Ack: - if (source == _connectionAddress) - { - if (sequenceNo == _seqNoSend) + + break; + + case Connect: + if (source == _connectionAddress) { - //E8 + //E0 switch (_currentState) { - case Closed: - case OpenIdle: - //A0 - break; - case OpenWait: - _currentState = OpenIdle; - A8(); - break; - case Connecting: - _currentState = Closed; - A6(source); - break; + case Closed: + _currentState = OpenIdle; + A1(source); + break; + + case OpenWait: + case OpenIdle: + case Connecting: + //A0: do nothing + break; } } else { - //E9 + //E1 switch (_currentState) { - case Closed: - case OpenIdle: - //A0 - break; - case OpenWait: - case Connecting: - _currentState = Closed; - A6(source); - break; - } - } - } - else - { - //E10 - switch (_currentState) - { - case Connecting: - A10(source); - break; - default: /* do nothing */ - break; + case Closed: + _currentState = OpenIdle; + A1(source); + break; + + case OpenIdle: + case OpenWait: + case Connecting: + A10(source); + break; + } } - } - break; - case Nack: - if (source == _connectionAddress) - { - if (sequenceNo != _seqNoSend) + + break; + + case Disconnect: + if (source == _connectionAddress) { - //E11 + //E2 switch (_currentState) { - case Closed: - case OpenIdle: - case OpenWait: - //A0 - break; - case Connecting: - _currentState = Closed; - A6(source); - break; + case Closed: + //A0 do nothing + break; + + case OpenIdle: + case OpenWait: + case Connecting: + _currentState = Closed; + 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: - //A0 - break; + case Closed: + case OpenIdle: + //A0 + break; + + case OpenWait: + _currentState = OpenIdle; + A8(); + break; + + case Connecting: + _currentState = Closed; + A6(source); + break; + } + } + else + { + //E9 + switch (_currentState) + { + case Closed: + case OpenIdle: + //A0 + break; + + case OpenWait: + case Connecting: + _currentState = Closed; + A6(source); + break; + } + } + } + else + { + //E10 + switch (_currentState) + { case Connecting: - case OpenIdle: - _currentState = Closed; - A6(source); + A10(source); break; - case OpenWait: - A9(); + + default: /* do nothing */ break; + } + } + + break; + + case Nack: + if (source == _connectionAddress) + { + if (sequenceNo != _seqNoSend) + { + //E11 + switch (_currentState) + { + case Closed: + case OpenIdle: + case OpenWait: + //A0 + break; + + case Connecting: + _currentState = Closed; + A6(source); + break; } } else { - //E13 - switch (_currentState) + 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 + { + //E14 + switch (_currentState) + { case Closed: - //A0 - break; case OpenIdle: case OpenWait: + //A0 + break; + case Connecting: - _currentState = Closed; - A6(source); + A10(source); + break; + + default: break; - } } } - } - else - { - //E14 - switch (_currentState) - { - case Closed: - case OpenIdle: - case OpenWait: - //A0 - break; - case Connecting: - A10(source); - break; - default: - break; - } - } - break; - default: - break; + + break; + + default: + break; } } void TransportLayer::dataIndividualConfirm(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu, bool status) { TpduType type = tpdu.type(); + switch (type) { - case DataInduvidual: - _applicationLayer.dataIndividualConfirm(ack, hopType, priority, destination, tpdu.apdu(), status); - break; - case DataConnected: - //E22 - //A0: do nothing - break; - case Connect: - if (status) - { - //E19 - switch (_currentState) + case DataInduvidual: + _applicationLayer.dataIndividualConfirm(ack, hopType, priority, destination, tpdu.apdu(), status); + break; + + case DataConnected: + //E22 + //A0: do nothing + break; + + case Connect: + if (status) { - case Closed: - case OpenIdle: - case OpenWait: - //A0: do nothing - break; - case Connecting: - _currentState = OpenIdle; - A13(destination); - break; + //E19 + switch (_currentState) + { + case Closed: + case OpenIdle: + case OpenWait: + //A0: do nothing + break; + + case Connecting: + _currentState = OpenIdle; + A13(destination); + break; + } } - } - else - { - //E20 - switch (_currentState) + else { - case Closed: - case OpenIdle: - case OpenWait: - //A0: do nothing - break; - case Connecting: - A5(destination); - break; + //E20 + switch (_currentState) + { + case Closed: + case OpenIdle: + case OpenWait: + //A0: do nothing + break; + + case Connecting: + A5(destination); + break; + } } - } - break; - case Disconnect: - //E21 - //A0: do nothing - break; - case Ack: - //E23 - //A0: do nothing - break; - case Nack: - //E24 - //A0: do nothing - break; - default: - break; - /* DataGroup and DataBroadcast should not appear here. If they do ignore them. */ + + break; + + case Disconnect: + //E21 + //A0: do nothing + break; + + case Ack: + //E23 + //A0: do nothing + break; + + case Nack: + //E24 + //A0: do nothing + break; + + default: + break; + /* DataGroup and DataBroadcast should not appear here. If they do ignore them. */ } } @@ -369,9 +411,10 @@ void TransportLayer::dataGroupIndication(uint16_t destination, HopCountType hopT return; uint16_t tsap = _groupAddressTable->getTsap(destination); + if (tsap == 0) return; - + _applicationLayer.dataGroupIndication(hopType, priority, tsap, tpdu.apdu()); } @@ -435,16 +478,17 @@ void TransportLayer::connectRequest(uint16_t destination, Priority priority) //E25 switch (_currentState) { - case Closed: - _currentState = Connecting; - A12(destination, priority); - break; - case OpenIdle: - case OpenWait: - case Connecting: - _currentState = Closed; - A6(destination); - break; + case Closed: + _currentState = Connecting; + A12(destination, priority); + break; + + case OpenIdle: + case OpenWait: + case Connecting: + _currentState = Closed; + A6(destination); + break; } } @@ -453,15 +497,16 @@ void TransportLayer::disconnectRequest(uint16_t tsap, Priority priority) //E26 switch (_currentState) { - case Closed: - A15(priority, tsap); - break; - case OpenIdle: - case OpenWait: - case Connecting: - _currentState = Closed; - A14(tsap, priority); - break; + case Closed: + A15(priority, tsap); + break; + + case OpenIdle: + case OpenWait: + case Connecting: + _currentState = Closed; + A14(tsap, priority); + break; } } @@ -472,19 +517,22 @@ void TransportLayer::dataConnectedRequest(uint16_t tsap, Priority priority, APDU //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; + case Closed: + //A0 + break; + + case OpenIdle: + _currentState = OpenWait; + A7(priority, apdu); + break; + + case OpenWait: + case Connecting: + A11(tsap, priority, apdu); + break; + + default: + break; } } @@ -493,15 +541,16 @@ void TransportLayer::connectionTimeoutIndication() //E16 switch (_currentState) { - case Closed: - //A0: do nothing - break; - case OpenIdle: - case OpenWait: - case Connecting: - _currentState = Closed; - A6(_connectionAddress); - break; + case Closed: + //A0: do nothing + break; + + case OpenIdle: + case OpenWait: + case Connecting: + _currentState = Closed; + A6(_connectionAddress); + break; } } @@ -512,14 +561,15 @@ void TransportLayer::ackTimeoutIndication() //E17 switch (_currentState) { - case Closed: - case OpenIdle: - case Connecting: - //A0: do nothing - break; - case OpenWait: - A9(); - break; + case Closed: + case OpenIdle: + case Connecting: + //A0: do nothing + break; + + case OpenWait: + A9(); + break; } } else @@ -527,15 +577,16 @@ void TransportLayer::ackTimeoutIndication() //E18 switch (_currentState) { - case Closed: - case OpenIdle: - case Connecting: - //A0: do nothing - break; - case OpenWait: - _currentState = Closed; - A6(_connectionAddress); - break; + case Closed: + case OpenIdle: + case Connecting: + //A0: do nothing + break; + + case OpenWait: + _currentState = Closed; + A6(_connectionAddress); + break; } } } @@ -557,12 +608,13 @@ uint16_t TransportLayer::getConnectionAddress() void TransportLayer::loop() { uint32_t milliseconds = millis(); - if (_connectionTimeoutEnabled - && (milliseconds - _connectionTimeoutStartMillis) > _connectionTimeoutMillis) + + if (_connectionTimeoutEnabled + && (milliseconds - _connectionTimeoutStartMillis) > _connectionTimeoutMillis) connectionTimeoutIndication(); if (_ackTimeoutEnabled - && (milliseconds - _ackTimeoutStartMillis) > _ackTimeoutMillis) + && (milliseconds - _ackTimeoutStartMillis) > _ackTimeoutMillis) ackTimeoutIndication(); if (_savedConnectingValid) @@ -580,7 +632,7 @@ void TransportLayer::sendControlTelegram(TpduType pduType, uint8_t seqNo) tpdu.type(pduType); tpdu.sequenceNumber(seqNo); _networkLayer->dataIndividualRequest(AckRequested, _connectionAddress, NetworkLayerParameter, - SystemPriority, tpdu); + SystemPriority, tpdu); } void TransportLayer::A0() @@ -600,6 +652,7 @@ void TransportLayer::A1(uint16_t source) void incSeqNr(uint8_t& seqNr) { seqNr += 1; + if (seqNr > 0xf) seqNr = 0; } diff --git a/src/knx/transport_layer.h b/src/knx/transport_layer.h index 8814cc33..a74d9b50 100644 --- a/src/knx/transport_layer.h +++ b/src/knx/transport_layer.h @@ -15,107 +15,107 @@ enum StateType { Closed, OpenIdle, OpenWait, Connecting }; class TransportLayer { -public: - TransportLayer(ApplicationLayer& layer); - void networkLayer(NetworkLayer& layer); - void groupAddressTable(AddressTableObject& addrTable); + 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 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); + #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 - uint8_t getTpciSeqNum(); - uint16_t getConnectionAddress(); -#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 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; + 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 + + #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; }; diff --git a/src/knx/usb_tunnel_interface.cpp b/src/knx/usb_tunnel_interface.cpp index 83889ea0..3eb02c07 100644 --- a/src/knx/usb_tunnel_interface.cpp +++ b/src/knx/usb_tunnel_interface.cpp @@ -26,8 +26,8 @@ #define PACKET_TYPE_END 2 #define PACKET_TYPE_PARTIAL 4 -//#define DEBUG_TX_HID_REPORT -//#define DEBUG_RX_HID_REPORT +//#define DEBUG_TX_HID_REPORT +//#define DEBUG_RX_HID_REPORT extern bool sendHidReport(uint8_t* data, uint16_t length); extern bool isSendHidReportPossible(); @@ -35,41 +35,41 @@ extern bool isSendHidReportPossible(); // class UsbTunnelInterface UsbTunnelInterface::UsbTunnelInterface(CemiServer& cemiServer, - uint16_t mId, - uint16_t mV) + uint16_t mId, + uint16_t mV) : _cemiServer(cemiServer), - _manufacturerId(mId), - _maskVersion(mV) + _manufacturerId(mId), + _maskVersion(mV) { } void UsbTunnelInterface::loop() { - // Make sure that the USB HW is also ready to send another report - if (!isTxQueueEmpty() && isSendHidReportPossible()) - { - uint8_t* buffer; - uint16_t length; - loadNextTxFrame(&buffer, &length); - sendHidReport(buffer, length); - delete buffer; - } - - // Check if we already a COMPLETE transport protocol packet - // A transport protocol packet might be split into multiple HID reports and - // need to be assembled again - if (rxHaveCompletePacket) - { - handleHidReportRxQueue(); - rxHaveCompletePacket = false; - } + // Make sure that the USB HW is also ready to send another report + if (!isTxQueueEmpty() && isSendHidReportPossible()) + { + uint8_t* buffer; + uint16_t length; + loadNextTxFrame(&buffer, &length); + sendHidReport(buffer, length); + delete buffer; + } + + // Check if we already a COMPLETE transport protocol packet + // A transport protocol packet might be split into multiple HID reports and + // need to be assembled again + if (rxHaveCompletePacket) + { + handleHidReportRxQueue(); + rxHaveCompletePacket = false; + } } /* USB TX */ void UsbTunnelInterface::sendCemiFrame(CemiFrame& frame) { - sendKnxHidReport(KnxTunneling, ServiceIdNotUsed, frame.data(), frame.dataLength()); + sendKnxHidReport(KnxTunneling, ServiceIdNotUsed, frame.data(), frame.dataLength()); } void UsbTunnelInterface::addBufferTxQueue(uint8_t* data, uint16_t length) @@ -80,8 +80,8 @@ void UsbTunnelInterface::addBufferTxQueue(uint8_t* data, uint16_t length) tx_buffer->data = new uint8_t[MAX_EP_SIZE]; // We always have to send full max. USB endpoint size of 64 bytes tx_buffer->next = nullptr; - memcpy(tx_buffer->data, data, tx_buffer->length); - memset(&tx_buffer->data[length], 0x00, MAX_EP_SIZE - length); // Set unused bytes to zero + memcpy(tx_buffer->data, data, tx_buffer->length); + memset(&tx_buffer->data[length], 0x00, MAX_EP_SIZE - length); // Set unused bytes to zero if (_tx_queue.back == nullptr) { @@ -100,6 +100,7 @@ bool UsbTunnelInterface::isTxQueueEmpty() { return true; } + return false; } @@ -109,6 +110,7 @@ void UsbTunnelInterface::loadNextTxFrame(uint8_t** sendBuffer, uint16_t* sendBuf { return; } + _queue_buffer_t* tx_buffer = _tx_queue.front; *sendBuffer = tx_buffer->data; *sendBufferLength = tx_buffer->length; @@ -118,88 +120,92 @@ void UsbTunnelInterface::loadNextTxFrame(uint8_t** sendBuffer, uint16_t* sendBuf { _tx_queue.back = nullptr; } + delete tx_buffer; #ifdef DEBUG_TX_HID_REPORT - print("TX HID report: len: "); - // We do not print the padded zeros - uint8_t len = (*sendBuffer)[2]; - println(len, DEC); - - for (int i = 0; i < len; i++) - { - if ((*sendBuffer)[i] < 16) - print("0"); - print((*sendBuffer)[i], HEX); - print(" "); - } - println(""); + print("TX HID report: len: "); + // We do not print the padded zeros + uint8_t len = (*sendBuffer)[2]; + println(len, DEC); + + for (int i = 0; i < len; i++) + { + if ((*sendBuffer)[i] < 16) + print("0"); + + print((*sendBuffer)[i], HEX); + print(" "); + } + + println(""); #endif } void UsbTunnelInterface::sendKnxHidReport(ProtocolIdType protId, ServiceIdType servId, uint8_t* data, uint16_t length) { - uint16_t maxData = MAX_DATASIZE_START_PACKET; - uint8_t packetType = PACKET_TYPE_START; - - if (length > maxData) - { - packetType |= PACKET_TYPE_PARTIAL; - } - - uint16_t offset = 0; - uint8_t* buffer = nullptr; - - // In theory we can only have sequence numbers from 1..5 - // First packet: 51 bytes max - // Other packets: 62 bytes max. - // -> 51 + 4*62 = 296 bytes -> enough for a KNX cEMI extended frame APDU + Transport Protocol Header length - for(uint8_t seqNum = 1; seqNum < 6; seqNum++) - { - uint16_t copyLen = MIN(length, maxData); - - // If this is the first packet we include the transport protocol header - if (packetType & PACKET_TYPE_START) - { - buffer = new uint8_t[copyLen + 8 + HID_HEADER_SIZE]; // length of transport protocol header: 11 bytes - buffer[2] = 8 + copyLen; // KNX USB Transfer Protocol Body length - buffer[3] = PROTOCOL_VERSION; // Protocol version (fixed 0x00) - buffer[4] = PROTOCOL_HEADER_LENGTH; // USB KNX Transfer Protocol Header Length (fixed 0x08) - pushWord(copyLen, &buffer[5]); // KNX USB Transfer Protocol Body length (e.g. cEMI length) - buffer[7] = (uint8_t) protId; // KNX Tunneling (0x01) or KNX Bus Access Server (0x0f) - buffer[8] = (protId == KnxTunneling) ? (uint8_t)CEMI : (uint8_t)servId; // either EMI ID or Service Id - buffer[9] = 0x00; // Manufacturer (fixed 0x00) see KNX Spec 9/3 p.23 3.4.1.3.5 - buffer[10] = 0x00; // Manufacturer (fixed 0x00) see KNX Spec 9/3 p.23 3.4.1.3.5 - memcpy(&buffer[11], &data[offset], copyLen); // Copy payload for KNX USB Transfer Protocol Body - } - else - { - buffer = new uint8_t[copyLen]; // no transport protocol header in partial packets - buffer[2] = copyLen; // KNX USB Transfer Protocol Body length - memcpy(&buffer[0], &data[offset], copyLen); // Copy payload for KNX USB Transfer Protocol Body - } - - offset += copyLen; - if (offset >= length) - { - packetType |= PACKET_TYPE_END; - } - - buffer[0] = KNX_HID_REPORT_ID; // ReportID (fixed 0x01) - buffer[1] = ((seqNum << 4) & 0xF0) | (packetType & 0x07); // PacketInfo (SeqNo and Type) - - addBufferTxQueue(buffer, (buffer[2] + HID_HEADER_SIZE)); - - delete[] buffer; - - if (offset >= length) - { - break; - } - - packetType &= ~PACKET_TYPE_START; - maxData = MAX_DATASIZE_PARTIAL_PACKET; - } + uint16_t maxData = MAX_DATASIZE_START_PACKET; + uint8_t packetType = PACKET_TYPE_START; + + if (length > maxData) + { + packetType |= PACKET_TYPE_PARTIAL; + } + + uint16_t offset = 0; + uint8_t* buffer = nullptr; + + // In theory we can only have sequence numbers from 1..5 + // First packet: 51 bytes max + // Other packets: 62 bytes max. + // -> 51 + 4*62 = 296 bytes -> enough for a KNX cEMI extended frame APDU + Transport Protocol Header length + for (uint8_t seqNum = 1; seqNum < 6; seqNum++) + { + uint16_t copyLen = MIN(length, maxData); + + // If this is the first packet we include the transport protocol header + if (packetType & PACKET_TYPE_START) + { + buffer = new uint8_t[copyLen + 8 + HID_HEADER_SIZE]; // length of transport protocol header: 11 bytes + buffer[2] = 8 + copyLen; // KNX USB Transfer Protocol Body length + buffer[3] = PROTOCOL_VERSION; // Protocol version (fixed 0x00) + buffer[4] = PROTOCOL_HEADER_LENGTH; // USB KNX Transfer Protocol Header Length (fixed 0x08) + pushWord(copyLen, &buffer[5]); // KNX USB Transfer Protocol Body length (e.g. cEMI length) + buffer[7] = (uint8_t) protId; // KNX Tunneling (0x01) or KNX Bus Access Server (0x0f) + buffer[8] = (protId == KnxTunneling) ? (uint8_t)CEMI : (uint8_t)servId; // either EMI ID or Service Id + buffer[9] = 0x00; // Manufacturer (fixed 0x00) see KNX Spec 9/3 p.23 3.4.1.3.5 + buffer[10] = 0x00; // Manufacturer (fixed 0x00) see KNX Spec 9/3 p.23 3.4.1.3.5 + memcpy(&buffer[11], &data[offset], copyLen); // Copy payload for KNX USB Transfer Protocol Body + } + else + { + buffer = new uint8_t[copyLen]; // no transport protocol header in partial packets + buffer[2] = copyLen; // KNX USB Transfer Protocol Body length + memcpy(&buffer[0], &data[offset], copyLen); // Copy payload for KNX USB Transfer Protocol Body + } + + offset += copyLen; + + if (offset >= length) + { + packetType |= PACKET_TYPE_END; + } + + buffer[0] = KNX_HID_REPORT_ID; // ReportID (fixed 0x01) + buffer[1] = ((seqNum << 4) & 0xF0) | (packetType & 0x07); // PacketInfo (SeqNo and Type) + + addBufferTxQueue(buffer, (buffer[2] + HID_HEADER_SIZE)); + + delete[] buffer; + + if (offset >= length) + { + break; + } + + packetType &= ~PACKET_TYPE_START; + maxData = MAX_DATASIZE_PARTIAL_PACKET; + } } /* USB RX */ @@ -207,21 +213,21 @@ void UsbTunnelInterface::sendKnxHidReport(ProtocolIdType protId, ServiceIdType s // Invoked when received SET_REPORT control request or via interrupt out pipe void UsbTunnelInterface::receiveHidReport(uint8_t const* data, uint16_t bufSize) { - // Check KNX ReportID (fixed 0x01) - if (data[0] == KNX_HID_REPORT_ID) - { - // We just store only the used space of the HID report buffer - // which is normally padded with 0 to fill the complete USB EP size (e.g. 64 bytes) - uint8_t packetLength = data[2] + HID_HEADER_SIZE; - UsbTunnelInterface::addBufferRxQueue(data, packetLength); - - // Check if packet type indicates last packet - if ((data[1] & PACKET_TYPE_END) == PACKET_TYPE_END) - { - // Signal main loop that we have a complete KNX USB packet - rxHaveCompletePacket = true; - } - } + // Check KNX ReportID (fixed 0x01) + if (data[0] == KNX_HID_REPORT_ID) + { + // We just store only the used space of the HID report buffer + // which is normally padded with 0 to fill the complete USB EP size (e.g. 64 bytes) + uint8_t packetLength = data[2] + HID_HEADER_SIZE; + UsbTunnelInterface::addBufferRxQueue(data, packetLength); + + // Check if packet type indicates last packet + if ((data[1] & PACKET_TYPE_END) == PACKET_TYPE_END) + { + // Signal main loop that we have a complete KNX USB packet + rxHaveCompletePacket = true; + } + } } UsbTunnelInterface::_queue_t UsbTunnelInterface::_rx_queue; @@ -235,11 +241,11 @@ void UsbTunnelInterface::addBufferRxQueue(const uint8_t* data, uint16_t length) rx_buffer->data = new uint8_t[rx_buffer->length]; rx_buffer->next = nullptr; - memcpy(rx_buffer->data, data, rx_buffer->length); + memcpy(rx_buffer->data, data, rx_buffer->length); if (_rx_queue.back == nullptr) { - _rx_queue.front =_rx_queue.back = rx_buffer; + _rx_queue.front = _rx_queue.back = rx_buffer; } else { @@ -254,6 +260,7 @@ bool UsbTunnelInterface::isRxQueueEmpty() { return true; } + return false; } @@ -263,6 +270,7 @@ void UsbTunnelInterface::loadNextRxBuffer(uint8_t** receiveBuffer, uint16_t* rec { return; } + _queue_buffer_t* rx_buffer = _rx_queue.front; *receiveBuffer = rx_buffer->data; *receiveBufferLength = rx_buffer->length; @@ -272,271 +280,286 @@ void UsbTunnelInterface::loadNextRxBuffer(uint8_t** receiveBuffer, uint16_t* rec { _rx_queue.back = nullptr; } + delete rx_buffer; #ifdef DEBUG_RX_HID_REPORT - print("RX HID report: len: "); - println(*receiveBufferLength, DEC); - - for (int i = 0; i < (*receiveBufferLength); i++) - { - if ((*receiveBuffer)[i] < 16) - print("0"); - print((*receiveBuffer)[i], HEX); - print(" "); - } - println(""); + print("RX HID report: len: "); + println(*receiveBufferLength, DEC); + + for (int i = 0; i < (*receiveBufferLength); i++) + { + if ((*receiveBuffer)[i] < 16) + print("0"); + + print((*receiveBuffer)[i], HEX); + print(" "); + } + + println(""); #endif } void UsbTunnelInterface::handleTransferProtocolPacket(uint8_t* data, uint16_t length) { - if (data[0] == PROTOCOL_VERSION && // Protocol version (fixed 0x00) - data[1] == PROTOCOL_HEADER_LENGTH) // USB KNX Transfer Protocol Header Length (fixed 0x08) - { - uint16_t bodyLength; - popWord(bodyLength, (uint8_t*)&data[2]); // KNX USB Transfer Protocol Body length - - if (data[4] == (uint8_t) BusAccessServer) // Bus Access Server Feature (0x0F) - { - handleBusAccessServerProtocol((ServiceIdType)data[5], &data[8], bodyLength); - } - else if (data[4] == (uint8_t) KnxTunneling) // KNX Tunneling (0x01) - { - if (data[5] == (uint8_t) CEMI) // EMI type: only cEMI supported (0x03)) - { - // Prepare the cEMI frame - CemiFrame frame((uint8_t*)&data[8], bodyLength); - /* - print("cEMI USB RX len: "); - print(length); - - print(" data: "); - printHex(" data: ", buffer, length); - */ - _cemiServer.frameReceived(frame); - } - else - { - println("Error: Only cEMI is supported!"); - } - } - } + if (data[0] == PROTOCOL_VERSION && // Protocol version (fixed 0x00) + data[1] == PROTOCOL_HEADER_LENGTH) // USB KNX Transfer Protocol Header Length (fixed 0x08) + { + uint16_t bodyLength; + popWord(bodyLength, (uint8_t*)&data[2]); // KNX USB Transfer Protocol Body length + + if (data[4] == (uint8_t) BusAccessServer) // Bus Access Server Feature (0x0F) + { + handleBusAccessServerProtocol((ServiceIdType)data[5], &data[8], bodyLength); + } + else if (data[4] == (uint8_t) KnxTunneling) // KNX Tunneling (0x01) + { + if (data[5] == (uint8_t) CEMI) // EMI type: only cEMI supported (0x03)) + { + // Prepare the cEMI frame + CemiFrame frame((uint8_t*)&data[8], bodyLength); + /* + print("cEMI USB RX len: "); + print(length); + + print(" data: "); + printHex(" data: ", buffer, length); + */ + _cemiServer.frameReceived(frame); + } + else + { + println("Error: Only cEMI is supported!"); + } + } + } } void UsbTunnelInterface::handleHidReportRxQueue() { - if (isRxQueueEmpty()) - { - println("Error: RX HID report queue was empty!"); - return; - } - - uint8_t tpPacket[MAX_KNX_TELEGRAM_SIZE + PROTOCOL_HEADER_LENGTH]; // Transport Protocol Header + Body - uint16_t offset = 0; - bool success = false; - - // Now we have to reassemble the whole transport protocol packet which might be distributed over multiple HID reports - - // In theory we can only have sequence numbers from 1..5 - // First packet: 51 bytes max - // Other packets: 62 bytes max. - // -> 51 + 4*62 = 296 bytes -> enough for a KNX cEMI extended frame APDU + Transport Protocol Header length - for(int expSeqNum = 1; expSeqNum < 6; expSeqNum++) - { - // We should have at least one packet: either single packet (START and END set) or - // start packet (START and PARTIAL set) -> thus load first part - uint8_t* data; - uint16_t bufSize; - loadNextRxBuffer(&data, &bufSize); // bufSize contains the complete HID report length incl. HID header - - // Get KNX HID report header details - uint8_t seqNum = data[1] >> 4; - uint8_t packetType = data[1] & 0x07; - uint8_t packetLength = MIN(data[2], bufSize - HID_HEADER_SIZE); // Do not try to read more than we actually have! - - // Does the received sequence number match the expected one? - if (expSeqNum != seqNum) - { - println("Error: Wrong sequence number!"); - delete data; - continue; - } - - // first RX buffer from queue should contain the first part of the transfer protocol packet - if ((expSeqNum == 1) && ((packetType & PACKET_TYPE_START) != PACKET_TYPE_START)) - { - println("Error: Sequence number 1 does not contain a START packet!"); - delete data; - continue; - } - - // Make sure we only have one START packet - if ((expSeqNum != 1) && ((packetType & PACKET_TYPE_START) == PACKET_TYPE_START)) - { - println("Error: Sequence number (!=1) contains a START packet!"); - delete data; - continue; - } - - // Make sure other packets are marked correctly as PARTIAL packet - if ((expSeqNum != 1) && ((packetType & PACKET_TYPE_PARTIAL) != PACKET_TYPE_PARTIAL)) - { - println("Error: Sequence number (!=1) must be a PARTIAL packet!"); - delete data; - continue; - } - - // Not really necessary, but we reset the offset here to zero - if ((packetType & PACKET_TYPE_START) == PACKET_TYPE_START) - { - offset = 0; - } - - // Copy KNX HID Report Body to final buffer for concatenating - memcpy(&tpPacket[offset], &data[3], packetLength); - // Remove the source HID report buffer - delete data; - // Move offset - offset += packetLength; - - // If we reached the end of the transport protocol packet, leave the loop - if ((packetType & PACKET_TYPE_END) == PACKET_TYPE_END) - { - success = true; - break; - } - } - - // Make sure that we really saw the end of the transport protocol packet - if (success) - { - handleTransferProtocolPacket(tpPacket, offset); - } - else - { - println("Error: Did not find END packet!"); - } + if (isRxQueueEmpty()) + { + println("Error: RX HID report queue was empty!"); + return; + } + + uint8_t tpPacket[MAX_KNX_TELEGRAM_SIZE + PROTOCOL_HEADER_LENGTH]; // Transport Protocol Header + Body + uint16_t offset = 0; + bool success = false; + + // Now we have to reassemble the whole transport protocol packet which might be distributed over multiple HID reports + + // In theory we can only have sequence numbers from 1..5 + // First packet: 51 bytes max + // Other packets: 62 bytes max. + // -> 51 + 4*62 = 296 bytes -> enough for a KNX cEMI extended frame APDU + Transport Protocol Header length + for (int expSeqNum = 1; expSeqNum < 6; expSeqNum++) + { + // We should have at least one packet: either single packet (START and END set) or + // start packet (START and PARTIAL set) -> thus load first part + uint8_t* data; + uint16_t bufSize; + loadNextRxBuffer(&data, &bufSize); // bufSize contains the complete HID report length incl. HID header + + // Get KNX HID report header details + uint8_t seqNum = data[1] >> 4; + uint8_t packetType = data[1] & 0x07; + uint8_t packetLength = MIN(data[2], bufSize - HID_HEADER_SIZE); // Do not try to read more than we actually have! + + // Does the received sequence number match the expected one? + if (expSeqNum != seqNum) + { + println("Error: Wrong sequence number!"); + delete data; + continue; + } + + // first RX buffer from queue should contain the first part of the transfer protocol packet + if ((expSeqNum == 1) && ((packetType & PACKET_TYPE_START) != PACKET_TYPE_START)) + { + println("Error: Sequence number 1 does not contain a START packet!"); + delete data; + continue; + } + + // Make sure we only have one START packet + if ((expSeqNum != 1) && ((packetType & PACKET_TYPE_START) == PACKET_TYPE_START)) + { + println("Error: Sequence number (!=1) contains a START packet!"); + delete data; + continue; + } + + // Make sure other packets are marked correctly as PARTIAL packet + if ((expSeqNum != 1) && ((packetType & PACKET_TYPE_PARTIAL) != PACKET_TYPE_PARTIAL)) + { + println("Error: Sequence number (!=1) must be a PARTIAL packet!"); + delete data; + continue; + } + + // Not really necessary, but we reset the offset here to zero + if ((packetType & PACKET_TYPE_START) == PACKET_TYPE_START) + { + offset = 0; + } + + // Copy KNX HID Report Body to final buffer for concatenating + memcpy(&tpPacket[offset], &data[3], packetLength); + // Remove the source HID report buffer + delete data; + // Move offset + offset += packetLength; + + // If we reached the end of the transport protocol packet, leave the loop + if ((packetType & PACKET_TYPE_END) == PACKET_TYPE_END) + { + success = true; + break; + } + } + + // Make sure that we really saw the end of the transport protocol packet + if (success) + { + handleTransferProtocolPacket(tpPacket, offset); + } + else + { + println("Error: Did not find END packet!"); + } } void UsbTunnelInterface::handleBusAccessServerProtocol(ServiceIdType servId, const uint8_t* requestData, uint16_t packetLength) { - uint8_t respData[3]; // max. 3 bytes are required for a response - - switch (servId) - { - case DeviceFeatureGet: // Device Feature Get - { - FeatureIdType featureId = (FeatureIdType)requestData[0]; - respData[0] = (uint8_t) featureId; // first byte in repsonse is the featureId itself again - - switch (featureId) - { - case SupportedEmiType: // Supported EMI types - println("Device Feature Get: Supported EMI types"); - respData[1] = 0x00; // USB KNX Transfer Protocol Body: Feature Data - respData[2] = 0x04; // USB KNX Transfer Protocol Body: Feature Data -> only cEMI supported - sendKnxHidReport(BusAccessServer, DeviceFeatureResponse, respData, 3); - break; - case HostDeviceDescriptorType0: // Host Device Descriptor Type 0 - println("Device Feature Get: Host Device Descriptor Type 0"); - pushWord(_maskVersion, &respData[1]); // USB KNX Transfer Protocol Body: Feature Data -> Mask version - sendKnxHidReport(BusAccessServer, DeviceFeatureResponse, respData, 3); - break; - case BusConnectionStatus: // Bus connection status - println("Device Feature Get: Bus connection status"); - respData[1] = 1; // USB KNX Transfer Protocol Body: Feature Data -> bus connection status - sendKnxHidReport(BusAccessServer, DeviceFeatureResponse, respData, 2); - break; - case KnxManufacturerCode: // KNX manufacturer code - println("Device Feature Get: KNX manufacturer code"); - pushWord(_manufacturerId, &respData[1]); // USB KNX Transfer Protocol Body: Feature Data -> Manufacturer Code - sendKnxHidReport(BusAccessServer, DeviceFeatureResponse, respData, 3); - break; - case ActiveEmiType: // Active EMI type - println("Device Feature Get: Active EMI type"); - respData[1] = (uint8_t) CEMI; // USB KNX Transfer Protocol Body: Feature Data -> cEMI type ID - sendKnxHidReport(BusAccessServer, DeviceFeatureResponse, respData, 2); - break; - default: - break; - } - break; - } - case DeviceFeatureSet: // Device Feature Set - { - FeatureIdType featureId = (FeatureIdType)requestData[0]; - switch (featureId) - { - case ActiveEmiType: // Active EMI type - print("Device Feature Set: Active EMI type: "); - if (requestData[1] < 16) - print("0"); - println(requestData[1], HEX); // USB KNX Transfer Protocol Body: Feature Data -> EMI TYPE ID - break; - // All other featureIds must not be set - case SupportedEmiType: // Supported EMI types - case HostDeviceDescriptorType0: // Host Device Descriptor Type 0 - case BusConnectionStatus: // Bus connection status - case KnxManufacturerCode: // KNX manufacturer code - default: - break; - } - break; - } - - // These are only sent from the device to the host - case DeviceFeatureResponse: // Device Feature Response - case DeviceFeatureInfo: // Device Feature Info - case DeviceFeatureEscape: // reserved (ESCAPE for future extensions) - default: - break; - } + uint8_t respData[3]; // max. 3 bytes are required for a response + + switch (servId) + { + case DeviceFeatureGet: // Device Feature Get + { + FeatureIdType featureId = (FeatureIdType)requestData[0]; + respData[0] = (uint8_t) featureId; // first byte in repsonse is the featureId itself again + + switch (featureId) + { + case SupportedEmiType: // Supported EMI types + println("Device Feature Get: Supported EMI types"); + respData[1] = 0x00; // USB KNX Transfer Protocol Body: Feature Data + respData[2] = 0x04; // USB KNX Transfer Protocol Body: Feature Data -> only cEMI supported + sendKnxHidReport(BusAccessServer, DeviceFeatureResponse, respData, 3); + break; + + case HostDeviceDescriptorType0: // Host Device Descriptor Type 0 + println("Device Feature Get: Host Device Descriptor Type 0"); + pushWord(_maskVersion, &respData[1]); // USB KNX Transfer Protocol Body: Feature Data -> Mask version + sendKnxHidReport(BusAccessServer, DeviceFeatureResponse, respData, 3); + break; + + case BusConnectionStatus: // Bus connection status + println("Device Feature Get: Bus connection status"); + respData[1] = 1; // USB KNX Transfer Protocol Body: Feature Data -> bus connection status + sendKnxHidReport(BusAccessServer, DeviceFeatureResponse, respData, 2); + break; + + case KnxManufacturerCode: // KNX manufacturer code + println("Device Feature Get: KNX manufacturer code"); + pushWord(_manufacturerId, &respData[1]); // USB KNX Transfer Protocol Body: Feature Data -> Manufacturer Code + sendKnxHidReport(BusAccessServer, DeviceFeatureResponse, respData, 3); + break; + + case ActiveEmiType: // Active EMI type + println("Device Feature Get: Active EMI type"); + respData[1] = (uint8_t) CEMI; // USB KNX Transfer Protocol Body: Feature Data -> cEMI type ID + sendKnxHidReport(BusAccessServer, DeviceFeatureResponse, respData, 2); + break; + + default: + break; + } + + break; + } + + case DeviceFeatureSet: // Device Feature Set + { + FeatureIdType featureId = (FeatureIdType)requestData[0]; + + switch (featureId) + { + case ActiveEmiType: // Active EMI type + print("Device Feature Set: Active EMI type: "); + + if (requestData[1] < 16) + print("0"); + + println(requestData[1], HEX); // USB KNX Transfer Protocol Body: Feature Data -> EMI TYPE ID + break; + + // All other featureIds must not be set + case SupportedEmiType: // Supported EMI types + case HostDeviceDescriptorType0: // Host Device Descriptor Type 0 + case BusConnectionStatus: // Bus connection status + case KnxManufacturerCode: // KNX manufacturer code + default: + break; + } + + break; + } + + // These are only sent from the device to the host + case DeviceFeatureResponse: // Device Feature Response + case DeviceFeatureInfo: // Device Feature Info + case DeviceFeatureEscape: // reserved (ESCAPE for future extensions) + default: + break; + } } /* USB HID report descriptor for KNX HID */ const uint8_t UsbTunnelInterface::descHidReport[] = { - //TUD_HID_REPORT_DESC_KNXHID_INOUT(64) -0x06, 0xA0, 0xFF, // Usage Page (Vendor Defined 0xFFA0) -0x09, 0x01, // Usage (0x01) -0xA1, 0x01, // Collection (Application) -0x09, 0x01, // Usage (0x01) -0xA1, 0x00, // Collection (Physical) -0x06, 0xA1, 0xFF, // Usage Page (Vendor Defined 0xFFA1) -0x09, 0x03, // Usage (0x03) -0x09, 0x04, // Usage (0x04) -0x15, 0x80, // Logical Minimum (-128) -0x25, 0x7F, // Logical Maximum (127) -0x35, 0x00, // Physical Minimum (0) -0x45, 0xFF, // Physical Maximum (-1) -0x75, 0x08, // Report Size (8) -0x85, 0x01, // Report ID (1) -0x95, 0x3F, // Report Count (63) -0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) -0x09, 0x05, // Usage (0x05) -0x09, 0x06, // Usage (0x06) -0x15, 0x80, // Logical Minimum (-128) -0x25, 0x7F, // Logical Maximum (127) -0x35, 0x00, // Physical Minimum (0) -0x45, 0xFF, // Physical Maximum (-1) -0x75, 0x08, // Report Size (8) -0x85, 0x01, // Report ID (1) -0x95, 0x3F, // Report Count (63) -0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) -0xC0, // End Collection -0xC0 // End Collection + //TUD_HID_REPORT_DESC_KNXHID_INOUT(64) + 0x06, 0xA0, 0xFF, // Usage Page (Vendor Defined 0xFFA0) + 0x09, 0x01, // Usage (0x01) + 0xA1, 0x01, // Collection (Application) + 0x09, 0x01, // Usage (0x01) + 0xA1, 0x00, // Collection (Physical) + 0x06, 0xA1, 0xFF, // Usage Page (Vendor Defined 0xFFA1) + 0x09, 0x03, // Usage (0x03) + 0x09, 0x04, // Usage (0x04) + 0x15, 0x80, // Logical Minimum (-128) + 0x25, 0x7F, // Logical Maximum (127) + 0x35, 0x00, // Physical Minimum (0) + 0x45, 0xFF, // Physical Maximum (-1) + 0x75, 0x08, // Report Size (8) + 0x85, 0x01, // Report ID (1) + 0x95, 0x3F, // Report Count (63) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x05, // Usage (0x05) + 0x09, 0x06, // Usage (0x06) + 0x15, 0x80, // Logical Minimum (-128) + 0x25, 0x7F, // Logical Maximum (127) + 0x35, 0x00, // Physical Minimum (0) + 0x45, 0xFF, // Physical Maximum (-1) + 0x75, 0x08, // Report Size (8) + 0x85, 0x01, // Report ID (1) + 0x95, 0x3F, // Report Count (63) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xC0 // End Collection }; const uint8_t* UsbTunnelInterface::getKnxHidReportDescriptor() { - return &descHidReport[0]; + return &descHidReport[0]; } uint16_t UsbTunnelInterface::getHidReportDescriptorLength() { - return sizeof(descHidReport); + return sizeof(descHidReport); } #endif diff --git a/src/knx/usb_tunnel_interface.h b/src/knx/usb_tunnel_interface.h index b47209f8..0395b02c 100644 --- a/src/knx/usb_tunnel_interface.h +++ b/src/knx/usb_tunnel_interface.h @@ -9,88 +9,88 @@ class CemiFrame; enum ProtocolIdType { - KnxTunneling = 0x01, - BusAccessServer = 0x0f + KnxTunneling = 0x01, + BusAccessServer = 0x0f }; enum EmiIdType { - EmiIdNotUsed = 0x00, - EMI1 = 0x01, - EMI2 = 0x02, - CEMI = 0x03 + EmiIdNotUsed = 0x00, + EMI1 = 0x01, + EMI2 = 0x02, + CEMI = 0x03 }; enum ServiceIdType { - ServiceIdNotUsed = 0x00, - DeviceFeatureGet = 0x01, - DeviceFeatureResponse = 0x02, - DeviceFeatureSet = 0x03, - DeviceFeatureInfo = 0x04, - DeviceFeatureEscape = 0xFF + ServiceIdNotUsed = 0x00, + DeviceFeatureGet = 0x01, + DeviceFeatureResponse = 0x02, + DeviceFeatureSet = 0x03, + DeviceFeatureInfo = 0x04, + DeviceFeatureEscape = 0xFF }; enum FeatureIdType { - SupportedEmiType = 0x01, - HostDeviceDescriptorType0 = 0x02, - BusConnectionStatus = 0x03, - KnxManufacturerCode = 0x04, - ActiveEmiType = 0x05 + 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); + 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); }; #endif \ No newline at end of file diff --git a/src/knx_facade.cpp b/src/knx_facade.cpp index 03e4ce63..dfb51734 100644 --- a/src/knx_facade.cpp +++ b/src/knx_facade.cpp @@ -4,102 +4,105 @@ #ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE - #if (defined(ARDUINO_ARCH_STM32) || \ +#if (defined(ARDUINO_ARCH_STM32) || \ defined(ARDUINO_ARCH_ESP32) || \ defined(ARDUINO_ARCH_ESP8266) || \ defined(ARDUINO_ARCH_SAMD) || \ - defined(ARDUINO_ARCH_RP2040)) + defined(ARDUINO_ARCH_RP2040)) - // Only ESP8266 and ESP32 have this define. For all other platforms this is just empty. - #ifndef ICACHE_RAM_ATTR - #define ICACHE_RAM_ATTR - #endif +// Only ESP8266 and ESP32 have this define. For all other platforms this is just empty. +#ifndef ICACHE_RAM_ATTR + #define ICACHE_RAM_ATTR +#endif - #ifndef PROG_BTN_PRESS_MIN_MILLIS - #define PROG_BTN_PRESS_MIN_MILLIS 50 - #endif +#ifndef PROG_BTN_PRESS_MIN_MILLIS + #define PROG_BTN_PRESS_MIN_MILLIS 50 +#endif - #ifndef PROG_BTN_PRESS_MAX_MILLIS - #define PROG_BTN_PRESS_MAX_MILLIS 500 - #endif +#ifndef PROG_BTN_PRESS_MAX_MILLIS + #define PROG_BTN_PRESS_MAX_MILLIS 500 +#endif - ICACHE_RAM_ATTR void buttonEvent() +ICACHE_RAM_ATTR void buttonEvent() +{ + static uint32_t lastEvent = 0; + static uint32_t lastPressed = 0; + + uint32_t diff = millis() - lastEvent; + + if (diff >= PROG_BTN_PRESS_MIN_MILLIS && diff <= PROG_BTN_PRESS_MAX_MILLIS) + { + if (millis() - lastPressed > 200) { - static uint32_t lastEvent=0; - static uint32_t lastPressed=0; - - uint32_t diff = millis() - lastEvent; - if (diff >= PROG_BTN_PRESS_MIN_MILLIS && diff <= PROG_BTN_PRESS_MAX_MILLIS){ - if (millis() - lastPressed > 200) - { - knx.toggleProgMode(); - lastPressed = millis(); - } - } - lastEvent = millis(); + knx.toggleProgMode(); + lastPressed = millis(); } + } + + lastEvent = millis(); +} +#endif + +#ifdef ARDUINO_ARCH_SAMD + // predefined global instance for TP or RF or TP/RF coupler + #if MASK_VERSION == 0x07B0 + KnxFacade knx(buttonEvent); + #elif MASK_VERSION == 0x27B0 + KnxFacade knx(buttonEvent); + #elif MASK_VERSION == 0x2920 + KnxFacade knx(buttonEvent); + #else + #error "Mask version not supported on ARDUINO_ARCH_SAMD" + #endif +#elif defined(ARDUINO_ARCH_RP2040) + // predefined global instance for TP or RF or IP or TP/RF coupler or TP/IP coupler + #if MASK_VERSION == 0x07B0 + KnxFacade knx(buttonEvent); + #elif MASK_VERSION == 0x27B0 + KnxFacade knx(buttonEvent); + #elif MASK_VERSION == 0x57B0 + KnxFacade knx(buttonEvent); + #elif MASK_VERSION == 0x2920 + KnxFacade knx(buttonEvent); + #elif MASK_VERSION == 0x091A + KnxFacade knx(buttonEvent); + #else + #error "Mask version not supported on ARDUINO_ARCH_RP2040" + #endif + +#elif defined(ARDUINO_ARCH_ESP8266) + // predefined global instance for TP or IP or TP/IP coupler + #if MASK_VERSION == 0x07B0 + KnxFacade knx(buttonEvent); + #elif MASK_VERSION == 0x57B0 + KnxFacade knx(buttonEvent); + #elif MASK_VERSION == 0x091A + KnxFacade knx(buttonEvent); + #else + #error "Mask version not supported on ARDUINO_ARCH_ESP8266" + #endif + +#elif defined(ARDUINO_ARCH_ESP32) + // predefined global instance for TP or IP or TP/IP coupler + #if MASK_VERSION == 0x07B0 + KnxFacade knx(buttonEvent); + #elif MASK_VERSION == 0x57B0 + KnxFacade knx(buttonEvent); + #elif MASK_VERSION == 0x091A + KnxFacade knx(buttonEvent); + #else + #error "Mask version not supported on ARDUINO_ARCH_ESP32" #endif - #ifdef ARDUINO_ARCH_SAMD - // predefined global instance for TP or RF or TP/RF coupler - #if MASK_VERSION == 0x07B0 - KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x27B0 - KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x2920 - KnxFacade knx(buttonEvent); - #else - #error "Mask version not supported on ARDUINO_ARCH_SAMD" - #endif - #elif defined(ARDUINO_ARCH_RP2040) - // predefined global instance for TP or RF or IP or TP/RF coupler or TP/IP coupler - #if MASK_VERSION == 0x07B0 - KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x27B0 - KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x57B0 - KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x2920 - KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x091A - KnxFacade knx(buttonEvent); - #else - #error "Mask version not supported on ARDUINO_ARCH_RP2040" - #endif - - #elif defined(ARDUINO_ARCH_ESP8266) - // predefined global instance for TP or IP or TP/IP coupler - #if MASK_VERSION == 0x07B0 - KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x57B0 - KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x091A - KnxFacade knx(buttonEvent); - #else - #error "Mask version not supported on ARDUINO_ARCH_ESP8266" - #endif - - #elif defined(ARDUINO_ARCH_ESP32) - // predefined global instance for TP or IP or TP/IP coupler - #if MASK_VERSION == 0x07B0 - KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x57B0 - KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x091A - KnxFacade knx(buttonEvent); - #else - #error "Mask version not supported on ARDUINO_ARCH_ESP32" - #endif - - #elif defined(ARDUINO_ARCH_STM32) - #if MASK_VERSION == 0x07B0 - KnxFacade knx(buttonEvent); - #else - #error "Mask version not supported on ARDUINO_ARCH_STM32" - #endif - #else // Non-Arduino platforms and Linux platform - // no predefined global instance +#elif defined(ARDUINO_ARCH_STM32) + #if MASK_VERSION == 0x07B0 + KnxFacade knx(buttonEvent); + #else + #error "Mask version not supported on ARDUINO_ARCH_STM32" #endif +#else // Non-Arduino platforms and Linux platform + // no predefined global instance +#endif #endif // KNX_NO_AUTOMATIC_GLOBAL_INSTANCE diff --git a/src/knx_facade.h b/src/knx_facade.h index 0e556672..ca2f7bec 100644 --- a/src/knx_facade.h +++ b/src/knx_facade.h @@ -9,7 +9,7 @@ #include "knx/bau57B0.h" #ifndef USERDATA_SAVE_SIZE -#define USERDATA_SAVE_SIZE 0 + #define USERDATA_SAVE_SIZE 0 #endif #ifdef ARDUINO_ARCH_SAMD @@ -28,9 +28,9 @@ void buttonUp(); #endif #elif defined(ARDUINO_ARCH_ESP32) -#if !defined(LED_BUILTIN) - #define LED_BUILTIN 13 -#endif + #if !defined(LED_BUILTIN) + #define LED_BUILTIN 13 + #endif #include "esp32_platform.h" #ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE void buttonUp(); @@ -41,14 +41,14 @@ void buttonUp(); #endif #elif __linux__ -#if !defined(LED_BUILTIN) - #define LED_BUILTIN 0 -#endif + #if !defined(LED_BUILTIN) + #define LED_BUILTIN 0 + #endif #include "linux_platform.h" #else -#if !defined(LED_BUILTIN) - #define LED_BUILTIN 5 // see GPIO_PinConfig gpioPinConfigs[] -#endif + #if !defined(LED_BUILTIN) + #define LED_BUILTIN 5 // see GPIO_PinConfig gpioPinConfigs[] + #endif #include "cc1310_platform.h" #ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE extern void buttonUp(); @@ -71,405 +71,408 @@ typedef void (*IsrFunctionPtr)(); typedef void (*ProgLedOnCallback)(); typedef void (*ProgLedOffCallback)(); #ifdef KNX_ACTIVITYCALLBACK -typedef void (*ActivityCallback)(uint8_t info); + typedef void (*ActivityCallback)(uint8_t info); #endif template class KnxFacade : private SaveRestore { - public: - KnxFacade() : _platformPtr(new P()), _bauPtr(new B(*_platformPtr)), _bau(*_bauPtr) - { - manufacturerId(0xfa); - bauNumber(platform().uniqueSerialNumber()); - _bau.addSaveRestore(this); - } - - KnxFacade(B& bau) : _bau(bau) - { - _platformPtr = static_cast(&bau.platform()); - manufacturerId(0xfa); - bauNumber(platform().uniqueSerialNumber()); - _bau.addSaveRestore(this); - } - - KnxFacade(IsrFunctionPtr buttonISRFunction) : _platformPtr(new P()), _bauPtr(new B(*_platformPtr)), _bau(*_bauPtr) - { - manufacturerId(0xfa); - bauNumber(platform().uniqueSerialNumber()); - _bau.addSaveRestore(this); - setButtonISRFunction(buttonISRFunction); - } - - virtual ~KnxFacade() - { - if (_bauPtr) - delete _bauPtr; - - if (_platformPtr) - delete _platformPtr; - } - - P& platform() - { - return *_platformPtr; - } - - B& bau() - { - return _bau; - } - - bool enabled() - { - return _bau.enabled(); - } - - void enabled(bool value) - { - _bau.enabled(value); - } - - bool progMode() - { - return _bau.deviceObject().progMode(); - } - - void progMode(bool value) - { - _bau.deviceObject().progMode(value); - } - - /** - * To be called by ISR handling on button press. - */ - void toggleProgMode() - { - _toggleProgMode = true; - } - - bool configured() - { - return _bau.configured(); - } - - /** - * returns HIGH if led is active on HIGH, LOW otherwise - */ - uint32_t ledPinActiveOn() - { - return _ledPinActiveOn; - } - - /** - * Sets if the programming led is active on HIGH or LOW. - * - * Set to HIGH for GPIO--RESISTOR--LED--GND or to LOW for GPIO--LED--RESISTOR--VDD - */ - void ledPinActiveOn(uint32_t value) - { - _ledPinActiveOn = value; - } - - uint32_t ledPin() - { - return _ledPin; - } - - void ledPin(uint32_t value) - { - _ledPin = value; - } - - void setProgLedOffCallback(ProgLedOffCallback progLedOffCallback) - { - _progLedOffCallback = progLedOffCallback; - } - - void setProgLedOnCallback(ProgLedOnCallback progLedOnCallback) - { - _progLedOnCallback = progLedOnCallback; - } - - int32_t buttonPin() - { - return _buttonPin; - } - - void buttonPin(int32_t value) - { - _buttonPin = value; - } - - void readMemory() - { - _bau.readMemory(); - } - - void writeMemory() - { - _bau.writeMemory(); - } - - uint16_t individualAddress() - { - return _bau.deviceObject().individualAddress(); - } - - void loop() - { - if (progMode() != _progLedState) - { - _progLedState = progMode(); - if (_progLedState) + public: + KnxFacade() : _platformPtr(new P()), _bauPtr(new B(*_platformPtr)), _bau(*_bauPtr) + { + manufacturerId(0xfa); + bauNumber(platform().uniqueSerialNumber()); + _bau.addSaveRestore(this); + } + + KnxFacade(B& bau) : _bau(bau) + { + _platformPtr = static_cast(&bau.platform()); + manufacturerId(0xfa); + bauNumber(platform().uniqueSerialNumber()); + _bau.addSaveRestore(this); + } + + KnxFacade(IsrFunctionPtr buttonISRFunction) : _platformPtr(new P()), _bauPtr(new B(*_platformPtr)), _bau(*_bauPtr) + { + manufacturerId(0xfa); + bauNumber(platform().uniqueSerialNumber()); + _bau.addSaveRestore(this); + setButtonISRFunction(buttonISRFunction); + } + + virtual ~KnxFacade() + { + if (_bauPtr) + delete _bauPtr; + + if (_platformPtr) + delete _platformPtr; + } + + P& platform() + { + return *_platformPtr; + } + + B& bau() + { + return _bau; + } + + bool enabled() + { + return _bau.enabled(); + } + + void enabled(bool value) + { + _bau.enabled(value); + } + + bool progMode() + { + return _bau.deviceObject().progMode(); + } + + void progMode(bool value) + { + _bau.deviceObject().progMode(value); + } + + /** + * To be called by ISR handling on button press. + */ + void toggleProgMode() + { + _toggleProgMode = true; + } + + bool configured() + { + return _bau.configured(); + } + + /** + * returns HIGH if led is active on HIGH, LOW otherwise + */ + uint32_t ledPinActiveOn() + { + return _ledPinActiveOn; + } + + /** + * Sets if the programming led is active on HIGH or LOW. + * + * Set to HIGH for GPIO--RESISTOR--LED--GND or to LOW for GPIO--LED--RESISTOR--VDD + */ + void ledPinActiveOn(uint32_t value) + { + _ledPinActiveOn = value; + } + + uint32_t ledPin() + { + return _ledPin; + } + + void ledPin(uint32_t value) + { + _ledPin = value; + } + + void setProgLedOffCallback(ProgLedOffCallback progLedOffCallback) + { + _progLedOffCallback = progLedOffCallback; + } + + void setProgLedOnCallback(ProgLedOnCallback progLedOnCallback) + { + _progLedOnCallback = progLedOnCallback; + } + + int32_t buttonPin() + { + return _buttonPin; + } + + void buttonPin(int32_t value) + { + _buttonPin = value; + } + + void readMemory() + { + _bau.readMemory(); + } + + void writeMemory() + { + _bau.writeMemory(); + } + + uint16_t individualAddress() + { + return _bau.deviceObject().individualAddress(); + } + + void loop() + { + if (progMode() != _progLedState) { - println("progmode on"); - progLedOn(); + _progLedState = progMode(); + + if (_progLedState) + { + println("progmode on"); + progLedOn(); + } + else + { + println("progmode off"); + progLedOff(); + } } - else + + if (_toggleProgMode) { - println("progmode off"); - progLedOff(); + progMode(!progMode()); + _toggleProgMode = false; } + + _bau.loop(); + } + + void manufacturerId(uint16_t value) + { + _bau.deviceObject().manufacturerId(value); } - if (_toggleProgMode) - { - progMode(!progMode()); - _toggleProgMode = false; - } - _bau.loop(); - } - - void manufacturerId(uint16_t value) - { - _bau.deviceObject().manufacturerId(value); - } - - void bauNumber(uint32_t value) - { - _bau.deviceObject().bauNumber(value); - } - - void orderNumber(const uint8_t* value) - { - _bau.deviceObject().orderNumber(value); - } - - void hardwareType(const uint8_t* value) - { - _bau.deviceObject().hardwareType(value); - } - - void version(uint16_t value) - { - _bau.deviceObject().version(value); - } - - void start() - { - if (_progLedOffCallback == 0 || _progLedOnCallback == 0) - pinMode(ledPin(), OUTPUT); - - progLedOff(); - - if (_progButtonISRFuncPtr && _buttonPin >= 0) - { - pinMode(buttonPin(), INPUT_PULLUP); - // Workaround for https://github.com/arduino/ArduinoCore-samd/issues/587 - #if (ARDUINO_API_VERSION >= 10200) + + void bauNumber(uint32_t value) + { + _bau.deviceObject().bauNumber(value); + } + + void orderNumber(const uint8_t* value) + { + _bau.deviceObject().orderNumber(value); + } + + void hardwareType(const uint8_t* value) + { + _bau.deviceObject().hardwareType(value); + } + + void version(uint16_t value) + { + _bau.deviceObject().version(value); + } + + void start() + { + if (_progLedOffCallback == 0 || _progLedOnCallback == 0) + pinMode(ledPin(), OUTPUT); + + progLedOff(); + + if (_progButtonISRFuncPtr && _buttonPin >= 0) + { + pinMode(buttonPin(), INPUT_PULLUP); + // Workaround for https://github.com/arduino/ArduinoCore-samd/issues/587 +#if (ARDUINO_API_VERSION >= 10200) attachInterrupt(_buttonPin, _progButtonISRFuncPtr, (PinStatus)CHANGE); - #else +#else attachInterrupt(_buttonPin, _progButtonISRFuncPtr, CHANGE); - #endif - } - - enabled(true); - } - - void setButtonISRFunction(IsrFunctionPtr progButtonISRFuncPtr) - { - _progButtonISRFuncPtr = progButtonISRFuncPtr; - } - - void setSaveCallback(SaveCallback func) - { - _saveCallback = func; - } - - void setRestoreCallback(RestoreCallback func) - { - _restoreCallback = func; - } - - uint8_t* paramData(uint32_t addr) - { - if (!_bau.configured()) - return nullptr; - - return _bau.parameters().data(addr); - } - - // paramBit(address, shift) - // get state of a parameter as a boolean like "enable/disable", ... - // Declaration in XML file: - // ... - // - // - // - // - // - // - // ... - // - // - // - // - // - // - // - // - // - // ... - // Usage in code : - // if ( knx.paramBit(1,1)) - // { - // //do somthings .... - // } - bool paramBit(uint32_t addr, uint8_t shift) - { - if (!_bau.configured()) - return 0; - - return (bool) ((_bau.parameters().getByte(addr) >> (7-shift)) & 0x01); - } - - uint8_t paramByte(uint32_t addr) - { - if (!_bau.configured()) - return 0; - - return _bau.parameters().getByte(addr); - } - - // Same usage than paramByte(addresse) for signed parameters - // Declaration in XML file - // - // - // - int8_t paramSignedByte(uint32_t addr) - { - if (!_bau.configured()) - return 0; - - return (int8_t) _bau.parameters().getByte(addr); - } - - uint16_t paramWord(uint32_t addr) - { - if (!_bau.configured()) - return 0; - - return _bau.parameters().getWord(addr); - } - - uint32_t paramInt(uint32_t addr) - { - if (!_bau.configured()) - return 0; - - return _bau.parameters().getInt(addr); - } - - double paramFloat(uint32_t addr, ParameterFloatEncodings enc) - { - if (!_bau.configured()) - return 0; - - return _bau.parameters().getFloat(addr, enc); - } - +#endif + } + + enabled(true); + } + + void setButtonISRFunction(IsrFunctionPtr progButtonISRFuncPtr) + { + _progButtonISRFuncPtr = progButtonISRFuncPtr; + } + + void setSaveCallback(SaveCallback func) + { + _saveCallback = func; + } + + void setRestoreCallback(RestoreCallback func) + { + _restoreCallback = func; + } + + uint8_t* paramData(uint32_t addr) + { + if (!_bau.configured()) + return nullptr; + + return _bau.parameters().data(addr); + } + + // paramBit(address, shift) + // get state of a parameter as a boolean like "enable/disable", ... + // Declaration in XML file: + // ... + // + // + // + // + // + // + // ... + // + // + // + // + // + // + // + // + // + // ... + // Usage in code : + // if ( knx.paramBit(1,1)) + // { + // //do somthings .... + // } + bool paramBit(uint32_t addr, uint8_t shift) + { + if (!_bau.configured()) + return 0; + + return (bool) ((_bau.parameters().getByte(addr) >> (7 - shift)) & 0x01); + } + + uint8_t paramByte(uint32_t addr) + { + if (!_bau.configured()) + return 0; + + return _bau.parameters().getByte(addr); + } + + // Same usage than paramByte(addresse) for signed parameters + // Declaration in XML file + // + // + // + int8_t paramSignedByte(uint32_t addr) + { + if (!_bau.configured()) + return 0; + + return (int8_t) _bau.parameters().getByte(addr); + } + + uint16_t paramWord(uint32_t addr) + { + if (!_bau.configured()) + return 0; + + return _bau.parameters().getWord(addr); + } + + uint32_t paramInt(uint32_t addr) + { + if (!_bau.configured()) + return 0; + + return _bau.parameters().getInt(addr); + } + + double paramFloat(uint32_t addr, ParameterFloatEncodings enc) + { + if (!_bau.configured()) + return 0; + + return _bau.parameters().getFloat(addr, enc); + } + #if (MASK_VERSION == 0x07B0) || (MASK_VERSION == 0x27B0) || (MASK_VERSION == 0x57B0) - GroupObject& getGroupObject(uint16_t goNr) - { - return _bau.groupObjectTable().get(goNr); - } + GroupObject& getGroupObject(uint16_t goNr) + { + return _bau.groupObjectTable().get(goNr); + } #endif - void restart(uint16_t individualAddress) - { - SecurityControl sc = {false, None}; - _bau.restartRequest(individualAddress, sc); - } - - void beforeRestartCallback(BeforeRestartCallback func) - { - _bau.beforeRestartCallback(func); - } - - BeforeRestartCallback beforeRestartCallback() - { - return _bau.beforeRestartCallback(); - } - - private: - P* _platformPtr = 0; - B* _bauPtr = 0; - B& _bau; - ProgLedOnCallback _progLedOnCallback = 0; - ProgLedOffCallback _progLedOffCallback = 0; + void restart(uint16_t individualAddress) + { + SecurityControl sc = {false, None}; + _bau.restartRequest(individualAddress, sc); + } + + void beforeRestartCallback(BeforeRestartCallback func) + { + _bau.beforeRestartCallback(func); + } + + BeforeRestartCallback beforeRestartCallback() + { + return _bau.beforeRestartCallback(); + } + + private: + P* _platformPtr = 0; + B* _bauPtr = 0; + B& _bau; + ProgLedOnCallback _progLedOnCallback = 0; + ProgLedOffCallback _progLedOffCallback = 0; #ifdef KNX_ACTIVITYCALLBACK - ActivityCallback _activityCallback = 0; + ActivityCallback _activityCallback = 0; #endif - uint32_t _ledPinActiveOn = KNX_LED_ACTIVE_ON; - uint32_t _ledPin = KNX_LED; - int32_t _buttonPin = KNX_BUTTON; - SaveCallback _saveCallback = 0; - RestoreCallback _restoreCallback = 0; - volatile bool _toggleProgMode = false; - bool _progLedState = false; - uint16_t _saveSize = USERDATA_SAVE_SIZE; - IsrFunctionPtr _progButtonISRFuncPtr = 0; - - uint8_t* save(uint8_t* buffer) - { - if (_saveCallback != 0) - return _saveCallback(buffer); - - return buffer; - } - - const uint8_t* restore(const uint8_t* buffer) - { - if (_restoreCallback != 0) - return _restoreCallback(buffer); - - return buffer; - } - - uint16_t saveSize() - { - return _saveSize; - } - - void saveSize(uint16_t size) - { - _saveSize = size; - } - - void progLedOn() - { - if (_progLedOnCallback == 0) - digitalWrite(ledPin(), _ledPinActiveOn); - else - _progLedOnCallback(); - } - - void progLedOff() - { - if (_progLedOffCallback == 0) - digitalWrite(ledPin(), HIGH - _ledPinActiveOn); - else - _progLedOffCallback(); - } + uint32_t _ledPinActiveOn = KNX_LED_ACTIVE_ON; + uint32_t _ledPin = KNX_LED; + int32_t _buttonPin = KNX_BUTTON; + SaveCallback _saveCallback = 0; + RestoreCallback _restoreCallback = 0; + volatile bool _toggleProgMode = false; + bool _progLedState = false; + uint16_t _saveSize = USERDATA_SAVE_SIZE; + IsrFunctionPtr _progButtonISRFuncPtr = 0; + + uint8_t* save(uint8_t* buffer) + { + if (_saveCallback != 0) + return _saveCallback(buffer); + + return buffer; + } + + const uint8_t* restore(const uint8_t* buffer) + { + if (_restoreCallback != 0) + return _restoreCallback(buffer); + + return buffer; + } + + uint16_t saveSize() + { + return _saveSize; + } + + void saveSize(uint16_t size) + { + _saveSize = size; + } + + void progLedOn() + { + if (_progLedOnCallback == 0) + digitalWrite(ledPin(), _ledPinActiveOn); + else + _progLedOnCallback(); + } + + void progLedOff() + { + if (_progLedOffCallback == 0) + digitalWrite(ledPin(), HIGH - _ledPinActiveOn); + else + _progLedOffCallback(); + } }; #ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE diff --git a/src/linux_platform.cpp b/src/linux_platform.cpp index 8ebac4a6..633cf8a6 100644 --- a/src/linux_platform.cpp +++ b/src/linux_platform.cpp @@ -42,6 +42,7 @@ LinuxPlatform::LinuxPlatform() { int socketMac = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (socketMac < 0) { printf("Lookup socket creation failed"); @@ -49,11 +50,15 @@ LinuxPlatform::LinuxPlatform() } struct ifreq ifr; + struct ifconf ifc; + char buf[1024]; ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; + if (ioctl(socketMac, SIOCGIFCONF, &ifc) < 0) return; @@ -63,6 +68,7 @@ LinuxPlatform::LinuxPlatform() for (; it != end; ++it) { strcpy(ifr.ifr_name, it->ifr_name); + if (ioctl(socketMac, SIOCGIFFLAGS, &ifr)) continue; @@ -89,6 +95,7 @@ LinuxPlatform::LinuxPlatform() //printf("Netmask: %s\n", inet_ntoa(ipaddr->sin_addr)); break; } + close(socketMac); // default GW @@ -113,10 +120,12 @@ LinuxPlatform::LinuxPlatform() char* pEnd; _defaultGateway = ntohl(strtol(g, &pEnd, 16)); } + break; } } } + fclose(f); } @@ -149,6 +158,7 @@ void LinuxPlatform::restart() void LinuxPlatform::fatalError() { printf("A fatal error occured. Stopping.\n"); + while (true) sleep(1); } @@ -171,6 +181,7 @@ void LinuxPlatform::setupMultiCast(uint32_t addr, uint16_t port) sin.sin_port = htons(port); _multicastSocketFd = socket(AF_INET, SOCK_DGRAM, 0); + if (_multicastSocketFd == -1) { perror("socket()"); @@ -179,6 +190,7 @@ void LinuxPlatform::setupMultiCast(uint32_t addr, uint16_t port) /* Mehr Prozessen erlauben, denselben Port zu nutzen */ loop = 1; + if (setsockopt(_multicastSocketFd, SOL_SOCKET, SO_REUSEADDR, &loop, sizeof(loop)) < 0) { perror("setsockopt:SO_REUSEADDR"); @@ -193,6 +205,7 @@ void LinuxPlatform::setupMultiCast(uint32_t addr, uint16_t port) /* loopback */ loop = 0; + if (setsockopt(_multicastSocketFd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) { perror("setsockopt:IP_MULTICAST_LOOP"); @@ -227,6 +240,7 @@ void LinuxPlatform::closeMultiCast() { perror("setsockopt:IP_DROP_MEMBERSHIP"); } + close(_multicastSocketFd); _multicastSocketFd = -1; } @@ -239,15 +253,18 @@ bool LinuxPlatform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) 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; } @@ -285,6 +302,7 @@ void LinuxPlatform::commitToEeprom() void LinuxPlatform::doMemoryMapping() { _fd = open(_flashFilePath.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRGRP | S_IROTH); + if (_fd < 0) { puts("Error in file opening"); @@ -292,7 +310,9 @@ void LinuxPlatform::doMemoryMapping() } struct stat st; + uint32_t ret = fstat(_fd, &st); + if (ret < 0) { puts("Error in fstat"); @@ -300,6 +320,7 @@ void LinuxPlatform::doMemoryMapping() } size_t len_file = st.st_size; + if (len_file < FLASHSIZE) { if (ftruncate(_fd, FLASHSIZE) != 0) @@ -307,9 +328,12 @@ void LinuxPlatform::doMemoryMapping() puts("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); @@ -322,6 +346,7 @@ void LinuxPlatform::doMemoryMapping() puts("Error in mmap"); //exit(-1); } + _mappedFile = addr; } @@ -340,7 +365,7 @@ int LinuxPlatform::readWriteSpi(uint8_t* data, size_t len) struct spi_ioc_transfer spi; // Mentioned in spidev.h but not used in the original kernel documentation - // test program )-: + // test program )-: memset(&spi, 0, sizeof(spi)); @@ -403,7 +428,7 @@ std::string LinuxPlatform::flashFilePath() -size_t LinuxPlatform::readBytesUart(uint8_t *buffer, size_t length) +size_t LinuxPlatform::readBytesUart(uint8_t* buffer, size_t length) { return read(_uartFd, buffer, length); } @@ -420,7 +445,7 @@ int LinuxPlatform::readUart() return ((int)x) & 0xFF ; } -size_t LinuxPlatform::writeUart(const uint8_t *buffer, size_t size) +size_t LinuxPlatform::writeUart(const uint8_t* buffer, size_t size) { return write(_uartFd, buffer, size) ; } @@ -434,12 +459,12 @@ int LinuxPlatform::uartAvailable() { int result ; - if (ioctl(_uartFd, FIONREAD, &result) == -1) - { + if (ioctl(_uartFd, FIONREAD, &result) == -1) + { return -1; - } + } - return result ; + return result ; } void LinuxPlatform::closeUart() @@ -459,16 +484,19 @@ void LinuxPlatform::setupUart() /* Port oeffnen - read/write, kein "controlling tty", Status von DCD ignorieren */ _uartFd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY); + if (_uartFd >= 0) { /* get the current options */ fcntl(_uartFd, F_SETFL, 0); + if (tcgetattr(_uartFd, &options) != 0) { close(_uartFd); _uartFd = -1; return; } + memset(&options, 0, sizeof(options)); /* Structur loeschen, ggf. vorher sichern und bei Programmende wieder restaurieren */ /* Baudrate setzen */ @@ -491,7 +519,7 @@ void LinuxPlatform::setupUart() 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 */ + tcflush(_uartFd, TCIOFLUSH); /* Puffer leeren */ if (tcsetattr(_uartFd, TCSAFLUSH, &options) != 0) { @@ -504,20 +532,22 @@ void LinuxPlatform::setupUart() #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'; uint64_t n = value; - do { - char c = n % base; - n /= base; - *--str = c < 10 ? c + '0' : c + 'A' - 10; + do + { + char c = n % base; + n /= base; + + *--str = c < 10 ? c + '0' : c + 'A' - 10; } while (n > 0); - print(str); + print(str); } void print(const char* s) @@ -737,7 +767,7 @@ void LinuxPlatform::cmdLineArgs(int argc, char** argv) if (_args) delete[] _args; - _args = new char*[argc + 1]; + _args = new char* [argc + 1]; memcpy(_args, argv, argc * sizeof(char*)); _args[argc] = 0; } @@ -747,8 +777,8 @@ void LinuxPlatform::cmdLineArgs(int argc, char** argv) #define MAX_NUM_GPIO 64 static int gpioFds[MAX_NUM_GPIO] = - { - -1, +{ + -1, -1, -1, -1, @@ -812,7 +842,7 @@ static int gpioFds[MAX_NUM_GPIO] = -1, -1, -1, -}; + }; /* Activate GPIO-Pin * Write GPIO pin number to /sys/class/gpio/export @@ -828,6 +858,7 @@ int gpio_export(int pin) fprintf(stderr, "Export GPIO pin %d\n", pin); fd = open("/sys/class/gpio/export", O_WRONLY); + if (fd < 0) { perror("Could not export GPIO pin(open)!\n"); @@ -865,6 +896,7 @@ int gpio_unexport(int pin) close(gpioFds[pin]); fd = open("/sys/class/gpio/unexport", O_WRONLY); + if (fd < 0) { perror("Could not unexport GPIO pin(open)!\n"); @@ -899,6 +931,7 @@ int gpio_direction(int pin, int dir) snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/direction", pin); fd = open(path, O_WRONLY); + if (fd < 0) { perror("Could not set mode for GPIO pin(open)!\n"); @@ -910,9 +943,11 @@ int gpio_direction(int pin, int dir) case INPUT: res = write(fd, "in", 2); break; + case OUTPUT: res = write(fd, "out", 3); break; + default: res = -1; break; @@ -937,8 +972,10 @@ int gpio_read(int pin) char c; snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/value", pin); + if (gpioFds[pin] < 0) gpioFds[pin] = open(path, O_RDWR); + if (gpioFds[pin] < 0) { perror("Could not read from GPIO(open)!\n"); @@ -946,6 +983,7 @@ int gpio_read(int pin) } lseek(gpioFds[pin], 0L, SEEK_SET); + if (read(gpioFds[pin], &c, 1) < 0) { perror("Could not read from GPIO(read)!\n"); @@ -964,6 +1002,7 @@ int gpio_write(int pin, int value) int res; /* Result from write()*/ snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/value", pin); + if (gpioFds[pin] < 0) gpioFds[pin] = open(path, O_RDWR); @@ -978,9 +1017,11 @@ int gpio_write(int pin, int value) case LOW: res = write(gpioFds[pin], "0\n", 2); break; + case HIGH: res = write(gpioFds[pin], "1\n", 2); break; + default: res = -1; break; @@ -1008,6 +1049,7 @@ int gpio_edge(unsigned int pin, char edge) snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/edge", pin); fd = open(path, O_WRONLY | O_NONBLOCK); + if (fd < 0) { perror("Could not set GPIO edge detection(open)!\n"); @@ -1019,15 +1061,19 @@ int gpio_edge(unsigned int pin, char edge) 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); @@ -1056,6 +1102,7 @@ int gpio_wait(unsigned int pin, int timeout) /* 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) { perror("Could not wait for GPIO edge(open)!\n"); @@ -1073,15 +1120,18 @@ int gpio_wait(unsigned int pin, int timeout) rc = read(fd, buf, MAX_STRBUF_SIZE - 1); rc = poll(polldat, 1, timeout); + if (rc < 0) - { /* poll() failed! */ + { + /* poll() failed! */ perror("Could not wait for GPIO edge(poll)!\n"); close(fd); return (-1); } if (rc == 0) - { /* poll() timeout! */ + { + /* poll() timeout! */ close(fd); return (0); } @@ -1089,11 +1139,13 @@ int gpio_wait(unsigned int pin, int timeout) if (polldat[0].revents & POLLPRI) { if (rc < 0) - { /* read() failed! */ + { + /* read() failed! */ perror("Could not wait for GPIO edge(read)!\n"); close(fd); return (-2); } + /* printf("poll() GPIO %d interrupt occurred: %s\n", pin, buf); */ close(fd); return (1 + atoi(buf)); @@ -1112,7 +1164,7 @@ void delayMicrosecondsHard(unsigned int howLong) tLong.tv_usec = howLong % 1000000; timeradd(&tNow, &tLong, &tEnd); - while (timercmp(&tNow, &tEnd, <)) + while (timercmp(&tNow, &tEnd, < )) gettimeofday(&tNow, NULL); } @@ -1142,15 +1194,18 @@ bool LinuxPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buff 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; } diff --git a/src/linux_platform.h b/src/linux_platform.h index d691e634..c06ac3df 100644 --- a/src/linux_platform.h +++ b/src/linux_platform.h @@ -13,69 +13,69 @@ 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; + 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 diff --git a/src/rp2040_arduino_platform.cpp b/src/rp2040_arduino_platform.cpp index 472d86b2..44ae730c 100644 --- a/src/rp2040_arduino_platform.cpp +++ b/src/rp2040_arduino_platform.cpp @@ -96,17 +96,17 @@ void __time_critical_func(uartDmaRestart)() #define FLASHPTR ((uint8_t*)XIP_BASE + KNX_FLASH_OFFSET) #ifndef USE_RP2040_EEPROM_EMULATION -#if KNX_FLASH_SIZE % 4096 -#error "KNX_FLASH_SIZE must be multiple of 4096" -#endif + #if KNX_FLASH_SIZE % 4096 + #error "KNX_FLASH_SIZE must be multiple of 4096" + #endif -#if KNX_FLASH_OFFSET % 4096 -#error "KNX_FLASH_OFFSET must be multiple of 4096" -#endif + #if KNX_FLASH_OFFSET % 4096 + #error "KNX_FLASH_OFFSET must be multiple of 4096" + #endif #endif #ifdef KNX_IP_LAN -extern Wiznet5500lwIP KNX_NETIF; + extern Wiznet5500lwIP KNX_NETIF; #elif defined(KNX_IP_WIFI) #elif defined(KNX_IP_GENERIC) @@ -148,6 +148,7 @@ bool RP2040ArduinoPlatform::overflowUart() // during dma restart bool ret; const uint32_t writeCount = uartDmaWriteCount(); + if (uartDmaRestartCount > 0) ret = writeCount >= (uartDmaBufferSize - uartDmaRestartCount - 1); else @@ -175,6 +176,7 @@ bool RP2040ArduinoPlatform::overflowUart() void RP2040ArduinoPlatform::setupUart() { #ifdef USE_KNX_DMA_UART + if (uartDmaChannel == -1) { // configure uart0 @@ -203,21 +205,27 @@ void RP2040ArduinoPlatform::setupUart() irq_set_exclusive_handler(KNX_DMA_IRQ, uartDmaRestart); irq_set_enabled(KNX_DMA_IRQ, true); } + #else SerialUART* serial = dynamic_cast(_knxSerial); + if (serial) { if (_rxPin != UART_PIN_NOT_DEFINED) serial->setRX(_rxPin); + if (_txPin != UART_PIN_NOT_DEFINED) serial->setTX(_txPin); + serial->setPollingMode(); serial->setFIFOSize(64); } _knxSerial->begin(19200, SERIAL_8E1); + while (!_knxSerial) ; + #endif } @@ -272,6 +280,7 @@ size_t RP2040ArduinoPlatform::writeUart(const uint8_t data) // println(data, HEX); while (!uart_is_writable(uart0)) ; + uart_putc_raw(uart0, data); return 1; } @@ -478,8 +487,8 @@ void RP2040ArduinoPlatform::setupMultiCast(uint32_t addr, uint16_t 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: "); @@ -509,14 +518,17 @@ bool RP2040ArduinoPlatform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) 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 > maxLen) { println("Unexpected UDP data packet length - drop packet"); + for (size_t i = 0; i < len; i++) _udp.read(); + return 0; } @@ -538,22 +550,26 @@ bool RP2040ArduinoPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8 { IPAddress ucastaddr(htonl(addr)); - if(!addr) + if (!addr) ucastaddr = _remoteIP; - - if(!port) + + if (!port) port = _remotePort; + // print("sendBytesUniCast to:"); // println(ucastaddr.toString().c_str()); #ifdef KNX_IP_GENERIC + 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.endPacket() == 0) println("sendBytesUniCast endPacket fail"); } diff --git a/src/rp2040_arduino_platform.h b/src/rp2040_arduino_platform.h index aa6e7460..1a5d13be 100644 --- a/src/rp2040_arduino_platform.h +++ b/src/rp2040_arduino_platform.h @@ -7,133 +7,149 @@ #ifdef ARDUINO_ARCH_RP2040 #ifndef USE_RP2040_EEPROM_EMULATION -#ifndef KNX_FLASH_OFFSET -#define KNX_FLASH_OFFSET 0x180000 // 1.5MiB -#pragma warning "KNX_FLASH_OFFSET not defined, using 0x180000" -#endif + #ifndef KNX_FLASH_OFFSET + #define KNX_FLASH_OFFSET 0x180000 // 1.5MiB + #pragma warning "KNX_FLASH_OFFSET not defined, using 0x180000" + #endif #endif #ifdef USE_RP2040_LARGE_EEPROM_EMULATION -#define USE_RP2040_EEPROM_EMULATION + #define USE_RP2040_EEPROM_EMULATION #endif #ifndef KNX_SERIAL -#pragma warn "KNX_SERIAL not defined, using Serial1" -#define KNX_SERIAL Serial1 + #pragma warn "KNX_SERIAL not defined, using Serial1" + #define KNX_SERIAL Serial1 #endif #ifdef KNX_IP_LAN -#if ARDUINO_PICO_MAJOR * 10000 + ARDUINO_PICO_MINOR * 100 + ARDUINO_PICO_REVISION < 30700 -#pragma error "arduino-pico >= 3.7.0 needed" -#endif -#define KNX_NETIF Eth + #if ARDUINO_PICO_MAJOR * 10000 + ARDUINO_PICO_MINOR * 100 + ARDUINO_PICO_REVISION < 30700 + #pragma error "arduino-pico >= 3.7.0 needed" + #endif + #define KNX_NETIF Eth -#include "SPI.h" -#include + #include "SPI.h" + #include #else -#include -#define KNX_NETIF WiFi + #include + #define KNX_NETIF WiFi #endif #if USE_KNX_DMA_UART == 1 -#define KNX_DMA_UART uart1 -#define KNX_DMA_UART_IRQ UART1_IRQ -#define KNX_DMA_UART_DREQ DREQ_UART1_RX + #define KNX_DMA_UART uart1 + #define KNX_DMA_UART_IRQ UART1_IRQ + #define KNX_DMA_UART_DREQ DREQ_UART1_RX #else -#define KNX_DMA_UART uart0 -#define KNX_DMA_UART_IRQ UART0_IRQ -#define KNX_DMA_UART_DREQ DREQ_UART0_RX + #define KNX_DMA_UART uart0 + #define KNX_DMA_UART_IRQ UART0_IRQ + #define KNX_DMA_UART_DREQ DREQ_UART0_RX #endif #if USE_KNX_DMA_IRQ == 1 -#define KNX_DMA_IRQ DMA_IRQ_1 + #define KNX_DMA_IRQ DMA_IRQ_1 #else -#define KNX_DMA_IRQ DMA_IRQ_0 + #define KNX_DMA_IRQ DMA_IRQ_0 #endif 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 {}; - #endif - - - // unique serial number - uint32_t uniqueSerialNumber() override; - - void restart(); + 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 {}; +#endif - #ifdef USE_RP2040_EEPROM_EMULATION - uint8_t* getEepromBuffer(uint32_t size); - void commitToEeprom(); - #ifdef USE_RP2040_LARGE_EEPROM_EMULATION - 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(); - #endif + // unique serial number + uint32_t uniqueSerialNumber() override; + void restart(); - #if defined(KNX_NETIF) - uint32_t currentIpAddress() override; - uint32_t currentSubnetMask() override; - uint32_t currentDefaultGateway() override; - void macAddress(uint8_t* addr) override; +#ifdef USE_RP2040_EEPROM_EMULATION + uint8_t* getEepromBuffer(uint32_t size); + void commitToEeprom(); - // 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; +#ifdef USE_RP2040_LARGE_EEPROM_EMULATION + uint8_t _rambuff[KNX_FLASH_SIZE]; + bool _rambuff_initialized = false; +#endif +#else - // unicast - bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override; + // 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 - #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; +#if defined(KNX_NETIF) + 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; + + // 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; }; #endif diff --git a/src/samd_platform.cpp b/src/samd_platform.cpp index 49b9ec4a..ce26b84c 100644 --- a/src/samd_platform.cpp +++ b/src/samd_platform.cpp @@ -5,15 +5,15 @@ #include #ifdef USE_SAMD_EEPROM_EMULATION -#include + #include #endif #if KNX_FLASH_SIZE % 1024 -#error "KNX_FLASH_SIZE must be multiple of 1024" + #error "KNX_FLASH_SIZE must be multiple of 1024" #endif #ifndef KNX_SERIAL -#define KNX_SERIAL Serial1 + #define KNX_SERIAL Serial1 #endif SamdPlatform::SamdPlatform() @@ -35,20 +35,20 @@ SamdPlatform::SamdPlatform( HardwareSerial* s) : ArduinoPlatform(s) uint32_t SamdPlatform::uniqueSerialNumber() { - #if defined (__SAMD51__) - // 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 +#if defined (__SAMD51__) + // 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 - #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 +#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; } @@ -64,9 +64,9 @@ void SamdPlatform::restart() uint8_t* SamdPlatform::getEepromBuffer(uint32_t size) { //EEPROM.begin(size); - if(size > EEPROM_EMULATION_SIZE) + if (size > EEPROM_EMULATION_SIZE) fatalError(); - + return EEPROM.getDataPtr(); } @@ -98,8 +98,10 @@ void SamdPlatform::init() _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) { + if (_MemoryStart < endEddr) + { println("KNX_FLASH_SIZE is not available (possible too much flash use by firmware)"); fatalError(); } @@ -132,7 +134,7 @@ void SamdPlatform::flashErase(uint16_t eraseBlockNum) { noInterrupts(); - eraseRow((void *)(_MemoryStart + eraseBlockNum * _rowSize)); + eraseRow((void*)(_MemoryStart + eraseBlockNum * _rowSize)); // flash_range_erase(KNX_FLASH_OFFSET + eraseBlockNum * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize()); interrupts(); @@ -142,7 +144,7 @@ void SamdPlatform::flashWritePage(uint16_t pageNumber, uint8_t* data) { noInterrupts(); - write((void *)(_MemoryStart + pageNumber * _pageSize), data, _pageSize); + write((void*)(_MemoryStart + pageNumber * _pageSize), data, _pageSize); // flash_range_program(KNX_FLASH_OFFSET + pageNumber * flashPageSize(), data, flashPageSize()); interrupts(); @@ -154,8 +156,8 @@ void SamdPlatform::writeBufferedEraseBlock() { noInterrupts(); - eraseRow((void *)(_MemoryStart + _bufferedEraseblockNumber * _rowSize)); - write((void *)(_MemoryStart + _bufferedEraseblockNumber * _rowSize), _eraseblockBuffer, _rowSize); + 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()); @@ -170,12 +172,12 @@ 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) +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* 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; @@ -187,12 +189,14 @@ void SamdPlatform::write(const volatile void *flash_ptr, const void *data, uint3 { // 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; @@ -203,28 +207,32 @@ void SamdPlatform::write(const volatile void *flash_ptr, const void *data, uint3 // Execute "WP" Write Page NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP; + while (NVMCTRL->INTFLAG.bit.READY == 0) { } } } -void SamdPlatform::erase(const volatile void *flash_ptr, uint32_t size) +void SamdPlatform::erase(const volatile void* flash_ptr, uint32_t size) { - const uint8_t *ptr = (const uint8_t *)flash_ptr; + 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) +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) { } diff --git a/src/samd_platform.h b/src/samd_platform.h index 948a5d8e..45399d1f 100644 --- a/src/samd_platform.h +++ b/src/samd_platform.h @@ -8,46 +8,46 @@ class SamdPlatform : public ArduinoPlatform { -public: - SamdPlatform(); - SamdPlatform( HardwareSerial* s); + 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); + // 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 }; diff --git a/src/stm32_platform.cpp b/src/stm32_platform.cpp index f5e5b28b..6e55ea45 100644 --- a/src/stm32_platform.cpp +++ b/src/stm32_platform.cpp @@ -5,7 +5,7 @@ #include "knx/bits.h" #ifndef KNX_SERIAL -#define KNX_SERIAL Serial2 + #define KNX_SERIAL Serial2 #endif Stm32Platform::Stm32Platform() @@ -34,7 +34,7 @@ void Stm32Platform::restart() NVIC_SystemReset(); } -uint8_t * Stm32Platform::getEepromBuffer(uint32_t size) +uint8_t* Stm32Platform::getEepromBuffer(uint32_t size) { // check if the buffer already exists if (_eepromPtr == nullptr) // we need to initialize the buffer first @@ -47,19 +47,22 @@ uint8_t * Stm32Platform::getEepromBuffer(uint32_t size) _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); } - + return _eepromPtr; } void Stm32Platform::commitToEeprom() { - if(_eepromPtr == nullptr || _eepromSize == 0) + if (_eepromPtr == nullptr || _eepromSize == 0) return; + 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) diff --git a/src/stm32_platform.h b/src/stm32_platform.h index 7545ca09..daa50a04 100644 --- a/src/stm32_platform.h +++ b/src/stm32_platform.h @@ -3,23 +3,23 @@ class Stm32Platform : public ArduinoPlatform { -public: - Stm32Platform(); - Stm32Platform( HardwareSerial* s); - ~Stm32Platform(); + public: + Stm32Platform(); + Stm32Platform( HardwareSerial* s); + ~Stm32Platform(); - // unique serial number - uint32_t uniqueSerialNumber() override; + // unique serial number + uint32_t uniqueSerialNumber() override; - // basic stuff - void restart(); - - //memory - uint8_t* getEepromBuffer(uint32_t size); - void commitToEeprom(); -private: - uint8_t *_eepromPtr = nullptr; - uint16_t _eepromSize = 0; + // basic stuff + void restart(); + + //memory + uint8_t* getEepromBuffer(uint32_t size); + void commitToEeprom(); + private: + uint8_t* _eepromPtr = nullptr; + uint16_t _eepromSize = 0; }; #endif