From 77a796a39ce6140fb5314db8a5d2d58c9f74f8d2 Mon Sep 17 00:00:00 2001 From: nanosonde <2073569+nanosonde@users.noreply.github.com> Date: Sun, 6 Sep 2020 21:41:34 +0200 Subject: [PATCH] Add coupler support (#79) * save work. * save work * save work * save work * save work * Remember which interface received the cemi frame * save work * save work * save work * Use default value from PID_ROUTING_COUNT * Add simple alternative to std::function without smart pointers or move semantics * Remove include * Add more comments about cleanup * save work * Remove forgotten code. * Move crc16Ccitt to bits.c as it also used for PID_MCB * save work * move comment * save work * save work * save work * save work * save work * save work * save work * derive from TableObject instead of InterfaceObject * save work * save work * Fix wrong pointer arithmetic in TableObject * Filter table setting/clearing * move comment * save work * save work * save work * handle SBC on closed media * save work * move coupler example to different dir * Restore device example for linux * save work * Remove MEDIUM_TYPE and use MASK_VERSION * save work * save work * save work * save work * save work * save work * save work * save work * save work * save work * save work * save work * save work * save work * Replace MEDIUM_TYPE by MASK_VERSION * Remove adafruit/travis-ci tests * Disable travis ci cache for platformio * Fix missing changes * Fix cemi server and add missing MASK_VERSION definitions * Enable platformio caching on travis ci again * Handle device address update for routing decision * source address is set in network layer and not in data link layer * Add remaining APCI types that are used with system broadcast * Add debug print for routing * Remove simple_functional * Fix CMakLists.txt * Use MASK_VERSION to conditionally compile code. * Remove fixed version reuqirement from platform esp8266 * Add demo-coupler for MCUs * Remove simple_functional.h from demo knx-linux * Enable CI for coupler demos * Correct path for knx-linux-coupler * Fix knx_facade.h * Refactor NetworkLayer to use getInterface() for devices and getPrimaryInterface(), getSecondaryInterface() for couplers * Add platformio configs for other currently possible mask/platform combinations * Add class diagrams and remove obsolete includes * Add some minimal docs --- .travis.yml | 57 +- doc/knx_coupler_notes.md | 17 + doc/knx_data_secure_notes.md | 25 + .../knx-demo-coupler/knx-demo-coupler.ino | 38 + examples/knx-demo-coupler/platformio-ci.ini | 54 ++ examples/knx-demo-coupler/platformio.ini | 71 ++ examples/knx-demo/platformio-ci.ini | 49 +- examples/knx-demo/platformio.ini | 44 +- examples/knx-linux-coupler/CMakeLists.txt | 138 +++ examples/knx-linux-coupler/CMakeSettings.json | 19 + examples/knx-linux-coupler/fdsk.cpp | 196 ++++ examples/knx-linux-coupler/fdsk.h | 37 + examples/knx-linux-coupler/gcc_Debug.h | 889 +++++++++++++++++ examples/knx-linux-coupler/gcc_Release.h | 895 ++++++++++++++++++ .../knx-linux-Debug.vgdbsettings | 179 ++++ examples/knx-linux-coupler/knx-linux.vcxproj | 188 ++++ .../knx-linux.vcxproj.filters | 353 +++++++ examples/knx-linux-coupler/main.cpp | 112 +++ examples/knx-linux/CMakeLists.txt | 163 ++-- examples/knx-linux/main.cpp | 7 +- examples/knx-usb/platformio-ci.ini | 2 +- examples/knx-usb/platformio.ini | 2 +- src/knx.h | 207 +++- src/knx/application_layer.cpp | 66 +- src/knx/application_layer.h | 8 +- src/knx/bau07B0.cpp | 42 +- src/knx/bau07B0.h | 18 +- src/knx/bau091A.cpp | 169 ++++ src/knx/bau091A.h | 39 + src/knx/bau27B0.cpp | 23 +- src/knx/bau27B0.h | 12 +- src/knx/bau2920.cpp | 157 +++ src/knx/bau2920.h | 37 + src/knx/bau57B0.cpp | 29 +- src/knx/bau57B0.h | 11 +- src/knx/bau_systemB.cpp | 270 +----- src/knx/bau_systemB.h | 50 +- src/knx/bau_systemB_coupler.cpp | 62 ++ src/knx/bau_systemB_coupler.h | 40 + src/knx/bau_systemB_device.cpp | 226 +++++ src/knx/bau_systemB_device.h | 57 ++ src/knx/bits.cpp | 30 + src/knx/bits.h | 2 + src/knx/cemi_frame.cpp | 2 +- src/knx/cemi_frame.h | 4 +- src/knx/cemi_server.cpp | 84 +- src/knx/cemi_server_object.cpp | 47 +- src/knx/cemi_server_object.h | 6 +- src/knx/config.h | 42 +- src/knx/data_link_layer.cpp | 48 +- src/knx/data_link_layer.h | 17 +- src/knx/device_object.cpp | 13 +- src/knx/device_object.h | 3 +- src/knx/ip_data_link_layer.cpp | 14 +- src/knx/ip_data_link_layer.h | 6 +- src/knx/knx_types.h | 14 + src/knx/network_layer.cpp | 145 +-- src/knx/network_layer.h | 53 +- src/knx/network_layer_coupler.cpp | 456 +++++++++ src/knx/network_layer_coupler.h | 75 ++ src/knx/network_layer_device.cpp | 148 +++ src/knx/network_layer_device.h | 44 + src/knx/network_layer_entity.cpp | 64 ++ src/knx/network_layer_entity.h | 42 + src/knx/property.h | 16 + src/knx/rf_data_link_layer.cpp | 13 +- src/knx/rf_data_link_layer.h | 8 +- src/knx/rf_medium_object.cpp | 8 +- src/knx/rf_medium_object.h | 3 +- src/knx/rf_physical_layer.cpp | 21 - src/knx/rf_physical_layer.h | 1 - src/knx/router_object.cpp | 505 ++++++++++ src/knx/router_object.h | 60 ++ src/knx/secure_application_layer.cpp | 43 +- src/knx/secure_application_layer.h | 8 +- src/knx/security_interface_object.cpp | 34 +- src/knx/security_interface_object.h | 10 +- src/knx/tpuart_data_link_layer.cpp | 46 +- src/knx/tpuart_data_link_layer.h | 19 +- src/knx/transport_layer.cpp | 19 +- src/knx/transport_layer.h | 5 +- src/knx_facade.cpp | 55 +- src/knx_facade.h | 61 +- 83 files changed, 6406 insertions(+), 946 deletions(-) create mode 100644 doc/knx_coupler_notes.md create mode 100644 doc/knx_data_secure_notes.md create mode 100644 examples/knx-demo-coupler/knx-demo-coupler.ino create mode 100644 examples/knx-demo-coupler/platformio-ci.ini create mode 100644 examples/knx-demo-coupler/platformio.ini create mode 100644 examples/knx-linux-coupler/CMakeLists.txt create mode 100644 examples/knx-linux-coupler/CMakeSettings.json create mode 100644 examples/knx-linux-coupler/fdsk.cpp create mode 100644 examples/knx-linux-coupler/fdsk.h create mode 100644 examples/knx-linux-coupler/gcc_Debug.h create mode 100644 examples/knx-linux-coupler/gcc_Release.h create mode 100644 examples/knx-linux-coupler/knx-linux-Debug.vgdbsettings create mode 100644 examples/knx-linux-coupler/knx-linux.vcxproj create mode 100644 examples/knx-linux-coupler/knx-linux.vcxproj.filters create mode 100644 examples/knx-linux-coupler/main.cpp create mode 100644 src/knx/bau091A.cpp create mode 100644 src/knx/bau091A.h create mode 100644 src/knx/bau2920.cpp create mode 100644 src/knx/bau2920.h create mode 100644 src/knx/bau_systemB_coupler.cpp create mode 100644 src/knx/bau_systemB_coupler.h create mode 100644 src/knx/bau_systemB_device.cpp create mode 100644 src/knx/bau_systemB_device.h create mode 100644 src/knx/network_layer_coupler.cpp create mode 100644 src/knx/network_layer_coupler.h create mode 100644 src/knx/network_layer_device.cpp create mode 100644 src/knx/network_layer_device.h create mode 100644 src/knx/network_layer_entity.cpp create mode 100644 src/knx/network_layer_entity.h create mode 100644 src/knx/router_object.cpp create mode 100644 src/knx/router_object.h diff --git a/.travis.yml b/.travis.yml index 1eeb901..615a9f6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,53 +29,13 @@ - cd build - cmake .. - make - - # Test build for Arduino platform - - language: cpp - os: linux - env: - - ARDUINO_IDE_VERSION="1.8.11" - cache: - directories: - - ~/arduino_ide - - ~/.arduino15/packages/ - git: - depth: false - quiet: true - before_install: - - downloadArduinoLib() { wget -O $1.zip $2; unzip -o $1.zip -d $HOME/arduino_ide/libraries; } - - source <(curl -SLs "https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh") - - downloadArduinoLib FlashStorage "https://github.com/thelsing/FlashStorage/archive/master.zip" - - downloadArduinoLib BSEC "https://github.com/BoschSensortec/BSEC-Arduino-library/archive/master.zip" - # only default warning level - - sed -i 's#compiler.warning_level=all#compiler.warning_level=default#' ~/.arduino15/preferences.txt - # changes for bsec lib - # samd - - ls -l ~/.arduino15/packages/arduino/hardware/samd - - sed -ri 's#(recipe.c.combine.pattern=[^$]*\{archive_file\}")( -Wl,--end-group)#\1 {compiler.libraries.ldflags}\2#' ~/.arduino15/packages/arduino/hardware/samd/1.8.6/platform.txt - - sed -i 's#compiler.elf2hex.extra_flags=#compiler.elf2hex.extra_flags=\ncompiler.libraries.ldflags=#' ~/.arduino15/packages/arduino/hardware/samd/1.8.6/platform.txt - # esp8266 - - ls -l ~/.arduino15/packages/esp8266/hardware/esp8266 - - sed -ri 's#(recipe.c.combine.pattern=[^$]*\{compiler.c.elf.libs\})( -Wl,--end-group "-L\{build.path\}")#\1 {compiler.libraries.ldflags}\2#' ~/.arduino15/packages/esp8266/hardware/esp8266/2.7.1/platform.txt - - sed -i 's#compiler.elf2hex.extra_flags=#compiler.elf2hex.extra_flags=\ncompiler.libraries.ldflags=#' ~/.arduino15/packages/esp8266/hardware/esp8266/2.7.1/platform.txt - - sed -i '/^.*libalgobsec.*$/d' ~/.arduino15/packages/esp8266/hardware/esp8266/2.7.1/tools/sdk/ld/eagle.app.v6.common.ld.h - - sed -ri 's#(\*libwps\.a:\(\.literal\.\* \.text\.\*\))#\1\n *libalgobsec.a:(.literal.* .text.*)#' ~/.arduino15/packages/esp8266/hardware/esp8266/2.7.1/tools/sdk/ld/eagle.app.v6.common.ld.h - - # the HDC100X lib is not properly set up in githup so move things around a bit - - rm -rf $HOME/arduino_ide/libraries/HDC100X_Arduino_Library-master - - downloadArduinoLib HDC100X "https://github.com/RFgermany/HDC100X_Arduino_Library/archive/master.zip" - - mv $HOME/arduino_ide/libraries/HDC100X_Arduino_Library-master/HDC100X/* $HOME/arduino_ide/libraries/HDC100X_Arduino_Library-master - #- buildExampleSketch() { arduino --verify --board $BOARD $PWD/examples/$1/$1.ino; } - - install: - - arduino --install-library "WiFiManager" - script: - # - buildExampleSketch knx-demo - # - buildExampleSketch knx-sonoffS20 - # - buildExampleSketch knx-bme680 - # - buildExampleSketch knx-hdc1008 - - build_platform zero - # - build_platform esp8266 + - cd ../.. + - echo "building knx-linux-coupler" + - cd knx-linux-coupler + - mkdir -p build + - cd build + - cmake .. + - make # Test build for PlatformIO based projects - language: python @@ -103,6 +63,9 @@ - echo "-------";echo "Compiling example knx-demo";echo "--------"; - platformio ci --lib="." --project-conf=examples/knx-demo/platformio-ci.ini examples/knx-demo/knx-demo.ino + - echo "-------";echo "Compiling example knx-demo-coupler";echo "--------"; + - platformio ci --lib="." --project-conf=examples/knx-demo-coupler/platformio-ci.ini examples/knx-demo-coupler/knx-demo-coupler.ino + notifications: email: on_success: change diff --git a/doc/knx_coupler_notes.md b/doc/knx_coupler_notes.md new file mode 100644 index 0000000..10576c0 --- /dev/null +++ b/doc/knx_coupler_notes.md @@ -0,0 +1,17 @@ +KNX Coupler +=========== + +Implementation Notes +-------------------- +* Add support for coupler model 1.x and coupler model 2.0 (only used for TP1/RF coupler so far) +* currently implemented mask versions: 091A (IP/TP1 coupler) and 2920 (TP1/RF coupler) + +ToDo: +----- +* class NetworkLayerCoupler: add support for all ACK modes for medium TP1, currently ALL received frames are ACK'ed (mode 2). +* handle MasterReset according to spec. for router object + +Development environment +----------------------- +* see linux coupler example + diff --git a/doc/knx_data_secure_notes.md b/doc/knx_data_secure_notes.md new file mode 100644 index 0000000..89150f1 --- /dev/null +++ b/doc/knx_data_secure_notes.md @@ -0,0 +1,25 @@ +KNX Data Secure +=============== + +Implementation Notes +-------------------- +* Implementation based on application note AN158 v07 KNX Data Security +* AES-128 is implemented in software, no hardware acceleration used currently +* Secure device setup with ETS-5.7.x tested and working +* Secure group communication needs more testing +* Support for FDSK generation +* Support for P2P mode prepared +* No support for LTE-mode[T_Data_Tag_Group] (zone key table is already there) currently +* No support roles (and no plan to implement this in the near future) + +ToDo: +----- +* Add support for AN192 v04 Coupler security extensions (a.k.a. Secure Proxy which translates between unsecured and secured devices) +* Handle S-A_Sync Service when initially the last valid sequence nummer is not known during runtime, i.e. group communication +* handle MasterReset according to spec. for security interface object + +Development environment +----------------------- +* see linux example on how to generate the FDSK string which needs to be entered in the ETS +* use BAU57B0, but fake the mask by setting _deviceObj.maskVersion(0x07B0). This "emulates" a TP1 device which is reachable over an IP router +* To generate a KNX ETS product database with support for KNX Data Secure, use the latest version of the CreateKnxProd tool which supports schema version 20. diff --git a/examples/knx-demo-coupler/knx-demo-coupler.ino b/examples/knx-demo-coupler/knx-demo-coupler.ino new file mode 100644 index 0000000..6e29bcc --- /dev/null +++ b/examples/knx-demo-coupler/knx-demo-coupler.ino @@ -0,0 +1,38 @@ +#include + +void setup() +{ + Serial.begin(115200); + ArduinoPlatform::SerialDebug = &Serial; + + randomSeed(millis()); + + // read adress table, association table, groupobject table and parameters from eeprom + knx.readMemory(); + + // print values of parameters if device is already configured + if (knx.configured()) + { + Serial.println("Coupler configured."); + } + + // pin or GPIO the programming led is connected to. Default is LED_BUILTIN + // knx.ledPin(LED_BUILTIN); + // is the led active on HIGH or low? Default is LOW + // knx.ledPinActiveOn(HIGH); + // pin or GPIO programming button is connected to. Default is 0 + // knx.buttonPin(0); + + // start the framework. + knx.start(); +} + +void loop() +{ + // don't delay here to much. Otherwise you might lose packages or mess up the timing with ETS + knx.loop(); + + // only run the application code if the device was configured with ETS + if (!knx.configured()) + return; +} diff --git a/examples/knx-demo-coupler/platformio-ci.ini b/examples/knx-demo-coupler/platformio-ci.ini new file mode 100644 index 0000000..1a2bd5f --- /dev/null +++ b/examples/knx-demo-coupler/platformio-ci.ini @@ -0,0 +1,54 @@ +;PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +;--- SAMD -------------------------------------------------- +[env:adafruit_feather_m0_tp_rf] +platform = atmelsam +board = adafruit_feather_m0 +framework = arduino +lib_deps = + SPI + https://github.com/thelsing/FlashStorage.git + knx + +build_flags = + -DMASK_VERSION=0x2920 + -Wno-unknown-pragmas + +;----------------------------------------------------------- + + +;--- ESP8266 ----------------------------------------------- +#[env:nodemcuv2_ip_tp] +#platform = espressif8266 +#board = nodemcuv2 +#framework = arduino +#lib_deps = +# WifiManager +# knx + +#build_flags = +# -DMASK_VERSION=0x091A +# -Wno-unknown-pragmas + +;--------------------------------------------------------- + + +;--- ESP32 ----------------------------------------------- +[env:esp32dev_ip_tp] +platform = espressif32 +board = esp32dev +framework = arduino +lib_deps = + knx + +build_flags = + -DMASK_VERSION=0x091A + -Wno-unknown-pragmas diff --git a/examples/knx-demo-coupler/platformio.ini b/examples/knx-demo-coupler/platformio.ini new file mode 100644 index 0000000..18169f8 --- /dev/null +++ b/examples/knx-demo-coupler/platformio.ini @@ -0,0 +1,71 @@ +;PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html +[platformio] +; We have to keep libdeps dir out the project directory otherwise, +; library scanner seems to have issues so compilation fails +libdeps_dir = /tmp/libdeps +src_dir = . + +;--- SAMD -------------------------------------------------- +[env:adafruit_feather_m0_tp_rf] +platform = atmelsam +board = adafruit_feather_m0 +framework = arduino +; We consider that the this projects is opened within its project directory +; while working with VS Code. +lib_extra_dirs = ../../../ + +lib_deps = + SPI + https://github.com/thelsing/FlashStorage.git + knx + +build_flags = + -DMASK_VERSION=0x2920 + -Wno-unknown-pragmas + +;----------------------------------------------------------- + + +;--- ESP8266 ----------------------------------------------- +#[env:nodemcuv2_ip_tp] +#platform = espressif8266 +#board = nodemcuv2 +#framework = arduino +; We consider that the this projects is opened within its project directory +; while working with VS Code. +#lib_extra_dirs = ../../../ + +#lib_deps = +# WifiManager +# knx + +#build_flags = +# -DMASK_VERSION=0x091A +# -Wno-unknown-pragmas + +;--------------------------------------------------------- + + +;--- ESP32 ----------------------------------------------- +[env:esp32dev_ip_tp] +platform = espressif32 +board = esp32dev +framework = arduino +; We consider that the this projects is opened within its project directory +; while working with VS Code. +lib_extra_dirs = ../../../ + +lib_deps = + knx + +build_flags = + -DMASK_VERSION=0x091A + -Wno-unknown-pragmas diff --git a/examples/knx-demo/platformio-ci.ini b/examples/knx-demo/platformio-ci.ini index 57c4188..26ae5c9 100644 --- a/examples/knx-demo/platformio-ci.ini +++ b/examples/knx-demo/platformio-ci.ini @@ -9,7 +9,7 @@ ; https://docs.platformio.org/page/projectconf.html ;--- SAMD -------------------------------------------------- -[env:adafruit_feather_m0] +[env:adafruit_feather_m0_rf] platform = atmelsam board = adafruit_feather_m0 framework = arduino @@ -19,28 +19,41 @@ lib_deps = knx build_flags = - -DMEDIUM_TYPE=2 + -DMASK_VERSION=0x27B0 -Wno-unknown-pragmas ;----------------------------------------------------------- ;--- ESP8266 ----------------------------------------------- -[env:nodemcuv2] -platform = espressif8266@2.2.3 -board = nodemcuv2 -framework = arduino -lib_deps = - WifiManager - knx +#[env:nodemcuv2_ip] +#platform = espressif8266 +#board = nodemcuv2 +#framework = arduino +#lib_deps = +# WifiManager +# knx -build_flags = - -Wno-unknown-pragmas +#build_flags = +# -DMASK_VERSION=0x57B0 +# -Wno-unknown-pragmas + +#[env:nodemcuv2_tp] +#platform = espressif8266 +#board = nodemcuv2 +#framework = arduino +#lib_deps = +# WifiManager +# knx + +#build_flags = +# -DMASK_VERSION=0x07B0 +# -Wno-unknown-pragmas ;--------------------------------------------------------- ;--- ESP32 ----------------------------------------------- -[env:esp32dev] +[env:esp32dev_ip] platform = espressif32 board = esp32dev framework = arduino @@ -48,4 +61,16 @@ lib_deps = knx build_flags = + -DMASK_VERSION=0x57B0 + -Wno-unknown-pragmas + +[env:esp32dev_tp] +platform = espressif32 +board = esp32dev +framework = arduino +lib_deps = + knx + +build_flags = + -DMASK_VERSION=0x07B0 -Wno-unknown-pragmas diff --git a/examples/knx-demo/platformio.ini b/examples/knx-demo/platformio.ini index 6134de6..0371159 100644 --- a/examples/knx-demo/platformio.ini +++ b/examples/knx-demo/platformio.ini @@ -14,7 +14,7 @@ libdeps_dir = /tmp/libdeps src_dir = . ;--- SAMD -------------------------------------------------- -[env:adafruit_feather_m0] +[env:adafruit_feather_m0_rf] platform = atmelsam board = adafruit_feather_m0 framework = arduino @@ -28,14 +28,30 @@ lib_deps = knx build_flags = - -DMEDIUM_TYPE=2 + -DMASK_VERSION=0x27B0 -Wno-unknown-pragmas ;----------------------------------------------------------- ;--- ESP8266 ----------------------------------------------- -[env:nodemcuv2] -platform = espressif8266@2.2.3 +#[env:nodemcuv2_ip] +#platform = espressif8266 +#board = nodemcuv2 +#framework = arduino +; We consider that the this projects is opened within its project directory +; while working with VS Code. +#lib_extra_dirs = ../../../ + +#lib_deps = +# WifiManager +# knx + +#build_flags = +# -DMASK_VERSION=0x57B0 +# -Wno-unknown-pragmas + +[env:nodemcuv2_tp] +platform = espressif8266 board = nodemcuv2 framework = arduino ; We consider that the this projects is opened within its project directory @@ -43,17 +59,17 @@ framework = arduino lib_extra_dirs = ../../../ lib_deps = - WifiManager@0.15.0 knx build_flags = + -DMASK_VERSION=0x07B0 -Wno-unknown-pragmas ;--------------------------------------------------------- ;--- ESP32 ----------------------------------------------- -[env:esp32dev] +[env:esp32dev_ip] platform = espressif32 board = esp32dev framework = arduino @@ -65,4 +81,20 @@ lib_deps = knx build_flags = + -DMASK_VERSION=0x57B0 + -Wno-unknown-pragmas + +[env:esp32dev_tp] +platform = espressif32 +board = esp32dev +framework = arduino +; We consider that the this projects is opened within its project directory +; while working with VS Code. +lib_extra_dirs = ../../../ + +lib_deps = + knx + +build_flags = + -DMASK_VERSION=0x07B0 -Wno-unknown-pragmas diff --git a/examples/knx-linux-coupler/CMakeLists.txt b/examples/knx-linux-coupler/CMakeLists.txt new file mode 100644 index 0000000..6fad30a --- /dev/null +++ b/examples/knx-linux-coupler/CMakeLists.txt @@ -0,0 +1,138 @@ +cmake_minimum_required(VERSION 2.7) +project(knx-linux-coupler) +set(LIBRARIES_FROM_REFERENCES "") +add_executable(knx-linux + ../../src/knx/address_table_object.cpp + ../../src/knx/address_table_object.h + ../../src/knx/aes.c + ../../src/knx/aes.h + ../../src/knx/aes.hpp + ../../src/knx/apdu.cpp + ../../src/knx/apdu.h + ../../src/knx/application_layer.cpp + ../../src/knx/application_layer.h + ../../src/knx/application_program_object.cpp + ../../src/knx/application_program_object.h + ../../src/knx/association_table_object.cpp + ../../src/knx/association_table_object.h + ../../src/knx/bau.cpp + ../../src/knx/bau.h + ../../src/knx/bau07B0.cpp + ../../src/knx/bau07B0.h + ../../src/knx/bau091A.cpp + ../../src/knx/bau091A.h + ../../src/knx/bau27B0.cpp + ../../src/knx/bau27B0.h + ../../src/knx/bau2920.cpp + ../../src/knx/bau2920.h + ../../src/knx/bau57B0.cpp + ../../src/knx/bau57B0.h + ../../src/knx/bau_systemB.cpp + ../../src/knx/bau_systemB.h + ../../src/knx/bau_systemB_device.cpp + ../../src/knx/bau_systemB_device.h + ../../src/knx/bau_systemB_coupler.cpp + ../../src/knx/bau_systemB_coupler.h + ../../src/knx/bits.cpp + ../../src/knx/bits.h + ../../src/knx/callback_property.h + ../../src/knx/cemi_frame.cpp + ../../src/knx/cemi_frame.h + ../../src/knx/cemi_server.cpp + ../../src/knx/cemi_server.h + ../../src/knx/cemi_server_object.cpp + ../../src/knx/cemi_server_object.h + ../../src/knx/config.h + ../../src/knx/data_link_layer.cpp + ../../src/knx/data_link_layer.h + ../../src/knx/data_property.cpp + ../../src/knx/data_property.h + ../../src/knx/device_object.cpp + ../../src/knx/device_object.h + ../../src/knx/dpt.cpp + ../../src/knx/dpt.h + ../../src/knx/dptconvert.cpp + ../../src/knx/dptconvert.h + ../../src/knx/function_property.h + ../../src/knx/group_object.cpp + ../../src/knx/group_object.h + ../../src/knx/group_object_table_object.cpp + ../../src/knx/group_object_table_object.h + ../../src/knx/interface_object.cpp + ../../src/knx/interface_object.h + ../../src/knx/ip_data_link_layer.cpp + ../../src/knx/ip_data_link_layer.h + ../../src/knx/ip_parameter_object.cpp + ../../src/knx/ip_parameter_object.h + ../../src/knx/knx_ip_device_information_dib.cpp + ../../src/knx/knx_ip_device_information_dib.h + ../../src/knx/knx_ip_dib.cpp + ../../src/knx/knx_ip_dib.h + ../../src/knx/knx_ip_frame.cpp + ../../src/knx/knx_ip_frame.h + ../../src/knx/knx_ip_routing_indication.cpp + ../../src/knx/knx_ip_routing_indication.h + ../../src/knx/knx_ip_search_request.cpp + ../../src/knx/knx_ip_search_request.h + ../../src/knx/knx_ip_search_response.cpp + ../../src/knx/knx_ip_search_response.h + ../../src/knx/knx_ip_supported_service_dib.cpp + ../../src/knx/knx_ip_supported_service_dib.h + ../../src/knx/ip_host_protocol_address_information.cpp + ../../src/knx/ip_host_protocol_address_information.h + ../../src/knx/knx_types.h + ../../src/knx/knx_value.cpp + ../../src/knx/knx_value.h + ../../src/knx/memory.cpp + ../../src/knx/memory.h + ../../src/knx/network_layer.cpp + ../../src/knx/network_layer.h + ../../src/knx/network_layer_coupler.cpp + ../../src/knx/network_layer_coupler.h + ../../src/knx/network_layer_device.cpp + ../../src/knx/network_layer_device.h + ../../src/knx/network_layer_entity.cpp + ../../src/knx/network_layer_entity.h + ../../src/knx/npdu.cpp + ../../src/knx/npdu.h + ../../src/knx/platform.cpp + ../../src/knx/platform.h + ../../src/knx/property.cpp + ../../src/knx/property.h + ../../src/knx/rf_data_link_layer.cpp + ../../src/knx/rf_data_link_layer.h + ../../src/knx/rf_medium_object.cpp + ../../src/knx/rf_medium_object.h + ../../src/knx/rf_physical_layer.cpp + ../../src/knx/rf_physical_layer.h + ../../src/knx/router_object.cpp + ../../src/knx/router_object.h + ../../src/knx/secure_application_layer.cpp + ../../src/knx/secure_application_layer.h + ../../src/knx/security_interface_object.cpp + ../../src/knx/security_interface_object.h + ../../src/knx/simple_map.h + ../../src/knx/save_restore.h + ../../src/knx/table_object.cpp + ../../src/knx/table_object.h + ../../src/knx/tpdu.cpp + ../../src/knx/tpdu.h + ../../src/knx/tpuart_data_link_layer.cpp + ../../src/knx/tpuart_data_link_layer.h + ../../src/knx/transport_layer.cpp + ../../src/knx/transport_layer.h + ../../src/knx/usb_tunnel_interface.cpp + ../../src/knx/usb_tunnel_interface.h + ../../src/knx_facade.cpp + ../../src/knx_facade.h + ../../src/linux_platform.cpp + ../../src/linux_platform.h + fdsk.cpp + fdsk.h + main.cpp) +target_link_libraries(knx-linux "${LIBRARIES_FROM_REFERENCES}") +include_directories(../../src) +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall -Wno-unknown-pragmas -g -O0") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wno-unknown-pragmas -g -O0") +set_property(TARGET knx-linux PROPERTY CXX_STANDARD 11) +add_definitions(-DMASK_VERSION=0x091A) diff --git a/examples/knx-linux-coupler/CMakeSettings.json b/examples/knx-linux-coupler/CMakeSettings.json new file mode 100644 index 0000000..22985a0 --- /dev/null +++ b/examples/knx-linux-coupler/CMakeSettings.json @@ -0,0 +1,19 @@ +{ + "configurations": [ + { + "name": "WSL-Debug", + "generator": "Unix Makefiles", + "configurationType": "Debug", + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeExecutable": "/usr/bin/cmake", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "inheritEnvironments": [ "linux_x64" ], + "wslPath": "${defaultWSLPath}", + "addressSanitizerRuntimeFlags": "detect_leaks=0", + "variables": [] + } + ] +} \ No newline at end of file diff --git a/examples/knx-linux-coupler/fdsk.cpp b/examples/knx-linux-coupler/fdsk.cpp new file mode 100644 index 0000000..8d9b28c --- /dev/null +++ b/examples/knx-linux-coupler/fdsk.cpp @@ -0,0 +1,196 @@ +#include "fdsk.h" + +#include + +// CRC-4 generator polynom: 10011 (x^4+x+1) +const uint8_t FdskCalculator::crc4_tab[16] = +{ + 0x0, 0x3, 0x6, 0x5, 0xc, 0xf, 0xa, 0x9, + 0xb, 0x8, 0xd, 0xe, 0x7, 0x4, 0x1, 0x2 +}; + +int FdskCalculator::snprintFdsk(char* str, int strSize, uint8_t* serialNumber, uint8_t* key) +{ + char* tmpStr = generateFdskString(serialNumber, key); + int written = 0; + + for (int i = 0; i < 36; i++) + { + if (((i % 6) == 0) && (i!=0)) + { + *(str+written++) = '-'; + if (written >= strSize-1) + break; + } + *(str+written++) = tmpStr[i]; + if (written >= strSize-1) + break; + } + + *(str+written++) = '\0'; + + delete[] tmpStr; + + return written; +} + +char* FdskCalculator::generateFdskString(uint8_t* serialNumber, uint8_t* key) +{ + uint8_t buffer[6 + 16 + 1]; // 6 bytes serialnumber + 16 bytes key + 1 byte placeholder for crc-4 + memcpy(&buffer[0], serialNumber, 6); + memcpy(&buffer[6], key, 16); + buffer[22] = (crc4Array(buffer, sizeof(buffer)-1)<<4) &0xFF; + + uint8_t* outEncoded = nullptr; + toBase32(buffer, sizeof(buffer), outEncoded, false); + + return (char*)outEncoded; +} + +int FdskCalculator::ceil(float num) +{ + int inum = (int)num; + if (num == (float)inum) { + return inum; + } + return inum + 1; +} + +int FdskCalculator::toBase32(uint8_t* in, long length, uint8_t*& out, bool usePadding) +{ + char base32StandardAlphabet[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"}; + char standardPaddingChar = '='; + + int result = 0; + int count = 0; + int bufSize = 8; + int index = 0; + int size = 0; // size of temporary array + uint8_t* temp = nullptr; + + if (length < 0 || length > 268435456LL) + { + return 0; + } + + size = 8 * ceil(length / 4.0); // Calculating size of temporary array. Not very precise. + temp = new uint8_t[size]; + + if (length > 0) + { + int buffer = in[0]; + int next = 1; + int bitsLeft = 8; + + while (count < bufSize && (bitsLeft > 0 || next < length)) + { + if (bitsLeft < 5) + { + if (next < length) + { + buffer <<= 8; + buffer |= in[next] & 0xFF; + next++; + bitsLeft += 8; + } + else + { + int pad = 5 - bitsLeft; + buffer <<= pad; + bitsLeft += pad; + } + } + index = 0x1F & (buffer >> (bitsLeft -5)); + + bitsLeft -= 5; + temp[result] = (uint8_t)base32StandardAlphabet[index]; + result++; + } + } + + if (usePadding) + { + int pads = (result % 8); + if (pads > 0) + { + pads = (8 - pads); + for (int i = 0; i < pads; i++) + { + temp[result] = standardPaddingChar; + result++; + } + } + } + + out = new uint8_t[result]; + + memcpy(out, temp, result); + delete [] temp; + + return result; +} + +int FdskCalculator::fromBase32(uint8_t* in, long length, uint8_t*& out) +{ + int result = 0; // Length of the array of decoded values. + int buffer = 0; + int bitsLeft = 0; + uint8_t* temp = NULL; + + temp = new uint8_t[length]; // Allocating temporary array. + + for (int i = 0; i < length; i++) + { + uint8_t ch = in[i]; + + // ignoring some characters: ' ', '\t', '\r', '\n', '=' + if (ch == 0xA0 || ch == 0x09 || ch == 0x0A || ch == 0x0D || ch == 0x3D) + continue; + + // recovering mistyped: '0' -> 'O', '1' -> 'L', '8' -> 'B' + if (ch == 0x30) + { + ch = 0x4F; + } + else if (ch == 0x31) + { + ch = 0x4C; + } + else if (ch == 0x38) + { + ch = 0x42; + } + + + // look up one base32 symbols: from 'A' to 'Z' or from 'a' to 'z' or from '2' to '7' + if ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A)) + { + ch = ((ch & 0x1F) - 1); + } + else if (ch >= 0x32 && ch <= 0x37) + { + ch -= (0x32 - 26); + } + else { + delete [] temp; + return 0; + } + + buffer <<= 5; + buffer |= ch; + bitsLeft += 5; + if (bitsLeft >= 8) + { + temp[result] = (unsigned char)((unsigned int)(buffer >> (bitsLeft - 8)) & 0xFF); + result++; + bitsLeft -= 8; + } + } + + out = new uint8_t[result]; + memcpy(out, temp, result); + delete [] temp; + + return result; +} + diff --git a/examples/knx-linux-coupler/fdsk.h b/examples/knx-linux-coupler/fdsk.h new file mode 100644 index 0000000..560ba22 --- /dev/null +++ b/examples/knx-linux-coupler/fdsk.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +class FdskCalculator +{ + public: + int snprintFdsk(char* str, int strSize, uint8_t* serialNumber, uint8_t* key); + + private: + char* generateFdskString(uint8_t* serialNumber, uint8_t* key); + + int toBase32(uint8_t* in, long length, uint8_t*& out, bool usePadding); + int fromBase32(uint8_t* in, long length, uint8_t*& out); + + uint8_t crc4Array(uint8_t* data, uint8_t len) { + uint8_t start = 0; + for (uint8_t i = 0; i > 4; + c = crc4_tab[c ^ high4Bits]; + c = crc4_tab[c ^ low4Bits]; + + return c; + } + + int ceil(float num); + + static const uint8_t crc4_tab[16]; +}; diff --git a/examples/knx-linux-coupler/gcc_Debug.h b/examples/knx-linux-coupler/gcc_Debug.h new file mode 100644 index 0000000..e4f1569 --- /dev/null +++ b/examples/knx-linux-coupler/gcc_Debug.h @@ -0,0 +1,889 @@ +/* + This file is only used by IntelliSense (VisualStudio code suggestion system) + DO NOT INCLUDE THIS FILE FROM YOUR ACTUAL SOURCE FILES. + This file lists the preprocessor macros extracted from your GCC. + It is needed for IntelliSense to parse other header files correctly. +*/ +#if defined(_MSC_VER) || defined (__SYSPROGS_CODESENSE__) +#pragma clang diagnostic push + +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#ifndef __DBL_MIN_EXP__ +#define __DBL_MIN_EXP__ (-1021) +#endif +#ifndef __cpp_attributes +#define __cpp_attributes 200809 +#endif +#ifndef __UINT_LEAST16_MAX__ +#define __UINT_LEAST16_MAX__ 0xffff +#endif +#ifndef __ATOMIC_ACQUIRE +#define __ATOMIC_ACQUIRE 2 +#endif +#ifndef __FLT_MIN__ +#define __FLT_MIN__ 1.17549435082228750797e-38F +#endif +#ifndef __GCC_IEC_559_COMPLEX +#define __GCC_IEC_559_COMPLEX 2 +#endif +#ifndef __cpp_aggregate_nsdmi +#define __cpp_aggregate_nsdmi 201304 +#endif +#ifndef __UINT_LEAST8_TYPE__ +#define __UINT_LEAST8_TYPE__ unsigned char +#endif +#ifndef __SIZEOF_FLOAT80__ +#define __SIZEOF_FLOAT80__ 16 +#endif +#ifndef __CHAR_BIT__ +#define __CHAR_BIT__ 8 +#endif +#ifndef __UINT8_MAX__ +#define __UINT8_MAX__ 0xff +#endif +#ifndef __WINT_MAX__ +#define __WINT_MAX__ 0xffffffffU +#endif +#ifndef __cpp_static_assert +#define __cpp_static_assert 200410 +#endif +#ifndef __ORDER_LITTLE_ENDIAN__ +#define __ORDER_LITTLE_ENDIAN__ 1234 +#endif +#ifndef __SIZE_MAX__ +#define __SIZE_MAX__ 0xffffffffffffffffUL +#endif +#ifndef __WCHAR_MAX__ +#define __WCHAR_MAX__ 0x7fffffff +#endif +#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 +#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1 +#endif +#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 +#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1 +#endif +#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 +#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1 +#endif +#ifndef __DBL_DENORM_MIN__ +#define __DBL_DENORM_MIN__ double(4.94065645841246544177e-324L) +#endif +#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 +#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1 +#endif +#ifndef __GCC_ATOMIC_CHAR_LOCK_FREE +#define __GCC_ATOMIC_CHAR_LOCK_FREE 2 +#endif +#ifndef __GCC_IEC_559 +#define __GCC_IEC_559 2 +#endif +#ifndef __FLT_EVAL_METHOD__ +#define __FLT_EVAL_METHOD__ 0 +#endif +#ifndef __unix__ +#define __unix__ 1 +#endif +#ifndef __cpp_binary_literals +#define __cpp_binary_literals 201304 +#endif +#ifndef __GCC_ATOMIC_CHAR32_T_LOCK_FREE +#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2 +#endif +#ifndef __x86_64 +#define __x86_64 1 +#endif +#ifndef __cpp_variadic_templates +#define __cpp_variadic_templates 200704 +#endif +#ifndef __UINT_FAST64_MAX__ +#define __UINT_FAST64_MAX__ 0xffffffffffffffffUL +#endif +#ifndef __SIG_ATOMIC_TYPE__ +#define __SIG_ATOMIC_TYPE__ int +#endif +#ifndef __DBL_MIN_10_EXP__ +#define __DBL_MIN_10_EXP__ (-307) +#endif +#ifndef __FINITE_MATH_ONLY__ +#define __FINITE_MATH_ONLY__ 0 +#endif +#ifndef __cpp_variable_templates +#define __cpp_variable_templates 201304 +#endif +#ifndef __GNUC_PATCHLEVEL__ +#define __GNUC_PATCHLEVEL__ 0 +#endif +#ifndef __UINT_FAST8_MAX__ +#define __UINT_FAST8_MAX__ 0xff +#endif +#ifndef __DEC64_MAX_EXP__ +#define __DEC64_MAX_EXP__ 385 +#endif +#ifndef __UINT_LEAST64_MAX__ +#define __UINT_LEAST64_MAX__ 0xffffffffffffffffUL +#endif +#ifndef __SHRT_MAX__ +#define __SHRT_MAX__ 0x7fff +#endif +#ifndef __LDBL_MAX__ +#define __LDBL_MAX__ 1.18973149535723176502e+4932L +#endif +#ifndef __UINT_LEAST8_MAX__ +#define __UINT_LEAST8_MAX__ 0xff +#endif +#ifndef __GCC_ATOMIC_BOOL_LOCK_FREE +#define __GCC_ATOMIC_BOOL_LOCK_FREE 2 +#endif +#ifndef __UINTMAX_TYPE__ +#define __UINTMAX_TYPE__ long unsigned int +#endif +#ifndef __linux +#define __linux 1 +#endif +#ifndef __DEC32_EPSILON__ +#define __DEC32_EPSILON__ 1E-6DF +#endif +#ifndef __unix +#define __unix 1 +#endif +#ifndef __UINT32_MAX__ +#define __UINT32_MAX__ 0xffffffffU +#endif +#if !defined(__GXX_EXPERIMENTAL_CXX0X__) && defined(__SYSPROGS_CODESENSE__) +#define __GXX_EXPERIMENTAL_CXX0X__ 1 +#endif +#ifndef __LDBL_MAX_EXP__ +#define __LDBL_MAX_EXP__ 16384 +#endif +#ifndef __WINT_MIN__ +#define __WINT_MIN__ 0U +#endif +#ifndef __linux__ +#define __linux__ 1 +#endif +#ifndef __SCHAR_MAX__ +#define __SCHAR_MAX__ 0x7f +#endif +#ifndef __WCHAR_MIN__ +#define __WCHAR_MIN__ (-__WCHAR_MAX__ - 1) +#endif +#ifndef __DBL_DIG__ +#define __DBL_DIG__ 15 +#endif +#ifndef __GCC_ATOMIC_POINTER_LOCK_FREE +#define __GCC_ATOMIC_POINTER_LOCK_FREE 2 +#endif +#ifndef __SIZEOF_INT__ +#define __SIZEOF_INT__ 4 +#endif +#ifndef __SIZEOF_POINTER__ +#define __SIZEOF_POINTER__ 8 +#endif +#ifndef __GCC_ATOMIC_CHAR16_T_LOCK_FREE +#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2 +#endif +#ifndef __USER_LABEL_PREFIX__ +#define __USER_LABEL_PREFIX__ +#endif +#ifndef __STDC_HOSTED__ +#define __STDC_HOSTED__ 1 +#endif +#ifndef __LDBL_HAS_INFINITY__ +#define __LDBL_HAS_INFINITY__ 1 +#endif +#ifndef __FLT_EPSILON__ +#define __FLT_EPSILON__ 1.19209289550781250000e-7F +#endif +#ifndef __GXX_WEAK__ +#define __GXX_WEAK__ 1 +#endif +#ifndef __LDBL_MIN__ +#define __LDBL_MIN__ 3.36210314311209350626e-4932L +#endif +#ifndef __DEC32_MAX__ +#define __DEC32_MAX__ 9.999999E96DF +#endif +#ifndef __INT32_MAX__ +#define __INT32_MAX__ 0x7fffffff +#endif +#ifndef __SIZEOF_LONG__ +#define __SIZEOF_LONG__ 8 +#endif +#ifndef __STDC_IEC_559__ +#define __STDC_IEC_559__ 1 +#endif +#ifndef __STDC_ISO_10646__ +#define __STDC_ISO_10646__ 201605L +#endif +#ifndef __DECIMAL_DIG__ +#define __DECIMAL_DIG__ 21 +#endif +#ifndef __gnu_linux__ +#define __gnu_linux__ 1 +#endif +#ifndef __LDBL_HAS_QUIET_NAN__ +#define __LDBL_HAS_QUIET_NAN__ 1 +#endif +#ifndef __GNUC__ +#define __GNUC__ 6 +#endif +#ifndef __GXX_RTTI +#define __GXX_RTTI 1 +#endif +#ifndef __pie__ +#define __pie__ 2 +#endif +#ifndef __MMX__ +#define __MMX__ 1 +#endif +#ifndef __cpp_delegating_constructors +#define __cpp_delegating_constructors 200604 +#endif +#ifndef __FLT_HAS_DENORM__ +#define __FLT_HAS_DENORM__ 1 +#endif +#ifndef __SIZEOF_LONG_DOUBLE__ +#define __SIZEOF_LONG_DOUBLE__ 16 +#endif +#ifndef __BIGGEST_ALIGNMENT__ +#define __BIGGEST_ALIGNMENT__ 16 +#endif +#ifndef __STDC_UTF_16__ +#define __STDC_UTF_16__ 1 +#endif +#ifndef __DBL_MAX__ +#define __DBL_MAX__ double(1.79769313486231570815e+308L) +#endif +#ifndef __cpp_raw_strings +#define __cpp_raw_strings 200710 +#endif +#ifndef __INT_FAST32_MAX__ +#define __INT_FAST32_MAX__ 0x7fffffffffffffffL +#endif +#ifndef __DBL_HAS_INFINITY__ +#define __DBL_HAS_INFINITY__ 1 +#endif +#ifndef __INT64_MAX__ +#define __INT64_MAX__ 0x7fffffffffffffffL +#endif +#ifndef __DEC32_MIN_EXP__ +#define __DEC32_MIN_EXP__ (-94) +#endif +#ifndef __INT_FAST16_TYPE__ +#define __INT_FAST16_TYPE__ long int +#endif +#ifndef __LDBL_HAS_DENORM__ +#define __LDBL_HAS_DENORM__ 1 +#endif +//VS2005-2012 treats all files as C++, while VS2013+ can treat C files correctly. +#if defined(_MSC_VER) && (_MSC_VER < 1800 || defined(__cplusplus)) +#undef __cplusplus +#define __cplusplus 201402L +#endif +#ifndef __cpp_ref_qualifiers +#define __cpp_ref_qualifiers 200710 +#endif +#ifndef __DEC128_MAX__ +#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL +#endif +#ifndef __INT_LEAST32_MAX__ +#define __INT_LEAST32_MAX__ 0x7fffffff +#endif +#ifndef __DEC32_MIN__ +#define __DEC32_MIN__ 1E-95DF +#endif +#ifndef __DEPRECATED +#define __DEPRECATED 1 +#endif +#ifndef __cpp_rvalue_references +#define __cpp_rvalue_references 200610 +#endif +#ifndef __DBL_MAX_EXP__ +#define __DBL_MAX_EXP__ 1024 +#endif +#ifndef __DEC128_EPSILON__ +#define __DEC128_EPSILON__ 1E-33DL +#endif +#ifndef __SSE2_MATH__ +#define __SSE2_MATH__ 1 +#endif +#ifndef __ATOMIC_HLE_RELEASE +#define __ATOMIC_HLE_RELEASE 131072 +#endif +#ifndef __PTRDIFF_MAX__ +#define __PTRDIFF_MAX__ 0x7fffffffffffffffL +#endif +#ifndef __amd64 +#define __amd64 1 +#endif +#ifndef __STDC_NO_THREADS__ +#define __STDC_NO_THREADS__ 1 +#endif +#ifndef __ATOMIC_HLE_ACQUIRE +#define __ATOMIC_HLE_ACQUIRE 65536 +#endif +#ifndef __GNUG__ +#define __GNUG__ 6 +#endif +#ifndef __LONG_LONG_MAX__ +#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL +#endif +#ifndef __SIZEOF_SIZE_T__ +#define __SIZEOF_SIZE_T__ 8 +#endif +#ifndef __cpp_rvalue_reference +#define __cpp_rvalue_reference 200610 +#endif +#ifndef __cpp_nsdmi +#define __cpp_nsdmi 200809 +#endif +#ifndef __SIZEOF_WINT_T__ +#define __SIZEOF_WINT_T__ 4 +#endif +#ifndef __cpp_initializer_lists +#define __cpp_initializer_lists 200806 +#endif +#ifndef __cpp_hex_float +#define __cpp_hex_float 201603 +#endif +#ifndef __GCC_HAVE_DWARF2_CFI_ASM +#define __GCC_HAVE_DWARF2_CFI_ASM 1 +#endif +#ifndef __GXX_ABI_VERSION +#define __GXX_ABI_VERSION 1010 +#endif +#ifndef __FLT_MIN_EXP__ +#define __FLT_MIN_EXP__ (-125) +#endif +#ifndef __cpp_lambdas +#define __cpp_lambdas 200907 +#endif +#ifndef __INT_FAST64_TYPE__ +#define __INT_FAST64_TYPE__ long int +#endif +#ifndef __DBL_MIN__ +#define __DBL_MIN__ double(2.22507385850720138309e-308L) +#endif +#ifndef __PIE__ +#define __PIE__ 2 +#endif +#ifndef __LP64__ +#define __LP64__ 1 +#endif +#ifndef __DECIMAL_BID_FORMAT__ +#define __DECIMAL_BID_FORMAT__ 1 +#endif +#ifndef __DEC128_MIN__ +#define __DEC128_MIN__ 1E-6143DL +#endif +#ifndef __REGISTER_PREFIX__ +#define __REGISTER_PREFIX__ +#endif +#ifndef __UINT16_MAX__ +#define __UINT16_MAX__ 0xffff +#endif +#ifndef __DBL_HAS_DENORM__ +#define __DBL_HAS_DENORM__ 1 +#endif +#ifndef __UINT8_TYPE__ +#define __UINT8_TYPE__ unsigned char +#endif +#ifndef __NO_INLINE__ +#define __NO_INLINE__ 1 +#endif +#ifndef __FLT_MANT_DIG__ +#define __FLT_MANT_DIG__ 24 +#endif +#ifndef __VERSION__ +#define __VERSION__ "6.3.0 20170516" +#endif +#ifndef __cpp_unicode_characters +#define __cpp_unicode_characters 200704 +#endif +#ifndef _STDC_PREDEF_H +#define _STDC_PREDEF_H 1 +#endif +#ifndef __cpp_decltype_auto +#define __cpp_decltype_auto 201304 +#endif +#ifndef __GCC_ATOMIC_INT_LOCK_FREE +#define __GCC_ATOMIC_INT_LOCK_FREE 2 +#endif +#ifndef __FLOAT_WORD_ORDER__ +#define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__ +#endif +#ifndef __STDC_IEC_559_COMPLEX__ +#define __STDC_IEC_559_COMPLEX__ 1 +#endif +#ifndef __DEC64_EPSILON__ +#define __DEC64_EPSILON__ 1E-15DD +#endif +#ifndef __ORDER_PDP_ENDIAN__ +#define __ORDER_PDP_ENDIAN__ 3412 +#endif +#ifndef __DEC128_MIN_EXP__ +#define __DEC128_MIN_EXP__ (-6142) +#endif +#ifndef __INT_FAST32_TYPE__ +#define __INT_FAST32_TYPE__ long int +#endif +#ifndef __UINT_LEAST16_TYPE__ +#define __UINT_LEAST16_TYPE__ short unsigned int +#endif +#ifndef unix +#define unix 1 +#endif +#ifndef __INT16_MAX__ +#define __INT16_MAX__ 0x7fff +#endif +#ifndef __cpp_rtti +#define __cpp_rtti 199711 +#endif +#ifndef __SIZE_TYPE__ +#define __SIZE_TYPE__ long unsigned int +#endif +#ifndef __UINT64_MAX__ +#define __UINT64_MAX__ 0xffffffffffffffffUL +#endif +#ifndef __INT8_TYPE__ +#define __INT8_TYPE__ signed char +#endif +#ifndef __cpp_digit_separators +#define __cpp_digit_separators 201309 +#endif +#ifndef __ELF__ +#define __ELF__ 1 +#endif +#ifndef __GCC_ASM_FLAG_OUTPUTS__ +#define __GCC_ASM_FLAG_OUTPUTS__ 1 +#endif +#ifndef __FLT_RADIX__ +#define __FLT_RADIX__ 2 +#endif +#ifndef __INT_LEAST16_TYPE__ +#define __INT_LEAST16_TYPE__ short int +#endif +#ifndef __LDBL_EPSILON__ +#define __LDBL_EPSILON__ 1.08420217248550443401e-19L +#endif +#ifndef __GLIBCXX_BITSIZE_INT_N_0 +#define __GLIBCXX_BITSIZE_INT_N_0 128 +#endif +#ifndef __k8 +#define __k8 1 +#endif +#ifndef __SIG_ATOMIC_MAX__ +#define __SIG_ATOMIC_MAX__ 0x7fffffff +#endif +#ifndef __GCC_ATOMIC_WCHAR_T_LOCK_FREE +#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2 +#endif +#ifndef __cpp_sized_deallocation +#define __cpp_sized_deallocation 201309 +#endif +#ifndef __SIZEOF_PTRDIFF_T__ +#define __SIZEOF_PTRDIFF_T__ 8 +#endif +#ifndef __x86_64__ +#define __x86_64__ 1 +#endif +#ifndef __DEC32_SUBNORMAL_MIN__ +#define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF +#endif +#ifndef __INT_FAST16_MAX__ +#define __INT_FAST16_MAX__ 0x7fffffffffffffffL +#endif +#ifndef __UINT_FAST32_MAX__ +#define __UINT_FAST32_MAX__ 0xffffffffffffffffUL +#endif +#ifndef __UINT_LEAST64_TYPE__ +#define __UINT_LEAST64_TYPE__ long unsigned int +#endif +#ifndef __FLT_HAS_QUIET_NAN__ +#define __FLT_HAS_QUIET_NAN__ 1 +#endif +#ifndef __FLT_MAX_10_EXP__ +#define __FLT_MAX_10_EXP__ 38 +#endif +#ifndef __LONG_MAX__ +#define __LONG_MAX__ 0x7fffffffffffffffL +#endif +#ifndef __DEC128_SUBNORMAL_MIN__ +#define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL +#endif +#ifndef __FLT_HAS_INFINITY__ +#define __FLT_HAS_INFINITY__ 1 +#endif +#ifndef __cpp_unicode_literals +#define __cpp_unicode_literals 200710 +#endif +#ifndef __UINT_FAST16_TYPE__ +#define __UINT_FAST16_TYPE__ long unsigned int +#endif +#ifndef __DEC64_MAX__ +#define __DEC64_MAX__ 9.999999999999999E384DD +#endif +#ifndef __CHAR16_TYPE__ +#define __CHAR16_TYPE__ short unsigned int +#endif +#ifndef __PRAGMA_REDEFINE_EXTNAME +#define __PRAGMA_REDEFINE_EXTNAME 1 +#endif +#ifndef __SEG_FS +#define __SEG_FS 1 +#endif +#ifndef __INT_LEAST16_MAX__ +#define __INT_LEAST16_MAX__ 0x7fff +#endif +#ifndef __DEC64_MANT_DIG__ +#define __DEC64_MANT_DIG__ 16 +#endif +#ifndef __UINT_LEAST32_MAX__ +#define __UINT_LEAST32_MAX__ 0xffffffffU +#endif +#ifndef __SEG_GS +#define __SEG_GS 1 +#endif +#ifndef __GCC_ATOMIC_LONG_LOCK_FREE +#define __GCC_ATOMIC_LONG_LOCK_FREE 2 +#endif +#ifndef __INT_LEAST64_TYPE__ +#define __INT_LEAST64_TYPE__ long int +#endif +#ifndef __INT16_TYPE__ +#define __INT16_TYPE__ short int +#endif +#ifndef __INT_LEAST8_TYPE__ +#define __INT_LEAST8_TYPE__ signed char +#endif +#ifndef __DEC32_MAX_EXP__ +#define __DEC32_MAX_EXP__ 97 +#endif +#ifndef __INT_FAST8_MAX__ +#define __INT_FAST8_MAX__ 0x7f +#endif +#ifndef __INTPTR_MAX__ +#define __INTPTR_MAX__ 0x7fffffffffffffffL +#endif +#ifndef linux +#define linux 1 +#endif +#ifndef __cpp_range_based_for +#define __cpp_range_based_for 200907 +#endif +#ifndef __SSE2__ +#define __SSE2__ 1 +#endif +#ifndef __EXCEPTIONS +#define __EXCEPTIONS 1 +#endif +#ifndef __LDBL_MANT_DIG__ +#define __LDBL_MANT_DIG__ 64 +#endif +#ifndef __DBL_HAS_QUIET_NAN__ +#define __DBL_HAS_QUIET_NAN__ 1 +#endif +#ifndef __SIG_ATOMIC_MIN__ +#define __SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1) +#endif +#ifndef __code_model_small__ +#define __code_model_small__ 1 +#endif +#ifndef __cpp_return_type_deduction +#define __cpp_return_type_deduction 201304 +#endif +#ifndef __k8__ +#define __k8__ 1 +#endif +#ifndef __INTPTR_TYPE__ +#define __INTPTR_TYPE__ long int +#endif +#ifndef __UINT16_TYPE__ +#define __UINT16_TYPE__ short unsigned int +#endif +#ifndef __WCHAR_TYPE__ +#define __WCHAR_TYPE__ int +#endif +#ifndef __SIZEOF_FLOAT__ +#define __SIZEOF_FLOAT__ 4 +#endif +#ifndef __pic__ +#define __pic__ 2 +#endif +#ifndef __UINTPTR_MAX__ +#define __UINTPTR_MAX__ 0xffffffffffffffffUL +#endif +#ifndef __DEC64_MIN_EXP__ +#define __DEC64_MIN_EXP__ (-382) +#endif +#ifndef __cpp_decltype +#define __cpp_decltype 200707 +#endif +#ifndef __INT_FAST64_MAX__ +#define __INT_FAST64_MAX__ 0x7fffffffffffffffL +#endif +#ifndef __GCC_ATOMIC_TEST_AND_SET_TRUEVAL +#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1 +#endif +#ifndef __FLT_DIG__ +#define __FLT_DIG__ 6 +#endif +#ifndef __UINT_FAST64_TYPE__ +#define __UINT_FAST64_TYPE__ long unsigned int +#endif +#ifndef __INT_MAX__ +#define __INT_MAX__ 0x7fffffff +#endif +#ifndef __amd64__ +#define __amd64__ 1 +#endif +#ifndef __INT64_TYPE__ +#define __INT64_TYPE__ long int +#endif +#ifndef __FLT_MAX_EXP__ +#define __FLT_MAX_EXP__ 128 +#endif +#ifndef __ORDER_BIG_ENDIAN__ +#define __ORDER_BIG_ENDIAN__ 4321 +#endif +#ifndef __DBL_MANT_DIG__ +#define __DBL_MANT_DIG__ 53 +#endif +#ifndef __cpp_inheriting_constructors +#define __cpp_inheriting_constructors 200802 +#endif +#ifndef __SIZEOF_FLOAT128__ +#define __SIZEOF_FLOAT128__ 16 +#endif +#ifndef __INT_LEAST64_MAX__ +#define __INT_LEAST64_MAX__ 0x7fffffffffffffffL +#endif +#ifndef __DEC64_MIN__ +#define __DEC64_MIN__ 1E-383DD +#endif +#ifndef __WINT_TYPE__ +#define __WINT_TYPE__ unsigned int +#endif +#ifndef __UINT_LEAST32_TYPE__ +#define __UINT_LEAST32_TYPE__ unsigned int +#endif +#ifndef __SIZEOF_SHORT__ +#define __SIZEOF_SHORT__ 2 +#endif +#ifndef __SSE__ +#define __SSE__ 1 +#endif +#ifndef __LDBL_MIN_EXP__ +#define __LDBL_MIN_EXP__ (-16381) +#endif +#ifndef __INT_LEAST8_MAX__ +#define __INT_LEAST8_MAX__ 0x7f +#endif +#ifndef __SIZEOF_INT128__ +#define __SIZEOF_INT128__ 16 +#endif +#ifndef __LDBL_MAX_10_EXP__ +#define __LDBL_MAX_10_EXP__ 4932 +#endif +#ifndef __ATOMIC_RELAXED +#define __ATOMIC_RELAXED 0 +#endif +#ifndef __DBL_EPSILON__ +#define __DBL_EPSILON__ double(2.22044604925031308085e-16L) +#endif +#ifndef _LP64 +#define _LP64 1 +#endif +#ifndef __INT_LEAST32_TYPE__ +#define __INT_LEAST32_TYPE__ int +#endif +#ifndef __SIZEOF_WCHAR_T__ +#define __SIZEOF_WCHAR_T__ 4 +#endif +#ifndef __UINT64_TYPE__ +#define __UINT64_TYPE__ long unsigned int +#endif +#ifndef __INT_FAST8_TYPE__ +#define __INT_FAST8_TYPE__ signed char +#endif +#ifndef __GNUC_STDC_INLINE__ +#define __GNUC_STDC_INLINE__ 1 +#endif +#ifndef __DBL_DECIMAL_DIG__ +#define __DBL_DECIMAL_DIG__ 17 +#endif +#ifndef __STDC_UTF_32__ +#define __STDC_UTF_32__ 1 +#endif +#ifndef __FXSR__ +#define __FXSR__ 1 +#endif +#ifndef __DEC_EVAL_METHOD__ +#define __DEC_EVAL_METHOD__ 2 +#endif +#ifndef __cpp_runtime_arrays +#define __cpp_runtime_arrays 198712 +#endif +#ifndef __INTMAX_MAX__ +#define __INTMAX_MAX__ 0x7fffffffffffffffL +#endif +#ifndef __cpp_alias_templates +#define __cpp_alias_templates 200704 +#endif +#ifndef __BYTE_ORDER__ +#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ +#endif +#ifndef __FLT_DENORM_MIN__ +#define __FLT_DENORM_MIN__ 1.40129846432481707092e-45F +#endif +#ifndef __INT8_MAX__ +#define __INT8_MAX__ 0x7f +#endif +#ifndef __PIC__ +#define __PIC__ 2 +#endif +#ifndef __UINT_FAST32_TYPE__ +#define __UINT_FAST32_TYPE__ long unsigned int +#endif +#ifndef __CHAR32_TYPE__ +#define __CHAR32_TYPE__ unsigned int +#endif +#ifndef __FLT_MAX__ +#define __FLT_MAX__ 3.40282346638528859812e+38F +#endif +#ifndef __cpp_constexpr +#define __cpp_constexpr 201304 +#endif +#ifndef __INT32_TYPE__ +#define __INT32_TYPE__ int +#endif +#ifndef __SIZEOF_DOUBLE__ +#define __SIZEOF_DOUBLE__ 8 +#endif +#ifndef __cpp_exceptions +#define __cpp_exceptions 199711 +#endif +#ifndef __INTMAX_TYPE__ +#define __INTMAX_TYPE__ long int +#endif +#ifndef __DEC128_MAX_EXP__ +#define __DEC128_MAX_EXP__ 6145 +#endif +#ifndef __ATOMIC_CONSUME +#define __ATOMIC_CONSUME 1 +#endif +#ifndef __GNUC_MINOR__ +#define __GNUC_MINOR__ 3 +#endif +#ifndef __GLIBCXX_TYPE_INT_N_0 +#define __GLIBCXX_TYPE_INT_N_0 __int128 +#endif +#ifndef __UINTMAX_MAX__ +#define __UINTMAX_MAX__ 0xffffffffffffffffUL +#endif +#ifndef __DEC32_MANT_DIG__ +#define __DEC32_MANT_DIG__ 7 +#endif +#ifndef __DBL_MAX_10_EXP__ +#define __DBL_MAX_10_EXP__ 308 +#endif +#ifndef __LDBL_DENORM_MIN__ +#define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L +#endif +#ifndef __cpp_generic_lambdas +#define __cpp_generic_lambdas 201304 +#endif +#ifndef __STDC__ +#define __STDC__ 1 +#endif +#ifndef __PTRDIFF_TYPE__ +#define __PTRDIFF_TYPE__ long int +#endif +#ifndef __ATOMIC_SEQ_CST +#define __ATOMIC_SEQ_CST 5 +#endif +#ifndef __UINT32_TYPE__ +#define __UINT32_TYPE__ unsigned int +#endif +#ifndef __UINTPTR_TYPE__ +#define __UINTPTR_TYPE__ long unsigned int +#endif +#ifndef __DEC64_SUBNORMAL_MIN__ +#define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD +#endif +#ifndef __DEC128_MANT_DIG__ +#define __DEC128_MANT_DIG__ 34 +#endif +#ifndef __LDBL_MIN_10_EXP__ +#define __LDBL_MIN_10_EXP__ (-4931) +#endif +#ifndef __SSE_MATH__ +#define __SSE_MATH__ 1 +#endif +#ifndef __SIZEOF_LONG_LONG__ +#define __SIZEOF_LONG_LONG__ 8 +#endif +#ifndef __cpp_user_defined_literals +#define __cpp_user_defined_literals 200809 +#endif +#ifndef __GCC_ATOMIC_LLONG_LOCK_FREE +#define __GCC_ATOMIC_LLONG_LOCK_FREE 2 +#endif +#ifndef __LDBL_DIG__ +#define __LDBL_DIG__ 18 +#endif +#ifndef __FLT_DECIMAL_DIG__ +#define __FLT_DECIMAL_DIG__ 9 +#endif +#ifndef __UINT_FAST16_MAX__ +#define __UINT_FAST16_MAX__ 0xffffffffffffffffUL +#endif +#ifndef __FLT_MIN_10_EXP__ +#define __FLT_MIN_10_EXP__ (-37) +#endif +#ifndef __GCC_ATOMIC_SHORT_LOCK_FREE +#define __GCC_ATOMIC_SHORT_LOCK_FREE 2 +#endif +#ifndef __UINT_FAST8_TYPE__ +#define __UINT_FAST8_TYPE__ unsigned char +#endif +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif +#ifndef __cpp_init_captures +#define __cpp_init_captures 201304 +#endif +#ifndef __ATOMIC_ACQ_REL +#define __ATOMIC_ACQ_REL 4 +#endif +#ifndef __ATOMIC_RELEASE +#define __ATOMIC_RELEASE 3 +#endif +#endif + +// --- Include directories begin --- // +///usr/include/c++/6 +///usr/include/x86_64-linux-gnu/c++/6 +///usr/include/c++/6/backward +///usr/lib/gcc/x86_64-linux-gnu/6/include +///usr/local/include +///usr/lib/gcc/x86_64-linux-gnu/6/include-fixed +///usr/include/x86_64-linux-gnu +///usr/include +// --- Include directories end --- // + + +// --- Library directories begin --- // +///usr/lib/gcc/x86_64-linux-gnu/6/ +///usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/ +///usr/lib/gcc/x86_64-linux-gnu/6/../../../../lib/ +///lib/x86_64-linux-gnu/ +///lib/../lib/ +///usr/lib/x86_64-linux-gnu/ +///usr/lib/../lib/ +///usr/lib/gcc/x86_64-linux-gnu/6/../../../ +///lib/ +///usr/lib/ +// --- Library directories begin --- // + +#pragma clang diagnostic pop diff --git a/examples/knx-linux-coupler/gcc_Release.h b/examples/knx-linux-coupler/gcc_Release.h new file mode 100644 index 0000000..5f82ca2 --- /dev/null +++ b/examples/knx-linux-coupler/gcc_Release.h @@ -0,0 +1,895 @@ +/* + This file is only used by IntelliSense (VisualStudio code suggestion system) + DO NOT INCLUDE THIS FILE FROM YOUR ACTUAL SOURCE FILES. + This file lists the preprocessor macros extracted from your GCC. + It is needed for IntelliSense to parse other header files correctly. +*/ +#if defined(_MSC_VER) || defined (__SYSPROGS_CODESENSE__) +#pragma clang diagnostic push + +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#ifndef __DBL_MIN_EXP__ +#define __DBL_MIN_EXP__ (-1021) +#endif +#ifndef __cpp_attributes +#define __cpp_attributes 200809 +#endif +#ifndef __UINT_LEAST16_MAX__ +#define __UINT_LEAST16_MAX__ 0xffff +#endif +#ifndef __ATOMIC_ACQUIRE +#define __ATOMIC_ACQUIRE 2 +#endif +#ifndef __FLT_MIN__ +#define __FLT_MIN__ 1.17549435082228750797e-38F +#endif +#ifndef __GCC_IEC_559_COMPLEX +#define __GCC_IEC_559_COMPLEX 2 +#endif +#ifndef __cpp_aggregate_nsdmi +#define __cpp_aggregate_nsdmi 201304 +#endif +#ifndef __UINT_LEAST8_TYPE__ +#define __UINT_LEAST8_TYPE__ unsigned char +#endif +#ifndef __SIZEOF_FLOAT80__ +#define __SIZEOF_FLOAT80__ 16 +#endif +#ifndef __CHAR_BIT__ +#define __CHAR_BIT__ 8 +#endif +#ifndef __UINT8_MAX__ +#define __UINT8_MAX__ 0xff +#endif +#ifndef __WINT_MAX__ +#define __WINT_MAX__ 0xffffffffU +#endif +#ifndef __cpp_static_assert +#define __cpp_static_assert 200410 +#endif +#ifndef __ORDER_LITTLE_ENDIAN__ +#define __ORDER_LITTLE_ENDIAN__ 1234 +#endif +#ifndef __SIZE_MAX__ +#define __SIZE_MAX__ 0xffffffffffffffffUL +#endif +#ifndef __WCHAR_MAX__ +#define __WCHAR_MAX__ 0x7fffffff +#endif +#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 +#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1 +#endif +#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 +#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1 +#endif +#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 +#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1 +#endif +#ifndef __DBL_DENORM_MIN__ +#define __DBL_DENORM_MIN__ double(4.94065645841246544177e-324L) +#endif +#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 +#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1 +#endif +#ifndef __GCC_ATOMIC_CHAR_LOCK_FREE +#define __GCC_ATOMIC_CHAR_LOCK_FREE 2 +#endif +#ifndef __GCC_IEC_559 +#define __GCC_IEC_559 2 +#endif +#ifndef __FLT_EVAL_METHOD__ +#define __FLT_EVAL_METHOD__ 0 +#endif +#ifndef __unix__ +#define __unix__ 1 +#endif +#ifndef __cpp_binary_literals +#define __cpp_binary_literals 201304 +#endif +#ifndef __GCC_ATOMIC_CHAR32_T_LOCK_FREE +#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2 +#endif +#ifndef __x86_64 +#define __x86_64 1 +#endif +#ifndef __cpp_variadic_templates +#define __cpp_variadic_templates 200704 +#endif +#ifndef __UINT_FAST64_MAX__ +#define __UINT_FAST64_MAX__ 0xffffffffffffffffUL +#endif +#ifndef __SIG_ATOMIC_TYPE__ +#define __SIG_ATOMIC_TYPE__ int +#endif +#ifndef __DBL_MIN_10_EXP__ +#define __DBL_MIN_10_EXP__ (-307) +#endif +#ifndef __FINITE_MATH_ONLY__ +#define __FINITE_MATH_ONLY__ 0 +#endif +#ifndef __cpp_variable_templates +#define __cpp_variable_templates 201304 +#endif +#ifndef __GNUC_PATCHLEVEL__ +#define __GNUC_PATCHLEVEL__ 0 +#endif +#ifndef __UINT_FAST8_MAX__ +#define __UINT_FAST8_MAX__ 0xff +#endif +#ifndef __DEC64_MAX_EXP__ +#define __DEC64_MAX_EXP__ 385 +#endif +#ifndef __UINT_LEAST64_MAX__ +#define __UINT_LEAST64_MAX__ 0xffffffffffffffffUL +#endif +#ifndef __SHRT_MAX__ +#define __SHRT_MAX__ 0x7fff +#endif +#ifndef __LDBL_MAX__ +#define __LDBL_MAX__ 1.18973149535723176502e+4932L +#endif +#ifndef __UINT_LEAST8_MAX__ +#define __UINT_LEAST8_MAX__ 0xff +#endif +#ifndef __GCC_ATOMIC_BOOL_LOCK_FREE +#define __GCC_ATOMIC_BOOL_LOCK_FREE 2 +#endif +#ifndef __UINTMAX_TYPE__ +#define __UINTMAX_TYPE__ long unsigned int +#endif +#ifndef __linux +#define __linux 1 +#endif +#ifndef __DEC32_EPSILON__ +#define __DEC32_EPSILON__ 1E-6DF +#endif +#ifndef __unix +#define __unix 1 +#endif +#ifndef __UINT32_MAX__ +#define __UINT32_MAX__ 0xffffffffU +#endif +#if !defined(__GXX_EXPERIMENTAL_CXX0X__) && defined(__SYSPROGS_CODESENSE__) +#define __GXX_EXPERIMENTAL_CXX0X__ 1 +#endif +#ifndef __LDBL_MAX_EXP__ +#define __LDBL_MAX_EXP__ 16384 +#endif +#ifndef __WINT_MIN__ +#define __WINT_MIN__ 0U +#endif +#ifndef __linux__ +#define __linux__ 1 +#endif +#ifndef __SCHAR_MAX__ +#define __SCHAR_MAX__ 0x7f +#endif +#ifndef __WCHAR_MIN__ +#define __WCHAR_MIN__ (-__WCHAR_MAX__ - 1) +#endif +#ifndef __DBL_DIG__ +#define __DBL_DIG__ 15 +#endif +#ifndef __GCC_ATOMIC_POINTER_LOCK_FREE +#define __GCC_ATOMIC_POINTER_LOCK_FREE 2 +#endif +#ifndef __SIZEOF_INT__ +#define __SIZEOF_INT__ 4 +#endif +#ifndef __SIZEOF_POINTER__ +#define __SIZEOF_POINTER__ 8 +#endif +#ifndef __GCC_ATOMIC_CHAR16_T_LOCK_FREE +#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2 +#endif +#ifndef __USER_LABEL_PREFIX__ +#define __USER_LABEL_PREFIX__ +#endif +#ifndef __STDC_HOSTED__ +#define __STDC_HOSTED__ 1 +#endif +#ifndef __LDBL_HAS_INFINITY__ +#define __LDBL_HAS_INFINITY__ 1 +#endif +#ifndef __FLT_EPSILON__ +#define __FLT_EPSILON__ 1.19209289550781250000e-7F +#endif +#ifndef __GXX_WEAK__ +#define __GXX_WEAK__ 1 +#endif +#ifndef __LDBL_MIN__ +#define __LDBL_MIN__ 3.36210314311209350626e-4932L +#endif +#ifndef __DEC32_MAX__ +#define __DEC32_MAX__ 9.999999E96DF +#endif +#ifndef __INT32_MAX__ +#define __INT32_MAX__ 0x7fffffff +#endif +#ifndef __SIZEOF_LONG__ +#define __SIZEOF_LONG__ 8 +#endif +#ifndef __STDC_IEC_559__ +#define __STDC_IEC_559__ 1 +#endif +#ifndef __STDC_ISO_10646__ +#define __STDC_ISO_10646__ 201605L +#endif +#ifndef __DECIMAL_DIG__ +#define __DECIMAL_DIG__ 21 +#endif +#ifndef __gnu_linux__ +#define __gnu_linux__ 1 +#endif +#ifndef __LDBL_HAS_QUIET_NAN__ +#define __LDBL_HAS_QUIET_NAN__ 1 +#endif +#ifndef __GNUC__ +#define __GNUC__ 6 +#endif +#ifndef __GXX_RTTI +#define __GXX_RTTI 1 +#endif +#ifndef __pie__ +#define __pie__ 2 +#endif +#ifndef __MMX__ +#define __MMX__ 1 +#endif +#ifndef __cpp_delegating_constructors +#define __cpp_delegating_constructors 200604 +#endif +#ifndef __FLT_HAS_DENORM__ +#define __FLT_HAS_DENORM__ 1 +#endif +#ifndef __SIZEOF_LONG_DOUBLE__ +#define __SIZEOF_LONG_DOUBLE__ 16 +#endif +#ifndef __BIGGEST_ALIGNMENT__ +#define __BIGGEST_ALIGNMENT__ 16 +#endif +#ifndef __STDC_UTF_16__ +#define __STDC_UTF_16__ 1 +#endif +#ifndef __DBL_MAX__ +#define __DBL_MAX__ double(1.79769313486231570815e+308L) +#endif +#ifndef __cpp_raw_strings +#define __cpp_raw_strings 200710 +#endif +#ifndef __INT_FAST32_MAX__ +#define __INT_FAST32_MAX__ 0x7fffffffffffffffL +#endif +#ifndef __DBL_HAS_INFINITY__ +#define __DBL_HAS_INFINITY__ 1 +#endif +#ifndef __INT64_MAX__ +#define __INT64_MAX__ 0x7fffffffffffffffL +#endif +#ifndef __DEC32_MIN_EXP__ +#define __DEC32_MIN_EXP__ (-94) +#endif +#ifndef __INT_FAST16_TYPE__ +#define __INT_FAST16_TYPE__ long int +#endif +#ifndef __LDBL_HAS_DENORM__ +#define __LDBL_HAS_DENORM__ 1 +#endif +//VS2005-2012 treats all files as C++, while VS2013+ can treat C files correctly. +#if defined(_MSC_VER) && (_MSC_VER < 1800 || defined(__cplusplus)) +#undef __cplusplus +#define __cplusplus 201402L +#endif +#ifndef __cpp_ref_qualifiers +#define __cpp_ref_qualifiers 200710 +#endif +#ifndef __DEC128_MAX__ +#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL +#endif +#ifndef __INT_LEAST32_MAX__ +#define __INT_LEAST32_MAX__ 0x7fffffff +#endif +#ifndef __DEC32_MIN__ +#define __DEC32_MIN__ 1E-95DF +#endif +#ifndef __DEPRECATED +#define __DEPRECATED 1 +#endif +#ifndef __cpp_rvalue_references +#define __cpp_rvalue_references 200610 +#endif +#ifndef __DBL_MAX_EXP__ +#define __DBL_MAX_EXP__ 1024 +#endif +#ifndef __DEC128_EPSILON__ +#define __DEC128_EPSILON__ 1E-33DL +#endif +#ifndef __SSE2_MATH__ +#define __SSE2_MATH__ 1 +#endif +#ifndef __ATOMIC_HLE_RELEASE +#define __ATOMIC_HLE_RELEASE 131072 +#endif +#ifndef __PTRDIFF_MAX__ +#define __PTRDIFF_MAX__ 0x7fffffffffffffffL +#endif +#ifndef __amd64 +#define __amd64 1 +#endif +#ifndef __STDC_NO_THREADS__ +#define __STDC_NO_THREADS__ 1 +#endif +#ifndef __ATOMIC_HLE_ACQUIRE +#define __ATOMIC_HLE_ACQUIRE 65536 +#endif +#ifndef __GNUG__ +#define __GNUG__ 6 +#endif +#ifndef __LONG_LONG_MAX__ +#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL +#endif +#ifndef __SIZEOF_SIZE_T__ +#define __SIZEOF_SIZE_T__ 8 +#endif +#ifndef __cpp_rvalue_reference +#define __cpp_rvalue_reference 200610 +#endif +#ifndef __cpp_nsdmi +#define __cpp_nsdmi 200809 +#endif +#ifndef __SIZEOF_WINT_T__ +#define __SIZEOF_WINT_T__ 4 +#endif +#ifndef __cpp_initializer_lists +#define __cpp_initializer_lists 200806 +#endif +#ifndef __cpp_hex_float +#define __cpp_hex_float 201603 +#endif +#ifndef __GCC_HAVE_DWARF2_CFI_ASM +#define __GCC_HAVE_DWARF2_CFI_ASM 1 +#endif +#ifndef __GXX_ABI_VERSION +#define __GXX_ABI_VERSION 1010 +#endif +#ifndef __FLT_MIN_EXP__ +#define __FLT_MIN_EXP__ (-125) +#endif +#ifndef __cpp_lambdas +#define __cpp_lambdas 200907 +#endif +#ifndef __INT_FAST64_TYPE__ +#define __INT_FAST64_TYPE__ long int +#endif +#ifndef __DBL_MIN__ +#define __DBL_MIN__ double(2.22507385850720138309e-308L) +#endif +#ifndef __PIE__ +#define __PIE__ 2 +#endif +#ifndef __LP64__ +#define __LP64__ 1 +#endif +#ifndef __DECIMAL_BID_FORMAT__ +#define __DECIMAL_BID_FORMAT__ 1 +#endif +#ifndef __DEC128_MIN__ +#define __DEC128_MIN__ 1E-6143DL +#endif +#ifndef __REGISTER_PREFIX__ +#define __REGISTER_PREFIX__ +#endif +#ifndef __UINT16_MAX__ +#define __UINT16_MAX__ 0xffff +#endif +#ifndef __DBL_HAS_DENORM__ +#define __DBL_HAS_DENORM__ 1 +#endif +#ifndef __UINT8_TYPE__ +#define __UINT8_TYPE__ unsigned char +#endif +#ifndef __NO_INLINE__ +#define __NO_INLINE__ 1 +#endif +#ifndef __FLT_MANT_DIG__ +#define __FLT_MANT_DIG__ 24 +#endif +#ifndef __VERSION__ +#define __VERSION__ "6.3.0 20170516" +#endif +#ifndef __cpp_unicode_characters +#define __cpp_unicode_characters 200704 +#endif +#ifndef _STDC_PREDEF_H +#define _STDC_PREDEF_H 1 +#endif +#ifndef __cpp_decltype_auto +#define __cpp_decltype_auto 201304 +#endif +#ifndef __GCC_ATOMIC_INT_LOCK_FREE +#define __GCC_ATOMIC_INT_LOCK_FREE 2 +#endif +#ifndef __FLOAT_WORD_ORDER__ +#define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__ +#endif +#ifndef __STDC_IEC_559_COMPLEX__ +#define __STDC_IEC_559_COMPLEX__ 1 +#endif +#ifndef __DEC64_EPSILON__ +#define __DEC64_EPSILON__ 1E-15DD +#endif +#ifndef __ORDER_PDP_ENDIAN__ +#define __ORDER_PDP_ENDIAN__ 3412 +#endif +#ifndef __DEC128_MIN_EXP__ +#define __DEC128_MIN_EXP__ (-6142) +#endif +#ifndef __INT_FAST32_TYPE__ +#define __INT_FAST32_TYPE__ long int +#endif +#ifndef __UINT_LEAST16_TYPE__ +#define __UINT_LEAST16_TYPE__ short unsigned int +#endif +#ifndef unix +#define unix 1 +#endif +#ifndef __INT16_MAX__ +#define __INT16_MAX__ 0x7fff +#endif +#ifndef __cpp_rtti +#define __cpp_rtti 199711 +#endif +#ifndef __SIZE_TYPE__ +#define __SIZE_TYPE__ long unsigned int +#endif +#ifndef __UINT64_MAX__ +#define __UINT64_MAX__ 0xffffffffffffffffUL +#endif +#ifndef __INT8_TYPE__ +#define __INT8_TYPE__ signed char +#endif +#ifndef __cpp_digit_separators +#define __cpp_digit_separators 201309 +#endif +#ifndef __ELF__ +#define __ELF__ 1 +#endif +#ifndef __GCC_ASM_FLAG_OUTPUTS__ +#define __GCC_ASM_FLAG_OUTPUTS__ 1 +#endif +#ifndef __FLT_RADIX__ +#define __FLT_RADIX__ 2 +#endif +#ifndef __INT_LEAST16_TYPE__ +#define __INT_LEAST16_TYPE__ short int +#endif +#ifndef __LDBL_EPSILON__ +#define __LDBL_EPSILON__ 1.08420217248550443401e-19L +#endif +#ifndef __GLIBCXX_BITSIZE_INT_N_0 +#define __GLIBCXX_BITSIZE_INT_N_0 128 +#endif +#ifndef __k8 +#define __k8 1 +#endif +#ifndef __SIG_ATOMIC_MAX__ +#define __SIG_ATOMIC_MAX__ 0x7fffffff +#endif +#ifndef __GCC_ATOMIC_WCHAR_T_LOCK_FREE +#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2 +#endif +#ifndef __cpp_sized_deallocation +#define __cpp_sized_deallocation 201309 +#endif +#ifndef __SIZEOF_PTRDIFF_T__ +#define __SIZEOF_PTRDIFF_T__ 8 +#endif +#ifndef __x86_64__ +#define __x86_64__ 1 +#endif +#ifndef __DEC32_SUBNORMAL_MIN__ +#define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF +#endif +#ifndef __INT_FAST16_MAX__ +#define __INT_FAST16_MAX__ 0x7fffffffffffffffL +#endif +#ifndef __UINT_FAST32_MAX__ +#define __UINT_FAST32_MAX__ 0xffffffffffffffffUL +#endif +#ifndef __UINT_LEAST64_TYPE__ +#define __UINT_LEAST64_TYPE__ long unsigned int +#endif +#ifndef __FLT_HAS_QUIET_NAN__ +#define __FLT_HAS_QUIET_NAN__ 1 +#endif +#ifndef __FLT_MAX_10_EXP__ +#define __FLT_MAX_10_EXP__ 38 +#endif +#ifndef __LONG_MAX__ +#define __LONG_MAX__ 0x7fffffffffffffffL +#endif +#ifndef __DEC128_SUBNORMAL_MIN__ +#define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL +#endif +#ifndef __FLT_HAS_INFINITY__ +#define __FLT_HAS_INFINITY__ 1 +#endif +#ifndef __cpp_unicode_literals +#define __cpp_unicode_literals 200710 +#endif +#ifndef __UINT_FAST16_TYPE__ +#define __UINT_FAST16_TYPE__ long unsigned int +#endif +#ifndef __DEC64_MAX__ +#define __DEC64_MAX__ 9.999999999999999E384DD +#endif +#ifndef __CHAR16_TYPE__ +#define __CHAR16_TYPE__ short unsigned int +#endif +#ifndef __PRAGMA_REDEFINE_EXTNAME +#define __PRAGMA_REDEFINE_EXTNAME 1 +#endif +#ifndef __SEG_FS +#define __SEG_FS 1 +#endif +#ifndef __INT_LEAST16_MAX__ +#define __INT_LEAST16_MAX__ 0x7fff +#endif +#ifndef __DEC64_MANT_DIG__ +#define __DEC64_MANT_DIG__ 16 +#endif +#ifndef __UINT_LEAST32_MAX__ +#define __UINT_LEAST32_MAX__ 0xffffffffU +#endif +#ifndef __SEG_GS +#define __SEG_GS 1 +#endif +#ifndef __GCC_ATOMIC_LONG_LOCK_FREE +#define __GCC_ATOMIC_LONG_LOCK_FREE 2 +#endif +#ifndef __INT_LEAST64_TYPE__ +#define __INT_LEAST64_TYPE__ long int +#endif +#ifndef __INT16_TYPE__ +#define __INT16_TYPE__ short int +#endif +#ifndef __INT_LEAST8_TYPE__ +#define __INT_LEAST8_TYPE__ signed char +#endif +#ifndef __DEC32_MAX_EXP__ +#define __DEC32_MAX_EXP__ 97 +#endif +#ifndef __INT_FAST8_MAX__ +#define __INT_FAST8_MAX__ 0x7f +#endif +#ifndef __INTPTR_MAX__ +#define __INTPTR_MAX__ 0x7fffffffffffffffL +#endif +#ifndef linux +#define linux 1 +#endif +#ifndef __cpp_range_based_for +#define __cpp_range_based_for 200907 +#endif +#ifndef __SSE2__ +#define __SSE2__ 1 +#endif +#ifndef __EXCEPTIONS +#define __EXCEPTIONS 1 +#endif +#ifndef __LDBL_MANT_DIG__ +#define __LDBL_MANT_DIG__ 64 +#endif +#ifndef __DBL_HAS_QUIET_NAN__ +#define __DBL_HAS_QUIET_NAN__ 1 +#endif +#ifndef __SIG_ATOMIC_MIN__ +#define __SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1) +#endif +#ifndef __code_model_small__ +#define __code_model_small__ 1 +#endif +#ifndef __cpp_return_type_deduction +#define __cpp_return_type_deduction 201304 +#endif +#ifndef __k8__ +#define __k8__ 1 +#endif +#ifndef __INTPTR_TYPE__ +#define __INTPTR_TYPE__ long int +#endif +#ifndef __UINT16_TYPE__ +#define __UINT16_TYPE__ short unsigned int +#endif +#ifndef __WCHAR_TYPE__ +#define __WCHAR_TYPE__ int +#endif +#ifndef __SIZEOF_FLOAT__ +#define __SIZEOF_FLOAT__ 4 +#endif +#ifndef __pic__ +#define __pic__ 2 +#endif +#ifndef __UINTPTR_MAX__ +#define __UINTPTR_MAX__ 0xffffffffffffffffUL +#endif +#ifndef __DEC64_MIN_EXP__ +#define __DEC64_MIN_EXP__ (-382) +#endif +#ifndef __cpp_decltype +#define __cpp_decltype 200707 +#endif +#ifndef __INT_FAST64_MAX__ +#define __INT_FAST64_MAX__ 0x7fffffffffffffffL +#endif +#ifndef __GCC_ATOMIC_TEST_AND_SET_TRUEVAL +#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1 +#endif +#ifndef __FLT_DIG__ +#define __FLT_DIG__ 6 +#endif +#ifndef __UINT_FAST64_TYPE__ +#define __UINT_FAST64_TYPE__ long unsigned int +#endif +#ifndef __INT_MAX__ +#define __INT_MAX__ 0x7fffffff +#endif +#ifndef __amd64__ +#define __amd64__ 1 +#endif +#ifndef __INT64_TYPE__ +#define __INT64_TYPE__ long int +#endif +#ifndef __FLT_MAX_EXP__ +#define __FLT_MAX_EXP__ 128 +#endif +#ifndef __ORDER_BIG_ENDIAN__ +#define __ORDER_BIG_ENDIAN__ 4321 +#endif +#ifndef __DBL_MANT_DIG__ +#define __DBL_MANT_DIG__ 53 +#endif +#ifndef __cpp_inheriting_constructors +#define __cpp_inheriting_constructors 200802 +#endif +#ifndef __SIZEOF_FLOAT128__ +#define __SIZEOF_FLOAT128__ 16 +#endif +#ifndef __INT_LEAST64_MAX__ +#define __INT_LEAST64_MAX__ 0x7fffffffffffffffL +#endif +#ifndef __DEC64_MIN__ +#define __DEC64_MIN__ 1E-383DD +#endif +#ifndef __WINT_TYPE__ +#define __WINT_TYPE__ unsigned int +#endif +#ifndef __UINT_LEAST32_TYPE__ +#define __UINT_LEAST32_TYPE__ unsigned int +#endif +#ifndef __SIZEOF_SHORT__ +#define __SIZEOF_SHORT__ 2 +#endif +#ifndef __SSE__ +#define __SSE__ 1 +#endif +#ifndef __LDBL_MIN_EXP__ +#define __LDBL_MIN_EXP__ (-16381) +#endif +#ifndef __INT_LEAST8_MAX__ +#define __INT_LEAST8_MAX__ 0x7f +#endif +#ifndef __SIZEOF_INT128__ +#define __SIZEOF_INT128__ 16 +#endif +#ifndef __LDBL_MAX_10_EXP__ +#define __LDBL_MAX_10_EXP__ 4932 +#endif +#ifndef __ATOMIC_RELAXED +#define __ATOMIC_RELAXED 0 +#endif +#ifndef __DBL_EPSILON__ +#define __DBL_EPSILON__ double(2.22044604925031308085e-16L) +#endif +#ifndef _LP64 +#define _LP64 1 +#endif +#ifndef __INT_LEAST32_TYPE__ +#define __INT_LEAST32_TYPE__ int +#endif +#ifndef __SIZEOF_WCHAR_T__ +#define __SIZEOF_WCHAR_T__ 4 +#endif +#ifndef __UINT64_TYPE__ +#define __UINT64_TYPE__ long unsigned int +#endif +#ifndef __INT_FAST8_TYPE__ +#define __INT_FAST8_TYPE__ signed char +#endif +#ifndef __GNUC_STDC_INLINE__ +#define __GNUC_STDC_INLINE__ 1 +#endif +#ifndef __DBL_DECIMAL_DIG__ +#define __DBL_DECIMAL_DIG__ 17 +#endif +#ifndef __STDC_UTF_32__ +#define __STDC_UTF_32__ 1 +#endif +#ifndef __FXSR__ +#define __FXSR__ 1 +#endif +#ifndef __DEC_EVAL_METHOD__ +#define __DEC_EVAL_METHOD__ 2 +#endif +#ifndef __cpp_runtime_arrays +#define __cpp_runtime_arrays 198712 +#endif +#ifndef __INTMAX_MAX__ +#define __INTMAX_MAX__ 0x7fffffffffffffffL +#endif +#ifndef __cpp_alias_templates +#define __cpp_alias_templates 200704 +#endif +#ifndef __BYTE_ORDER__ +#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ +#endif +#ifndef __FLT_DENORM_MIN__ +#define __FLT_DENORM_MIN__ 1.40129846432481707092e-45F +#endif +#ifndef __INT8_MAX__ +#define __INT8_MAX__ 0x7f +#endif +#ifndef __PIC__ +#define __PIC__ 2 +#endif +#ifndef __UINT_FAST32_TYPE__ +#define __UINT_FAST32_TYPE__ long unsigned int +#endif +#ifndef __CHAR32_TYPE__ +#define __CHAR32_TYPE__ unsigned int +#endif +#ifndef __FLT_MAX__ +#define __FLT_MAX__ 3.40282346638528859812e+38F +#endif +#ifndef __cpp_constexpr +#define __cpp_constexpr 201304 +#endif +#ifndef __INT32_TYPE__ +#define __INT32_TYPE__ int +#endif +#ifndef __SIZEOF_DOUBLE__ +#define __SIZEOF_DOUBLE__ 8 +#endif +#ifndef __cpp_exceptions +#define __cpp_exceptions 199711 +#endif +#ifndef __INTMAX_TYPE__ +#define __INTMAX_TYPE__ long int +#endif +#ifndef __DEC128_MAX_EXP__ +#define __DEC128_MAX_EXP__ 6145 +#endif +#ifndef __ATOMIC_CONSUME +#define __ATOMIC_CONSUME 1 +#endif +#ifndef __GNUC_MINOR__ +#define __GNUC_MINOR__ 3 +#endif +#ifndef __GLIBCXX_TYPE_INT_N_0 +#define __GLIBCXX_TYPE_INT_N_0 __int128 +#endif +#ifndef __UINTMAX_MAX__ +#define __UINTMAX_MAX__ 0xffffffffffffffffUL +#endif +#ifndef __DEC32_MANT_DIG__ +#define __DEC32_MANT_DIG__ 7 +#endif +#ifndef __DBL_MAX_10_EXP__ +#define __DBL_MAX_10_EXP__ 308 +#endif +#ifndef __LDBL_DENORM_MIN__ +#define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L +#endif +#ifndef __cpp_generic_lambdas +#define __cpp_generic_lambdas 201304 +#endif +#ifndef __STDC__ +#define __STDC__ 1 +#endif +#ifndef __PTRDIFF_TYPE__ +#define __PTRDIFF_TYPE__ long int +#endif +#ifndef __ATOMIC_SEQ_CST +#define __ATOMIC_SEQ_CST 5 +#endif +#ifndef __UINT32_TYPE__ +#define __UINT32_TYPE__ unsigned int +#endif +#ifndef __UINTPTR_TYPE__ +#define __UINTPTR_TYPE__ long unsigned int +#endif +#ifndef __DEC64_SUBNORMAL_MIN__ +#define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD +#endif +#ifndef __DEC128_MANT_DIG__ +#define __DEC128_MANT_DIG__ 34 +#endif +#ifndef __LDBL_MIN_10_EXP__ +#define __LDBL_MIN_10_EXP__ (-4931) +#endif +#ifndef __SSE_MATH__ +#define __SSE_MATH__ 1 +#endif +#ifndef __SIZEOF_LONG_LONG__ +#define __SIZEOF_LONG_LONG__ 8 +#endif +#ifndef __cpp_user_defined_literals +#define __cpp_user_defined_literals 200809 +#endif +#ifndef __GCC_ATOMIC_LLONG_LOCK_FREE +#define __GCC_ATOMIC_LLONG_LOCK_FREE 2 +#endif +#ifndef __LDBL_DIG__ +#define __LDBL_DIG__ 18 +#endif +#ifndef __FLT_DECIMAL_DIG__ +#define __FLT_DECIMAL_DIG__ 9 +#endif +#ifndef __UINT_FAST16_MAX__ +#define __UINT_FAST16_MAX__ 0xffffffffffffffffUL +#endif +#ifndef __FLT_MIN_10_EXP__ +#define __FLT_MIN_10_EXP__ (-37) +#endif +#ifndef __GCC_ATOMIC_SHORT_LOCK_FREE +#define __GCC_ATOMIC_SHORT_LOCK_FREE 2 +#endif +#ifndef __UINT_FAST8_TYPE__ +#define __UINT_FAST8_TYPE__ unsigned char +#endif +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif +#ifndef __cpp_init_captures +#define __cpp_init_captures 201304 +#endif +#ifndef __ATOMIC_ACQ_REL +#define __ATOMIC_ACQ_REL 4 +#endif +#ifndef __ATOMIC_RELEASE +#define __ATOMIC_RELEASE 3 +#endif +#ifndef NDEBUG +#define NDEBUG 1 +#endif +#ifndef RELEASE +#define RELEASE 1 +#endif +#endif + +// --- Include directories begin --- // +///usr/include/c++/6 +///usr/include/x86_64-linux-gnu/c++/6 +///usr/include/c++/6/backward +///usr/lib/gcc/x86_64-linux-gnu/6/include +///usr/local/include +///usr/lib/gcc/x86_64-linux-gnu/6/include-fixed +///usr/include/x86_64-linux-gnu +///usr/include +// --- Include directories end --- // + + +// --- Library directories begin --- // +///usr/lib/gcc/x86_64-linux-gnu/6/ +///usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/ +///usr/lib/gcc/x86_64-linux-gnu/6/../../../../lib/ +///lib/x86_64-linux-gnu/ +///lib/../lib/ +///usr/lib/x86_64-linux-gnu/ +///usr/lib/../lib/ +///usr/lib/gcc/x86_64-linux-gnu/6/../../../ +///lib/ +///usr/lib/ +// --- Library directories begin --- // + +#pragma clang diagnostic pop diff --git a/examples/knx-linux-coupler/knx-linux-Debug.vgdbsettings b/examples/knx-linux-coupler/knx-linux-Debug.vgdbsettings new file mode 100644 index 0000000..5c17819 --- /dev/null +++ b/examples/knx-linux-coupler/knx-linux-Debug.vgdbsettings @@ -0,0 +1,179 @@ + + + Debug + + + + RemoteUnix + + + Immerlund + SSH + tkunze + + + false + + Suzail + SSH + tkunze + + $(ProjectDir)\..\.. + /home/tkunze/vgdb/knx-linux + + *.cpp + *.h + *.hpp + *.c + *.cc + *.cxx + *.mak + Makefile + *.txt + *.cmake + CMakeLists.txt + *.cmake + + false + true + + true + true + + Outgoing + false + Always + + + false + false + false + false + false + $(ProjectDir) + + + + com.sysprogs.toolchain.default-gcc + + 0 + + + examples/knx-linux + DEBUG + Debug + knx-linux + + false + + BuildMachine + BuiltinShortcut + + $(ToolchainMake) + $(ToolchainMakeArgs) + $(BuildDir) + + + + false + + BuildMachine + BuiltinShortcut + + $(ToolchainCMake) + $(BuildDir) + + + false + false + false + false + RemoveBuildDirectory + + + + + + + + + + + + + Default + + + + true + + + + + True + -DMEDIUM_TYPE=5 + + true + true + + Silent + true + true + true + + true + ..\.clang-format + ClangFormat + + + false + + + + + + + + + false + false + false + false + false + false + false + false + false + + false + false + false + false + false + false + true + false + None + false + false + main + true + false + false + false + 0 + + + $(TargetPath) + 2000 + + + false + Local + false + false + Auto + true + false + + \ No newline at end of file diff --git a/examples/knx-linux-coupler/knx-linux.vcxproj b/examples/knx-linux-coupler/knx-linux.vcxproj new file mode 100644 index 0000000..cdc925d --- /dev/null +++ b/examples/knx-linux-coupler/knx-linux.vcxproj @@ -0,0 +1,188 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + 16.0 + {456D87B3-1DFE-4724-BDEF-17E0FDB55A61} + + + + Makefile + true + v142 + + + Makefile + false + v142 + + + com.sysprogs.toolchain.default-gcc + + + + + + + + + + + + + + + + + + $(LOCALAPPDATA)\VisualGDB\RemoteSourceCache\Suzail\0000\include\c++\6;$(LOCALAPPDATA)\VisualGDB\RemoteSourceCache\Suzail\0000\include\x86_64-linux-gnu\c++\6;$(LOCALAPPDATA)\VisualGDB\RemoteSourceCache\Suzail\0000\include\c++\6\backward;$(LOCALAPPDATA)\VisualGDB\RemoteSourceCache\Suzail\0003\include;$(LOCALAPPDATA)\VisualGDB\RemoteSourceCache\Suzail\0005\include;$(LOCALAPPDATA)\VisualGDB\RemoteSourceCache\Suzail\0004\include-fixed;$(LOCALAPPDATA)\VisualGDB\RemoteSourceCache\Suzail\0000\include\x86_64-linux-gnu;$(LOCALAPPDATA)\VisualGDB\RemoteSourceCache\Suzail\0000\include;..\src;$(NMakeIncludeSearchPath) + $(ProjectDir)\gcc_Debug.h;$(VISUALGDB_DIR)\gcc_compat.h;$(NMakeForcedIncludes) + "$(VISUALGDB_DIR)\VisualGDB.exe" /build "$(ProjectPath)" "/solution:$(SolutionPath)" "/config:$(Configuration)" "/platform:$(Platform)" + "$(VISUALGDB_DIR)\VisualGDB.exe" /clean "$(ProjectPath)" "/solution:$(SolutionPath)" "/config:$(Configuration)" "/platform:$(Platform)" + "$(VISUALGDB_DIR)\VisualGDB.exe" /rebuild "$(ProjectPath)" "/solution:$(SolutionPath)" "/config:$(Configuration)" "/platform:$(Platform)" + $(ProjectDir)knx-linux-Debug.vgdbsettings + + + + __VisualGDB_CFG_Debug;$(NMakePreprocessorDefinitions) + + + $(LOCALAPPDATA)\VisualGDB\RemoteSourceCache\Suzail\0000\include\c++\6;$(LOCALAPPDATA)\VisualGDB\RemoteSourceCache\Suzail\0000\include\x86_64-linux-gnu\c++\6;$(LOCALAPPDATA)\VisualGDB\RemoteSourceCache\Suzail\0000\include\c++\6\backward;$(LOCALAPPDATA)\VisualGDB\RemoteSourceCache\Suzail\0003\include;$(LOCALAPPDATA)\VisualGDB\RemoteSourceCache\Suzail\0005\include;$(LOCALAPPDATA)\VisualGDB\RemoteSourceCache\Suzail\0004\include-fixed;$(LOCALAPPDATA)\VisualGDB\RemoteSourceCache\Suzail\0000\include\x86_64-linux-gnu;$(LOCALAPPDATA)\VisualGDB\RemoteSourceCache\Suzail\0000\include;$(NMakeIncludeSearchPath) + $(ProjectDir)\gcc_Release.h;$(VISUALGDB_DIR)\gcc_compat.h;$(NMakeForcedIncludes) + __VisualGDB_CFG_Release;$(NMakePreprocessorDefinitions) + "$(VISUALGDB_DIR)\VisualGDB.exe" /build "$(ProjectPath)" "/solution:$(SolutionPath)" "/config:$(Configuration)" "/platform:$(Platform)" + "$(VISUALGDB_DIR)\VisualGDB.exe" /clean "$(ProjectPath)" "/solution:$(SolutionPath)" "/config:$(Configuration)" "/platform:$(Platform)" + "$(VISUALGDB_DIR)\VisualGDB.exe" /rebuild "$(ProjectPath)" "/solution:$(SolutionPath)" "/config:$(Configuration)" "/platform:$(Platform)" + $(ProjectDir)knx-linux-Release.vgdbsettings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/knx-linux-coupler/knx-linux.vcxproj.filters b/examples/knx-linux-coupler/knx-linux.vcxproj.filters new file mode 100644 index 0000000..6b44be3 --- /dev/null +++ b/examples/knx-linux-coupler/knx-linux.vcxproj.filters @@ -0,0 +1,353 @@ + + + + + {29de078d-e84a-4e6d-92cb-26384b285546} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {d598f99b-b8fc-4ed9-8a7e-0a047e95dd6a} + h;hpp;hxx;hm;inl;inc;xsd + + + {ca59d480-df76-48f4-984e-06d3c358cbc3} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {b4d51fcc-4baa-41f7-a703-7beb0174c220} + + + {3dbcfef7-ce75-49d5-bb03-d72ec2dd20bd} + + + {726bfac3-c98a-4508-9595-11dab7ffc9d0} + + + + + Source files + + + VisualGDB settings + + + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files + + + Header files + + + Header files + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + + + Source files + + + Source files + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + \ No newline at end of file diff --git a/examples/knx-linux-coupler/main.cpp b/examples/knx-linux-coupler/main.cpp new file mode 100644 index 0000000..ac564d2 --- /dev/null +++ b/examples/knx-linux-coupler/main.cpp @@ -0,0 +1,112 @@ +#include "knx_facade.h" + +#include "knx/bau091A.h" +#include "knx/bau2920.h" + +#include "knx/bits.h" +#include +#include +#include +#include +#include +#include +#include + +#include "fdsk.h" + +volatile sig_atomic_t loopActive = 1; +void signalHandler(int sig) +{ + (void)sig; + + // can be called asynchronously + loopActive = 0; +} + +bool sendHidReport(uint8_t* data, uint16_t length) +{ + return false; +} +bool isSendHidReportPossible() +{ + return false; +} + +#if MASK_VERSION == 0x091A +KnxFacade knx; // IP/TP1 coupler +#elif MASK_VERSION == 0x2920 +KnxFacade knx; // TP1/RF coupler +#else +#error Mask version not supported yet! +#endif + +void appLoop() +{ + if (!knx.configured()) + return; +} + +void setup() +{ + srand((unsigned int)time(NULL)); + knx.readMemory(); + + if (knx.induvidualAddress() == 0) + knx.progMode(true); + + if (knx.configured()) + { + printf("configured %d\n", knx.paramByte(5)); + } + else + println("not configured"); + knx.start(); +} + +int main(int argc, char **argv) +{ + printf("main() start.\n"); + + uint8_t serialNumber[] = { 0x00, 0xFA, 0x01, 0x02, 0x03, 0x04}; + uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; + + FdskCalculator calc; + char fdskString[42]; // 6 * 6 chars + 5 dashes + nullbyte = 42 + calc.snprintFdsk(fdskString, sizeof(fdskString), serialNumber, key); + printf("FDSK: %s\n", fdskString); + + // Prevent swapping of this process + struct sched_param sp; + memset(&sp, 0, sizeof(sp)); + sp.sched_priority = sched_get_priority_max(SCHED_FIFO); + sched_setscheduler(0, SCHED_FIFO, &sp); + mlockall(MCL_CURRENT | MCL_FUTURE); + + // Register signals + signal(SIGINT, signalHandler); + signal(SIGTERM, signalHandler); + + knx.platform().cmdLineArgs(argc, argv); + + setup(); + + while (loopActive) + { + knx.loop(); + if(knx.configured()) + appLoop(); + delayMicroseconds(100); + } + + // pinMode() will automatically export GPIO pin in sysfs + // Read or writing the GPIO pin for the first time automatically + // opens the "value" sysfs file to read or write the GPIO pin value. + // The following calls will close the "value" sysfs fiel for the pin + // and unexport the GPIO pin. +#ifdef USE_RF + gpio_unexport(SPI_SS_PIN); + gpio_unexport(GPIO_GDO2_PIN); + gpio_unexport(GPIO_GDO0_PIN); +#endif + printf("main() exit.\n"); +} diff --git a/examples/knx-linux/CMakeLists.txt b/examples/knx-linux/CMakeLists.txt index fe87d43..b84d7b7 100644 --- a/examples/knx-linux/CMakeLists.txt +++ b/examples/knx-linux/CMakeLists.txt @@ -2,61 +2,69 @@ cmake_minimum_required(VERSION 2.7) project(knx-linux) set(LIBRARIES_FROM_REFERENCES "") add_executable(knx-linux - ../../src/knx/address_table_object.cpp - ../../src/knx/address_table_object.h + ../../src/knx/address_table_object.cpp + ../../src/knx/address_table_object.h ../../src/knx/aes.c ../../src/knx/aes.h ../../src/knx/aes.hpp ../../src/knx/apdu.cpp - ../../src/knx/apdu.h - ../../src/knx/application_layer.cpp - ../../src/knx/application_layer.h - ../../src/knx/application_program_object.cpp - ../../src/knx/application_program_object.h - ../../src/knx/association_table_object.cpp - ../../src/knx/association_table_object.h - ../../src/knx/bau.cpp - ../../src/knx/bau.h - ../../src/knx/bau07B0.cpp - ../../src/knx/bau07B0.h - ../../src/knx/bau27B0.cpp - ../../src/knx/bau27B0.h - ../../src/knx/bau57B0.cpp - ../../src/knx/bau57B0.h - ../../src/knx/bau_systemB.cpp - ../../src/knx/bau_systemB.h - ../../src/knx/bits.cpp - ../../src/knx/bits.h - ../../src/knx/callback_property.h - ../../src/knx/cemi_frame.cpp - ../../src/knx/cemi_frame.h - ../../src/knx/cemi_server.cpp + ../../src/knx/apdu.h + ../../src/knx/application_layer.cpp + ../../src/knx/application_layer.h + ../../src/knx/application_program_object.cpp + ../../src/knx/application_program_object.h + ../../src/knx/association_table_object.cpp + ../../src/knx/association_table_object.h + ../../src/knx/bau.cpp + ../../src/knx/bau.h + ../../src/knx/bau07B0.cpp + ../../src/knx/bau07B0.h + ../../src/knx/bau091A.cpp + ../../src/knx/bau091A.h + ../../src/knx/bau27B0.cpp + ../../src/knx/bau27B0.h + ../../src/knx/bau2920.cpp + ../../src/knx/bau2920.h + ../../src/knx/bau57B0.cpp + ../../src/knx/bau57B0.h + ../../src/knx/bau_systemB.cpp + ../../src/knx/bau_systemB.h + ../../src/knx/bau_systemB_device.cpp + ../../src/knx/bau_systemB_device.h + ../../src/knx/bau_systemB_coupler.cpp + ../../src/knx/bau_systemB_coupler.h + ../../src/knx/bits.cpp + ../../src/knx/bits.h + ../../src/knx/callback_property.h + ../../src/knx/cemi_frame.cpp + ../../src/knx/cemi_frame.h + ../../src/knx/cemi_server.cpp ../../src/knx/cemi_server.h ../../src/knx/cemi_server_object.cpp ../../src/knx/cemi_server_object.h ../../src/knx/config.h ../../src/knx/data_link_layer.cpp - ../../src/knx/data_link_layer.h - ../../src/knx/data_property.cpp - ../../src/knx/data_property.h - ../../src/knx/device_object.cpp - ../../src/knx/device_object.h - ../../src/knx/dpt.cpp - ../../src/knx/dpt.h - ../../src/knx/dptconvert.cpp - ../../src/knx/dptconvert.h + ../../src/knx/data_link_layer.h + ../../src/knx/data_property.cpp + ../../src/knx/data_property.h + ../../src/knx/device_object.cpp + ../../src/knx/device_object.h + ../../src/knx/dpt.cpp + ../../src/knx/dpt.h + ../../src/knx/dptconvert.cpp + ../../src/knx/dptconvert.h ../../src/knx/function_property.h ../../src/knx/group_object.cpp - ../../src/knx/group_object.h - ../../src/knx/group_object_table_object.cpp - ../../src/knx/group_object_table_object.h - ../../src/knx/interface_object.cpp - ../../src/knx/interface_object.h - ../../src/knx/ip_data_link_layer.cpp - ../../src/knx/ip_data_link_layer.h - ../../src/knx/ip_parameter_object.cpp - ../../src/knx/ip_parameter_object.h - ../../src/knx/knx_ip_device_information_dib.cpp + ../../src/knx/group_object.h + ../../src/knx/group_object_table_object.cpp + ../../src/knx/group_object_table_object.h + ../../src/knx/interface_object.cpp + ../../src/knx/interface_object.h + ../../src/knx/ip_data_link_layer.cpp + ../../src/knx/ip_data_link_layer.h + ../../src/knx/ip_parameter_object.cpp + ../../src/knx/ip_parameter_object.h + ../../src/knx/knx_ip_device_information_dib.cpp ../../src/knx/knx_ip_device_information_dib.h ../../src/knx/knx_ip_dib.cpp ../../src/knx/knx_ip_dib.h @@ -74,44 +82,51 @@ add_executable(knx-linux ../../src/knx/ip_host_protocol_address_information.h ../../src/knx/knx_types.h ../../src/knx/knx_value.cpp - ../../src/knx/knx_value.h - ../../src/knx/memory.cpp - ../../src/knx/memory.h - ../../src/knx/network_layer.cpp - ../../src/knx/network_layer.h - ../../src/knx/npdu.cpp - ../../src/knx/npdu.h + ../../src/knx/knx_value.h + ../../src/knx/memory.cpp + ../../src/knx/memory.h + ../../src/knx/network_layer.cpp + ../../src/knx/network_layer.h + ../../src/knx/network_layer_coupler.cpp + ../../src/knx/network_layer_coupler.h + ../../src/knx/network_layer_device.cpp + ../../src/knx/network_layer_device.h + ../../src/knx/network_layer_entity.cpp + ../../src/knx/network_layer_entity.h + ../../src/knx/npdu.cpp + ../../src/knx/npdu.h ../../src/knx/platform.cpp - ../../src/knx/platform.h - ../../src/knx/property.cpp - ../../src/knx/property.h - ../../src/knx/rf_data_link_layer.cpp - ../../src/knx/rf_data_link_layer.h - ../../src/knx/rf_medium_object.cpp - ../../src/knx/rf_medium_object.h - ../../src/knx/rf_physical_layer.cpp - ../../src/knx/rf_physical_layer.h + ../../src/knx/platform.h + ../../src/knx/property.cpp + ../../src/knx/property.h + ../../src/knx/rf_data_link_layer.cpp + ../../src/knx/rf_data_link_layer.h + ../../src/knx/rf_medium_object.cpp + ../../src/knx/rf_medium_object.h + ../../src/knx/rf_physical_layer.cpp + ../../src/knx/rf_physical_layer.h + ../../src/knx/router_object.cpp + ../../src/knx/router_object.h ../../src/knx/secure_application_layer.cpp ../../src/knx/secure_application_layer.h ../../src/knx/security_interface_object.cpp ../../src/knx/security_interface_object.h ../../src/knx/simple_map.h - ../../src/knx/table_object.cpp ../../src/knx/save_restore.h - ../../src/knx/table_object.cpp - ../../src/knx/table_object.h - ../../src/knx/tpdu.cpp - ../../src/knx/tpdu.h - ../../src/knx/tpuart_data_link_layer.cpp - ../../src/knx/tpuart_data_link_layer.h - ../../src/knx/transport_layer.cpp - ../../src/knx/transport_layer.h - ../../src/knx/usb_tunnel_interface.cpp + ../../src/knx/table_object.cpp + ../../src/knx/table_object.h + ../../src/knx/tpdu.cpp + ../../src/knx/tpdu.h + ../../src/knx/tpuart_data_link_layer.cpp + ../../src/knx/tpuart_data_link_layer.h + ../../src/knx/transport_layer.cpp + ../../src/knx/transport_layer.h + ../../src/knx/usb_tunnel_interface.cpp ../../src/knx/usb_tunnel_interface.h ../../src/knx_facade.cpp - ../../src/knx_facade.h - ../../src/linux_platform.cpp - ../../src/linux_platform.h + ../../src/knx_facade.h + ../../src/linux_platform.cpp + ../../src/linux_platform.h fdsk.cpp fdsk.h main.cpp) @@ -120,4 +135,4 @@ include_directories(../../src) set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall -Wno-unknown-pragmas -g -O0") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wno-unknown-pragmas -g -O0") set_property(TARGET knx-linux PROPERTY CXX_STANDARD 11) -add_definitions(-DMEDIUM_TYPE=5) +add_definitions(-DMASK_VERSION=0x57B0) diff --git a/examples/knx-linux/main.cpp b/examples/knx-linux/main.cpp index f835e0e..9c17954 100644 --- a/examples/knx-linux/main.cpp +++ b/examples/knx-linux/main.cpp @@ -33,12 +33,13 @@ bool isSendHidReportPossible() { return false; } -#if MEDIUM_TYPE == 5 + +#if MASK_VERSION == 0x57B0 KnxFacade knx; -#elif MEDIUM_TYPE == 2 +#elif MASK_VERSION == 0x27B0 KnxFacade knx; #else -#error Only MEDIUM_TYPE IP and RF supported +#error Mask version not supported yet! #endif long lastsend = 0; diff --git a/examples/knx-usb/platformio-ci.ini b/examples/knx-usb/platformio-ci.ini index 0dd3625..5f96f44 100644 --- a/examples/knx-usb/platformio-ci.ini +++ b/examples/knx-usb/platformio-ci.ini @@ -24,7 +24,7 @@ lib_deps = knx build_flags = - -DMEDIUM_TYPE=2 + -DMASK_VERSION=0x27B0 -DUSE_USB -DUSE_TINYUSB -Wno-unknown-pragmas diff --git a/examples/knx-usb/platformio.ini b/examples/knx-usb/platformio.ini index b3ae3ad..c4b69f1 100644 --- a/examples/knx-usb/platformio.ini +++ b/examples/knx-usb/platformio.ini @@ -32,7 +32,7 @@ lib_deps = knx build_flags = - -DMEDIUM_TYPE=2 + -DMASK_VERSION=0x27B0 -DUSE_USB -DUSE_TINYUSB -Wno-unknown-pragmas diff --git a/src/knx.h b/src/knx.h index 9ead5cd..d53f48e 100644 --- a/src/knx.h +++ b/src/knx.h @@ -1,54 +1,80 @@ #pragma once -/** \page Classdiagramm - * This diagramm shows the most important classes. +/** \page Classdiagramm KNX device + * This diagramm shows the most important classes of a normal KNX device. @startuml + skinparam monochrome true skinparam componentStyle uml2 -package knx { + +note top of knx + Class diagram for a + normal KNX device +end note +package "knx" { class BusAccessUnit [[class_bus_access_unit.html]] class DeviceObject [[class_device_object.html]] -class BauSystemB [[class_bau_system_b.html]] +class BauSystemBDevice [[class_bau_system_b.html]] BusAccessUnit<|--BauSystemB +BauSystemB<|--BauSystemBDevice class ApplicationProgramObject [[class_application_program_object.html]] BauSystemB*--ApplicationProgramObject DeviceObject--*BauSystemB class AddressTableObject [[class_address_table_object.html]] -BauSystemB*--AddressTableObject +BauSystemBDevice*--AddressTableObject class AssociationTableObject [[class_association_table_object.html]] -BauSystemB*--AssociationTableObject +BauSystemBDevice*--AssociationTableObject class GroupObjectTableObject [[class_group_object_table_object.html]] -BauSystemB*--GroupObjectTableObject +BauSystemBDevice*--GroupObjectTableObject class GroupObject [[class_group_object.html]] GroupObject<--GroupObjectTableObject GroupObjectTableObject<--GroupObject class ApplicationLayer [[class_application_layer.html]] -ApplicationLayer--*BauSystemB + +package knx-data-secure +{ +class SecureApplicationLayer [[class_secure_application_layer.html]] +class SecurityInterfaceObject [[class_security_interface_object.html]] +SecureApplicationLayer-->SecurityInterfaceObject +SecurityInterfaceObject-->SecureApplicationLayer +BauSystemBDevice*--"SecurityInterfaceObject" +BauSystemBDevice*--"SecureApplicationLayer" +} +BauSystemBDevice*--"ApplicationLayer" +ApplicationLayer<|--SecureApplicationLayer +SecureApplicationLayer--*BauSystemBDevice class TransportLayer [[class_transport_layer.html]] -TransportLayer--*BauSystemB -class NetworkLayer [[class_network_layer.html]] -NetworkLayer--*BauSystemB +TransportLayer--*BauSystemBDevice +class NetworkLayerDevice [[class_network_layer.html]] +NetworkLayerDevice--*BauSystemBDevice +class NetworkLayerEntity [[class_network_layer_entity.html]] +NetworkLayerEntity--*NetworkLayerDevice class DataLinkLayer [[class_data_link_layer.html]] -DataLinkLayer--*BauSystemB +ApplicationLayer-->SecureApplicationLayer +SecureApplicationLayer-->ApplicationLayer ApplicationLayer-->BusAccessUnit ApplicationLayer-->TransportLayer +SecureApplicationLayer-->TransportLayer TransportLayer-->ApplicationLayer -TransportLayer-->NetworkLayer -NetworkLayer-->TransportLayer -NetworkLayer-->DataLinkLayer -DataLinkLayer-->NetworkLayer +TransportLayer-->SecureApplicationLayer +TransportLayer-->NetworkLayerDevice +NetworkLayerDevice-->TransportLayer +NetworkLayerEntity-->DataLinkLayer +DataLinkLayer-->NetworkLayerEntity TransportLayer-->AddressTableObject -DataLinkLayer-->AddressTableObject +SecureApplicationLayer-->AddressTableObject +SecureApplicationLayer-->DeviceObject DataLinkLayer-->DeviceObject ApplicationLayer-->AssociationTableObject class Dpt [[class_dpt.html]] GroupObject->Dpt + package knx-ip { class IpDataLinkLayer [[class_ip_data_link_layer.html]] IpDataLinkLayer--|>DataLinkLayer class Bau57B0 [[class_bau57_b0.html]] -Bau57B0--|>BauSystemB +Bau57B0--|>BauSystemBDevice Bau57B0*--IpDataLinkLayer class IpParameterObject [[class_ip_parameter_object.html]] IpParameterObject-->DeviceObject @@ -61,26 +87,161 @@ class TpUartDataLinkLayer [[class_tp_uart_data_link_layer.html]] TpUartDataLinkLayer--|>DataLinkLayer class Bau07B0 [[class_bau07_b0.html]] Bau07B0*--TpUartDataLinkLayer -Bau07B0--|>BauSystemB +Bau07B0--|>BauSystemBDevice } +package knx-rf +{ +class RfDataLinkLayer [[class_rf_data_link_layer.html]] +RfDataLinkLayer--|>DataLinkLayer +class Bau27B0 [[class_bau27_b0.html]] +Bau27B0*--"RfDataLinkLayer" +Bau27B0--|>BauSystemBDevice +class RfMediumObject [[class_rf_medium_object.html]] +Bau27B0*--"RfMediumObject" +class RfPhysicalLayer [[class_rf_physical_layer.html]] +"RfDataLinkLayer"*--"RfPhysicalLayer" +} +package knx-cemi-server +{ +class CemiServer [[class_cemi_server.html]] +class CemiServerObject [[class_cemi_server_object.html]] +class UsbTunnelInterface [[class_usb_tunnel_inerface.html]] +CemiServer*--"UsbTunnelInterface" +Bau57B0*--"CemiServer" +Bau57B0*--"CemiServerObject" +Bau27B0*--"CemiServer" +Bau27B0*--"CemiServerObject" +Bau07B0*--"CemiServer" +Bau07B0*--"CemiServerObject" +} +CemiServer-->DataLinkLayer +DataLinkLayer-->CemiServer } -package platfom +package platform { class Platform [[class_platform.html]] +class ArduinoPlatform [[class_arduino_platform.html]] class SamdPlatform [[class_samd_platform.html]] -Platform<|--SamdPlatform +Platform<|--ArduinoPlatform +ArduinoPlatform<|--SamdPlatform class EspPlatform [[class_esp_platform.html]] -Platform<|--EspPlatform +ArduinoPlatform<|--EspPlatform +class Esp32Platform [[class_esp32_platform.html]] +ArduinoPlatform<|--Esp32Platform +class Stm32Platform [[class_stm32_platform.html]] +ArduinoPlatform<|--Stm32Platform class LinuxPlatform [[class_linux_platform.html]] LinuxPlatform--|>Platform } package frontend { class KnxFacade [[class_knx_facade.html]] -BauSystemB<--KnxFacade +BauSystemBDevice<--KnxFacade } knx-->Platform @enduml + +/** \page Classdiagramm KNX coupler + * This diagramm shows the most important classes of a KNX coupler. +@startuml + +skinparam monochrome true +skinparam componentStyle uml2 + +note top of knx + Class diagram for a + KNX coupler +end note +package "knx" { +class BusAccessUnit [[class_bus_access_unit.html]] +class DeviceObject [[class_device_object.html]] +class BauSystemBCoupler [[class_bau_system_b.html]] +BusAccessUnit<|--BauSystemB +BauSystemB<|--BauSystemBCoupler +class ApplicationProgramObject [[class_application_program_object.html]] +BauSystemB*--ApplicationProgramObject +DeviceObject--*BauSystemB +class ApplicationLayer [[class_application_layer.html]] + +package knx-data-secure +{ +class SecureApplicationLayer [[class_secure_application_layer.html]] +class SecurityInterfaceObject [[class_security_interface_object.html]] +SecureApplicationLayer-->SecurityInterfaceObject +SecurityInterfaceObject-->SecureApplicationLayer +BauSystemBCoupler*--"SecurityInterfaceObject" +BauSystemBCoupler*--"SecureApplicationLayer" +} +BauSystemBCoupler*--"ApplicationLayer" +ApplicationLayer<|--SecureApplicationLayer +SecureApplicationLayer--*BauSystemBCoupler +class TransportLayer [[class_transport_layer.html]] +TransportLayer--*BauSystemBCoupler +class NetworkLayerEntity [[class_network_layer_entity.html]] +class NetworkLayerCoupler [[class_network_layer.html]] +{ +NetworkLayerEntity[] _networkLayerEntities +} +NetworkLayerCoupler*--"NetworkLayerEntity" +NetworkLayerCoupler--*BauSystemBCoupler +class DataLinkLayer [[class_data_link_layer.html]] +ApplicationLayer-->SecureApplicationLayer +SecureApplicationLayer-->ApplicationLayer +ApplicationLayer-->BusAccessUnit +ApplicationLayer-->TransportLayer +SecureApplicationLayer-->TransportLayer +TransportLayer-->ApplicationLayer +TransportLayer-->SecureApplicationLayer +TransportLayer-->NetworkLayerCoupler +NetworkLayerCoupler-->TransportLayer +NetworkLayerEntity-->DataLinkLayer +DataLinkLayer-->NetworkLayerEntity +SecureApplicationLayer-->DeviceObject +DataLinkLayer-->DeviceObject + +package knx-ip-tp +{ +class IpDataLinkLayer [[class_ip_data_link_layer.html]] +IpDataLinkLayer--|>DataLinkLayer +class TpUartDataLinkLayer [[class_tp_uart_data_link_layer.html]] +TpUartDataLinkLayer--|>DataLinkLayer +class Bau091A [[class_bau09_1a.html]] +Bau091A--|>BauSystemBCoupler +Bau091A*--IpDataLinkLayer +Bau091A*--TpUartDataLinkLayer +class RouterObject [[class_router_object.html]] +class IpParameterObject [[class_ip_parameter_object.html]] +IpParameterObject-->DeviceObject +Bau091A*--"RouterObject" +Bau091A*--IpParameterObject +IpDataLinkLayer-->IpParameterObject +} +} + +package platform +{ +class Platform [[class_platform.html]] +class ArduinoPlatform [[class_arduino_platform.html]] +class SamdPlatform [[class_samd_platform.html]] +Platform<|--ArduinoPlatform +ArduinoPlatform<|--SamdPlatform +class EspPlatform [[class_esp_platform.html]] +ArduinoPlatform<|--EspPlatform +class Esp32Platform [[class_esp32_platform.html]] +ArduinoPlatform<|--Esp32Platform +class Stm32Platform [[class_stm32_platform.html]] +ArduinoPlatform<|--Stm32Platform +class LinuxPlatform [[class_linux_platform.html]] +LinuxPlatform--|>Platform +} +package frontend +{ +class KnxFacade [[class_knx_facade.html]] +BauSystemBCoupler<--KnxFacade +} +knx-->Platform +@enduml + */ #include "knx_facade.h" diff --git a/src/knx/application_layer.cpp b/src/knx/application_layer.cpp index 36b2ce2..18094d0 100644 --- a/src/knx/application_layer.cpp +++ b/src/knx/application_layer.cpp @@ -10,8 +10,7 @@ const SecurityControl ApplicationLayer::noSecurity {.toolAccess=false, .dataSecurity=DataSecurity::none}; -ApplicationLayer::ApplicationLayer(AssociationTableObject& assocTable, BusAccessUnit& bau): - _assocTable(assocTable), _bau(bau) +ApplicationLayer::ApplicationLayer(BusAccessUnit& bau) : _bau(bau) { } @@ -20,6 +19,11 @@ void ApplicationLayer::transportLayer(TransportLayer& layer) _transportLayer = &layer; } +void ApplicationLayer::associationTableObject(AssociationTableObject& assocTable) +{ + _assocTable = &assocTable; +} + #pragma region TL Callbacks void ApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) @@ -29,6 +33,9 @@ void ApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priori void ApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) { + if (_assocTable == nullptr) + return; + uint8_t len = apdu.length(); uint8_t dataArray[len]; uint8_t* data = dataArray; @@ -45,8 +52,8 @@ 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)) + int32_t asap = _assocTable->nextAsap(tsap, startIdx); + for (; asap != -1; asap = _assocTable->nextAsap(tsap, startIdx)) { switch (apdu.type()) { @@ -135,14 +142,8 @@ void ApplicationLayer::dataBroadcastIndication(HopCountType hopType, Priority pr break; } default: -#if (MEDIUM_TYPE == 5)||(MEDIUM_TYPE == 0) - // Make sure we also check if it is a service normally available only on SystemBroadcast on open media - dataSystemBroadcastIndication(hopType, priority, source, apdu, secCtrl); -#else print("Broadcast-indication: unhandled APDU-Type: "); println(apdu.type()); - -#endif break; } } @@ -188,14 +189,8 @@ void ApplicationLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, P break; } default: -#if (MEDIUM_TYPE == 5)||(MEDIUM_TYPE == 0) - // Make sure we also check if it is a service normally available only on SystemBroadcast on open media - dataSystemBroadcastConfirm(hopType, priority, apdu, secCtrl, status); -#else print("Broadcast-confirm: unhandled APDU-Type: "); println(apdu.type()); - -#endif break; } } @@ -239,11 +234,7 @@ void ApplicationLayer::dataSystemBroadcastIndication(HopCountType hopType, Prior break; } default: -#if (MEDIUM_TYPE == 5)||(MEDIUM_TYPE == 0) - print("Broadcast-indication: unhandled APDU-Type: "); -#else print("SystemBroadcast-indication: unhandled APDU-Type: "); -#endif println(apdu.type()); break; } @@ -287,11 +278,7 @@ void ApplicationLayer::dataSystemBroadcastConfirm(HopCountType hopType, Priority break; } default: -#if (MEDIUM_TYPE == 5)||(MEDIUM_TYPE == 0) - print("Broadcast-confirm: unhandled APDU-Type: "); -#else print("SystemBroadcast-confirm: unhandled APDU-Type: "); -#endif println(apdu.type()); break; } @@ -365,12 +352,15 @@ void ApplicationLayer::dataConnectedConfirm(uint16_t tsap, const SecurityControl #pragma endregion void ApplicationLayer::groupValueReadRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl) { + if (_assocTable == nullptr) + return; + _savedAsapReadRequest = asap; CemiFrame frame(1); APDU& apdu = frame.apdu(); apdu.type(GroupValueRead); - int32_t value = _assocTable.translateAsap(asap); + int32_t value = _assocTable->translateAsap(asap); if (value < 0) return; // there is no tsap in association table for this asap @@ -742,25 +732,6 @@ void ApplicationLayer::memoryExtReadResponse(AckType ack, Priority priority, Hop individualSend(ack, hopType, priority, asap, apdu, secCtrl); } -uint16_t ApplicationLayer::crc16Ccitt(uint8_t* input, uint16_t length) -{ - uint32_t polynom = 0x1021; - uint8_t padded[length+2]; - - memcpy(padded, input, length); - memset(padded+length, 0x00, 2); - - uint32_t result = 0xffff; - for (uint32_t i = 0; i < 8 * (uint32_t)sizeof(padded); i++) { - result <<= 1; - uint32_t nextBit = (padded[i / 8] >> (7 - (i % 8))) & 0x1; - result |= nextBit; - if ((result & 0x10000) != 0) - result ^= polynom; - } - return result & 0xffff; -} - 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) { @@ -777,7 +748,7 @@ void ApplicationLayer::memoryExtWriteResponse(AckType ack, Priority priority, Ho if (withCrc) { - uint16_t crc = crc16Ccitt(memoryData, number); // TODO + uint16_t crc = crc16Ccitt(memoryData, number); data[5] = crc >> 8; data[6] = crc & 0xFF; } @@ -928,6 +899,9 @@ void ApplicationLayer::propertyExtDataSend(ApduType type, AckType ack, Priority 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; + CemiFrame frame(dataLength + 1); APDU& apdu = frame.apdu(); apdu.type(type); @@ -943,7 +917,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 trough - uint16_t tsap = (uint16_t)_assocTable.translateAsap(asap); + uint16_t tsap = (uint16_t)_assocTable->translateAsap(asap); dataGroupRequest(ack, hopType, priority, tsap, apdu, secCtrl); dataGroupIndication(hopType, priority, tsap, apdu, secCtrl); } diff --git a/src/knx/application_layer.h b/src/knx/application_layer.h index 4234716..73832e2 100644 --- a/src/knx/application_layer.h +++ b/src/knx/application_layer.h @@ -22,12 +22,14 @@ class ApplicationLayer * @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(AssociationTableObject& assocTable, BusAccessUnit& bau); + ApplicationLayer(BusAccessUnit& bau); /** * Assigns the TransportLayer to which encoded APDU are submitted to. */ void transportLayer(TransportLayer& layer); + void associationTableObject(AssociationTableObject& assocTable); + // from transport layer // Note: without data secure feature, the application layer is just used with SecurtyControl.dataSecurity = none // hooks that can be implemented by derived class (e.g. SecureApplicationLayer) @@ -199,12 +201,10 @@ class ApplicationLayer 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 crc16Ccitt(uint8_t* input, uint16_t length); - uint16_t _savedAsapReadRequest; uint16_t _savedAsapWriteRequest; uint16_t _savedAsapResponse; - AssociationTableObject& _assocTable; + AssociationTableObject* _assocTable = nullptr; BusAccessUnit& _bau; int32_t _connectedTsap = -1; diff --git a/src/knx/bau07B0.cpp b/src/knx/bau07B0.cpp index 47c4f34..279ee11 100644 --- a/src/knx/bau07B0.cpp +++ b/src/knx/bau07B0.cpp @@ -1,21 +1,23 @@ +#include "config.h" +#if MASK_VERSION == 0x07B0 + #include "bau07B0.h" #include "bits.h" #include #include -#ifdef USE_TP - using namespace std; Bau07B0::Bau07B0(Platform& platform) - : BauSystemB(platform), - _dlLayer(_deviceObj, _addrTable, _netLayer, _platform) + : BauSystemBDevice(platform), + _dlLayer(_deviceObj, _netLayer.getInterface(), _platform, (ITpUartCallBacks&) *this) #ifdef USE_CEMI_SERVER , _cemiServer(*this) #endif { - _netLayer.dataLinkLayer(_dlLayer); + _netLayer.getInterface().dataLinkLayer(_dlLayer); #ifdef USE_CEMI_SERVER + _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_TP1); _cemiServer.dataLinkLayer(_dlLayer); _dlLayer.cemiServer(_cemiServer); _memory.addSaveRestore(&_cemiServerObject); @@ -106,17 +108,41 @@ InterfaceObject* Bau07B0::getInterfaceObject(ObjectType objectType, uint8_t obje } } -DataLinkLayer& Bau07B0::dataLinkLayer() +bool Bau07B0::enabled() { - return _dlLayer; + return _dlLayer.enabled(); +} + +void Bau07B0::enabled(bool value) +{ + _dlLayer.enabled(value); } void Bau07B0::loop() { - ::BauSystemB::loop(); + _dlLayer.loop(); + BauSystemBDevice::loop(); #ifdef USE_CEMI_SERVER _cemiServer.loop(); #endif } +bool Bau07B0::isAckRequired(uint16_t address, bool isGrpAddr) +{ + if (isGrpAddr) + { + // ACK for broadcasts + if (address == 0) + return true; + // is group address in group address table? ACK if yes. + return _addrTable.contains(address); + } + + // Also ACK for our own individual address + if (address == _deviceObj.induvidualAddress()) + return true; + + return false; +} + #endif diff --git a/src/knx/bau07B0.h b/src/knx/bau07B0.h index a886d17..7828e41 100644 --- a/src/knx/bau07B0.h +++ b/src/knx/bau07B0.h @@ -1,23 +1,27 @@ #pragma once #include "config.h" -#include "bau_systemB.h" +#if MASK_VERSION == 0x07B0 + +#include "bau_systemB_device.h" #include "tpuart_data_link_layer.h" #include "cemi_server.h" #include "cemi_server_object.h" -#ifdef USE_TP - -class Bau07B0 : public BauSystemB +class Bau07B0 : public BauSystemBDevice, public ITpUartCallBacks { public: Bau07B0(Platform& platform); - void loop(); + virtual void loop() override; + virtual bool enabled() override; + virtual void enabled(bool value) override; protected: InterfaceObject* getInterfaceObject(uint8_t idx); InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance); - DataLinkLayer& dataLinkLayer(); + + // For TP1 only + virtual bool isAckRequired(uint16_t address, bool isGrpAddr) override; private: TpUartDataLinkLayer _dlLayer; @@ -26,4 +30,4 @@ class Bau07B0 : public BauSystemB CemiServerObject _cemiServerObject; #endif }; -#endif \ No newline at end of file +#endif diff --git a/src/knx/bau091A.cpp b/src/knx/bau091A.cpp new file mode 100644 index 0000000..9774952 --- /dev/null +++ b/src/knx/bau091A.cpp @@ -0,0 +1,169 @@ +#include "config.h" +#if MASK_VERSION == 0x091A + +#include "bau091A.h" +#include "bits.h" +#include +#include + +using namespace std; + +Bau091A::Bau091A(Platform& platform) + : BauSystemBCoupler(platform), + _routerObj(memory()), + _ipParameters(_deviceObj, platform), + _dlLayerPrimary(_deviceObj, _ipParameters, _netLayer.getPrimaryInterface(), _platform), + _dlLayerSecondary(_deviceObj, _netLayer.getSecondaryInterface(), platform, (ITpUartCallBacks&) *this) +#ifdef USE_CEMI_SERVER + , + _cemiServer(*this) +#endif +{ + // Before accessing anything of the router object they have to be initialized according to the used medium + // Coupler model 1.x + _routerObj.initialize1x(DptMedium::KNX_IP, 220); + + // Mask 091A uses older coupler model 1.x which only uses one router object + _netLayer.rtObj(_routerObj); + + _netLayer.getPrimaryInterface().dataLinkLayer(_dlLayerPrimary); + _netLayer.getSecondaryInterface().dataLinkLayer(_dlLayerSecondary); + +#ifdef USE_CEMI_SERVER + _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_IP); + _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_TP1); + _cemiServer.dataLinkLayer(_dlLayerSecondary); // Secondary I/F is the important one! + _dlLayerSecondary.cemiServer(_cemiServer); + _memory.addSaveRestore(&_cemiServerObject); +#endif + + _memory.addSaveRestore(&_routerObj); + + _memory.addSaveRestore(&_ipParameters); + + // Set Mask Version in Device Object depending on the BAU + _deviceObj.maskVersion(0x091A); + + // Set which interface objects are available in the device object + // This differs from BAU to BAU with different medium types. + // See PID_IO_LIST + Property* prop = _deviceObj.property(PID_IO_LIST); + prop->write(1, (uint16_t) OT_DEVICE); + prop->write(2, (uint16_t) OT_ROUTER); + prop->write(3, (uint16_t) OT_APPLICATION_PROG); + prop->write(4, (uint16_t) OT_IP_PARAMETER); +#if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER) + prop->write(5, (uint16_t) OT_SECURITY); + prop->write(6, (uint16_t) OT_CEMI_SERVER); +#elif defined(USE_DATASECURE) + prop->write(5, (uint16_t) OT_SECURITY); +#elif defined(USE_CEMI_SERVER) + prop->write(5, (uint16_t) OT_CEMI_SERVER); +#endif +} + +InterfaceObject* Bau091A::getInterfaceObject(uint8_t idx) +{ + switch (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; + } +} + +InterfaceObject* Bau091A::getInterfaceObject(ObjectType objectType, uint8_t objectInstance) +{ + // We do not use it right now. + // Required for coupler mode as there are multiple router objects for example + (void) objectInstance; + + switch (objectType) + { + 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; + } +} + +void Bau091A::doMasterReset(EraseCode eraseCode, uint8_t channel) +{ + // Common SystemB objects + BauSystemBCoupler::doMasterReset(eraseCode, channel); + + _ipParameters.masterReset(eraseCode, channel); + _routerObj.masterReset(eraseCode, channel); +} + +bool Bau091A::enabled() +{ + return _dlLayerPrimary.enabled() && _dlLayerSecondary.enabled(); +} + +void Bau091A::enabled(bool value) +{ + _dlLayerPrimary.enabled(value); + _dlLayerSecondary.enabled(value); +} + +void Bau091A::loop() +{ + _dlLayerPrimary.loop(); + _dlLayerSecondary.loop(); + BauSystemBCoupler::loop(); +} + +bool Bau091A::isAckRequired(uint16_t address, bool isGrpAddr) +{ + if (isGrpAddr) + { + // ACK for broadcasts + if (address == 0) + return true; + + // is group address in filter table? ACK if yes. + return _routerObj.isGroupAddressInFilterTable(address); + } + else + { + return _netLayer.isRoutedIndividualAddress(address); + } + + return false; +} + +#endif diff --git a/src/knx/bau091A.h b/src/knx/bau091A.h new file mode 100644 index 0000000..262055b --- /dev/null +++ b/src/knx/bau091A.h @@ -0,0 +1,39 @@ +#pragma once + +#include "config.h" +#if MASK_VERSION == 0x091A + +#include "bau_systemB_coupler.h" +#include "router_object.h" +#include "ip_parameter_object.h" +#include "ip_data_link_layer.h" +#include "tpuart_data_link_layer.h" +#include "cemi_server_object.h" + +class Bau091A : public BauSystemBCoupler, public ITpUartCallBacks +{ + public: + Bau091A(Platform& platform); + virtual void loop() override; + virtual bool enabled() override; + virtual void enabled(bool value) override; + + protected: + InterfaceObject* getInterfaceObject(uint8_t idx); + InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance); + + // For TP1 only + virtual bool isAckRequired(uint16_t address, bool isGrpAddr) override; + + virtual 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; +#endif +}; +#endif diff --git a/src/knx/bau27B0.cpp b/src/knx/bau27B0.cpp index 0ef567a..9b119f9 100644 --- a/src/knx/bau27B0.cpp +++ b/src/knx/bau27B0.cpp @@ -1,5 +1,7 @@ +#include "config.h" +#if MASK_VERSION == 0x27B0 + #include "bau27B0.h" -#ifdef USE_RF #include "bits.h" #include #include @@ -7,15 +9,16 @@ using namespace std; Bau27B0::Bau27B0(Platform& platform) - : BauSystemB(platform), - _dlLayer(_deviceObj, _rfMediumObj, _addrTable, _netLayer, _platform) + : BauSystemBDevice(platform), + _dlLayer(_deviceObj, _rfMediumObj, _netLayer.getInterface(), _platform) #ifdef USE_CEMI_SERVER , _cemiServer(*this) #endif { - _netLayer.dataLinkLayer(_dlLayer); + _netLayer.getInterface().dataLinkLayer(_dlLayer); _memory.addSaveRestore(&_rfMediumObj); #ifdef USE_CEMI_SERVER + _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_RF); _cemiServer.dataLinkLayer(_dlLayer); _dlLayer.cemiServer(_cemiServer); _memory.addSaveRestore(&_cemiServerObject); @@ -128,14 +131,20 @@ void Bau27B0::doMasterReset(EraseCode eraseCode, uint8_t channel) _rfMediumObj.masterReset(eraseCode, channel); } -DataLinkLayer& Bau27B0::dataLinkLayer() +bool Bau27B0::enabled() { - return _dlLayer; + return _dlLayer.enabled(); +} + +void Bau27B0::enabled(bool value) +{ + _dlLayer.enabled(value); } void Bau27B0::loop() { - ::BauSystemB::loop(); + _dlLayer.loop(); + BauSystemBDevice::loop(); #ifdef USE_CEMI_SERVER _cemiServer.loop(); #endif diff --git a/src/knx/bau27B0.h b/src/knx/bau27B0.h index 63f2844..8659fac 100644 --- a/src/knx/bau27B0.h +++ b/src/knx/bau27B0.h @@ -1,24 +1,26 @@ #pragma once #include "config.h" -#ifdef USE_RF -#include "bau_systemB.h" +#if MASK_VERSION == 0x27B0 + +#include "bau_systemB_device.h" #include "rf_medium_object.h" #include "rf_physical_layer.h" #include "rf_data_link_layer.h" #include "cemi_server.h" #include "cemi_server_object.h" -class Bau27B0 : public BauSystemB +class Bau27B0 : public BauSystemBDevice { public: Bau27B0(Platform& platform); - void loop(); + virtual void loop() override; + virtual bool enabled() override; + virtual void enabled(bool value) override; protected: InterfaceObject* getInterfaceObject(uint8_t idx); InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance); - DataLinkLayer& dataLinkLayer(); virtual void doMasterReset(EraseCode eraseCode, uint8_t channel) override; private: diff --git a/src/knx/bau2920.cpp b/src/knx/bau2920.cpp new file mode 100644 index 0000000..f5e5367 --- /dev/null +++ b/src/knx/bau2920.cpp @@ -0,0 +1,157 @@ +#include "config.h" +#if MASK_VERSION == 0x2920 + +#include "bau2920.h" +#include "bits.h" +#include +#include + +using namespace std; + +// Mask 0x2920 uses coupler model 2.0 +Bau2920::Bau2920(Platform& platform) + : BauSystemBCoupler(platform), + _rtObjPrimary(memory()), + _rtObjSecondary(memory()), + _rfMediumObject(), + _dlLayerPrimary(_deviceObj, _netLayer.getPrimaryInterface(), _platform, (ITpUartCallBacks&) *this), + _dlLayerSecondary(_deviceObj, _rfMediumObject, _netLayer.getSecondaryInterface(), platform) +#ifdef USE_CEMI_SERVER + , + _cemiServer(*this) +#endif +{ + // Before accessing anything of the two router objects they have to be initialized according to the used media combination + // Coupler model 2.0 + _rtObjPrimary.initialize20(1, DptMedium::KNX_TP1, RouterObjectType::Primary, 201); + _rtObjSecondary.initialize20(2, DptMedium::KNX_RF, RouterObjectType::Secondary, 201); + + _netLayer.rtObjPrimary(_rtObjPrimary); + _netLayer.rtObjSecondary(_rtObjSecondary); + _netLayer.getPrimaryInterface().dataLinkLayer(_dlLayerPrimary); + _netLayer.getSecondaryInterface().dataLinkLayer(_dlLayerSecondary); + +#ifdef USE_CEMI_SERVER + _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_TP1); + _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_RF); + _cemiServer.dataLinkLayer(_dlLayerSecondary); // Secondary I/F is the important one! + _dlLayerSecondary.cemiServer(_cemiServer); + _memory.addSaveRestore(&_cemiServerObject); +#endif + + _memory.addSaveRestore(&_rtObjPrimary); + _memory.addSaveRestore(&_rtObjSecondary); + + _memory.addSaveRestore(&_rfMediumObject); + + // Set Mask Version in Device Object depending on the BAU + _deviceObj.maskVersion(0x2920); + + // Set which interface objects are available in the device object + // This differs from BAU to BAU with different medium types. + // See PID_IO_LIST + Property* prop = _deviceObj.property(PID_IO_LIST); + prop->write(1, (uint16_t) OT_DEVICE); + prop->write(2, (uint16_t) OT_ROUTER); + prop->write(3, (uint16_t) OT_ROUTER); + prop->write(4, (uint16_t) OT_APPLICATION_PROG); + prop->write(5, (uint16_t) OT_RF_MEDIUM); +#if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER) + prop->write(6, (uint16_t) OT_SECURITY); + prop->write(7, (uint16_t) OT_CEMI_SERVER); +#elif defined(USE_DATASECURE) + prop->write(6, (uint16_t) OT_SECURITY); +#elif defined(USE_CEMI_SERVER) + prop->write(6, (uint16_t) OT_CEMI_SERVER); +#endif +} + +InterfaceObject* Bau2920::getInterfaceObject(uint8_t idx) +{ + switch (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; + } +} + +InterfaceObject* Bau2920::getInterfaceObject(ObjectType objectType, uint8_t objectInstance) +{ + // We do not use it right now. + // Required for coupler mode as there are multiple router objects for example + (void) objectInstance; + + switch (objectType) + { + 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; + } +} + +void Bau2920::doMasterReset(EraseCode eraseCode, uint8_t channel) +{ + // Common SystemB objects + BauSystemBCoupler::doMasterReset(eraseCode, channel); + + _rfMediumObject.masterReset(eraseCode, channel); + _rtObjPrimary.masterReset(eraseCode, channel); + _rtObjSecondary.masterReset(eraseCode, channel); +} + +bool Bau2920::enabled() +{ + return _dlLayerPrimary.enabled() && _dlLayerSecondary.enabled(); +} + +void Bau2920::enabled(bool value) +{ + _dlLayerPrimary.enabled(value); + _dlLayerSecondary.enabled(value); +} + +void Bau2920::loop() +{ + _dlLayerPrimary.loop(); + _dlLayerSecondary.loop(); + BauSystemBCoupler::loop(); +} + +#endif diff --git a/src/knx/bau2920.h b/src/knx/bau2920.h new file mode 100644 index 0000000..539d07e --- /dev/null +++ b/src/knx/bau2920.h @@ -0,0 +1,37 @@ +#pragma once + +#include "config.h" +#if MASK_VERSION == 0x2920 + +#include "bau_systemB_coupler.h" +#include "tpuart_data_link_layer.h" +#include "rf_physical_layer.h" +#include "rf_data_link_layer.h" +#include "rf_medium_object.h" +#include "cemi_server_object.h" + +class Bau2920 : public BauSystemBCoupler +{ + public: + Bau2920(Platform& platform); + virtual void loop() override; + virtual bool enabled() override; + virtual void enabled(bool value) override; + + protected: + InterfaceObject* getInterfaceObject(uint8_t idx); + InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance); + + virtual 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; +#endif +}; +#endif diff --git a/src/knx/bau57B0.cpp b/src/knx/bau57B0.cpp index eee3cc2..c9b3827 100644 --- a/src/knx/bau57B0.cpp +++ b/src/knx/bau57B0.cpp @@ -1,24 +1,25 @@ #include "config.h" +#if MASK_VERSION == 0x57B0 + #include "bau57B0.h" #include "bits.h" #include #include -#ifdef USE_IP - using namespace std; Bau57B0::Bau57B0(Platform& platform) - : BauSystemB(platform), + : BauSystemBDevice(platform), _ipParameters(_deviceObj, platform), - _dlLayer(_deviceObj, _addrTable, _ipParameters, _netLayer, _platform) + _dlLayer(_deviceObj, _ipParameters, _netLayer.getInterface(), _platform) #ifdef USE_CEMI_SERVER , _cemiServer(*this) #endif { - _netLayer.dataLinkLayer(_dlLayer); + _netLayer.getInterface().dataLinkLayer(_dlLayer); #ifdef USE_CEMI_SERVER + _cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_IP); _cemiServer.dataLinkLayer(_dlLayer); _dlLayer.cemiServer(_cemiServer); _memory.addSaveRestore(&_cemiServerObject); @@ -124,9 +125,23 @@ void Bau57B0::doMasterReset(EraseCode eraseCode, uint8_t channel) _ipParameters.masterReset(eraseCode, channel); } -DataLinkLayer& Bau57B0::dataLinkLayer() +bool Bau57B0::enabled() { - return _dlLayer; + return _dlLayer.enabled(); +} + +void Bau57B0::enabled(bool value) +{ + _dlLayer.enabled(value); +} + +void Bau57B0::loop() +{ + _dlLayer.loop(); + BauSystemBDevice::loop(); +#ifdef USE_CEMI_SERVER + _cemiServer.loop(); +#endif } #endif diff --git a/src/knx/bau57B0.h b/src/knx/bau57B0.h index 85c5ca0..3c017c1 100644 --- a/src/knx/bau57B0.h +++ b/src/knx/bau57B0.h @@ -1,21 +1,24 @@ #pragma once #include "config.h" -#ifdef USE_IP -#include "bau_systemB.h" +#if MASK_VERSION == 0x57B0 + +#include "bau_systemB_device.h" #include "ip_parameter_object.h" #include "ip_data_link_layer.h" #include "cemi_server_object.h" -class Bau57B0 : public BauSystemB +class Bau57B0 : public BauSystemBDevice { public: Bau57B0(Platform& platform); + virtual void loop() override; + virtual bool enabled() override; + virtual void enabled(bool value) override; protected: InterfaceObject* getInterfaceObject(uint8_t idx); InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance); - DataLinkLayer& dataLinkLayer(); virtual void doMasterReset(EraseCode eraseCode, uint8_t channel) override; private: diff --git a/src/knx/bau_systemB.cpp b/src/knx/bau_systemB.cpp index 8d20f59..a94cf29 100644 --- a/src/knx/bau_systemB.cpp +++ b/src/knx/bau_systemB.cpp @@ -14,119 +14,11 @@ enum NmReadSerialNumberType static constexpr auto kFunctionPropertyResultBufferMaxSize = 64; static constexpr auto kRestartProcessTime = 3; -BauSystemB::BauSystemB(Platform& platform): _memory(platform, _deviceObj), _addrTable(_memory), - _assocTable(_memory), _groupObjTable(_memory), _appProgram(_memory), - _platform(platform), -#ifdef USE_DATASECURE - _appLayer(_deviceObj, _secIfObj, _assocTable, _addrTable, *this), -#else - _appLayer(_assocTable, *this), -#endif - _transLayer(_appLayer, _addrTable), _netLayer(_transLayer) +BauSystemB::BauSystemB(Platform& platform): _memory(platform, _deviceObj), + _appProgram(_memory), + _platform(platform) { -#ifdef USE_DATASECURE - _secIfObj.secureApplicationLayer(_appLayer); -#endif - _appLayer.transportLayer(_transLayer); - _transLayer.networkLayer(_netLayer); - _memory.addSaveRestore(&_deviceObj); _memory.addSaveRestore(&_appProgram); - _memory.addSaveRestore(&_addrTable); - _memory.addSaveRestore(&_assocTable); - _memory.addSaveRestore(&_groupObjTable); -#ifdef USE_DATASECURE - _memory.addSaveRestore(&_secIfObj); -#endif - -} - -void BauSystemB::loop() -{ - dataLinkLayer().loop(); - _transLayer.loop(); - sendNextGroupTelegram(); - nextRestartState(); -#ifdef USE_DATASECURE - _appLayer.loop(); -#endif -} - -bool BauSystemB::enabled() -{ - return dataLinkLayer().enabled(); -} - -void BauSystemB::enabled(bool value) -{ - dataLinkLayer().enabled(value); -} - -void BauSystemB::sendNextGroupTelegram() -{ - if(!configured()) - return; - - static uint16_t startIdx = 1; - - GroupObjectTableObject& table = _groupObjTable; - uint16_t objCount = table.entryCount(); - - for (uint16_t asap = startIdx; asap <= objCount; asap++) - { - GroupObject& go = table.get(asap); - - ComFlag flag = go.commFlag(); - if (flag != ReadRequest && flag != WriteRequest) - continue; - - if (!go.communicationEnable()) - continue; - - SecurityControl goSecurity; - goSecurity.toolAccess = false; // Secured group communication never uses the toolkey. ETS knows all keys, also the group keys. - -#ifdef USE_DATASECURE - // Get security flags from Security Interface Object for this group object - goSecurity.dataSecurity = _secIfObj.getGroupObjectSecurity(asap); -#else - goSecurity.dataSecurity = DataSecurity::none; -#endif - - if (flag == WriteRequest && go.transmitEnable()) - { - uint8_t* data = go.valueRef(); - _appLayer.groupValueWriteRequest(AckRequested, asap, go.priority(), NetworkLayerParameter, goSecurity, data, - go.sizeInTelegram()); - } - else if (flag == ReadRequest) - { - _appLayer.groupValueReadRequest(AckRequested, asap, go.priority(), NetworkLayerParameter, goSecurity); - } - - go.commFlag(Transmitting); - - startIdx = asap + 1; - return; - } - - startIdx = 1; -} - -void BauSystemB::updateGroupObject(GroupObject & go, uint8_t * data, uint8_t length) -{ - uint8_t* goData = go.valueRef(); - if (length != go.valueSize()) - { - go.commFlag(Error); - return; - } - - memcpy(goData, data, length); - - go.commFlag(Updated); - GroupObjectUpdatedHandler handler = go.callback(); - if (handler) - handler(go); } void BauSystemB::readMemory() @@ -139,34 +31,14 @@ void BauSystemB::writeMemory() _memory.writeMemory(); } -DeviceObject& BauSystemB::deviceObject() -{ - return _deviceObj; -} - -GroupObjectTableObject& BauSystemB::groupObjectTable() -{ - return _groupObjTable; -} - ApplicationProgramObject& BauSystemB::parameters() { return _appProgram; } -bool BauSystemB::configured() +DeviceObject& BauSystemB::deviceObject() { - // _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; - - return _configured; + return _deviceObj; } uint8_t BauSystemB::checkmasterResetValidity(EraseCode eraseCode, uint8_t channel) @@ -233,7 +105,7 @@ void BauSystemB::deviceDescriptorReadIndication(Priority priority, HopCountType uint8_t data[2]; pushWord(_deviceObj.maskVersion(), data); - _appLayer.deviceDescriptorReadResponse(AckRequested, priority, hopType, asap, secCtrl, descriptorType, data); + applicationLayer().deviceDescriptorReadResponse(AckRequested, priority, hopType, asap, secCtrl, descriptorType, data); } void BauSystemB::memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number, @@ -248,7 +120,7 @@ void BauSystemB::memoryWriteIndication(Priority priority, HopCountType hopType, void BauSystemB::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number, uint16_t memoryAddress) { - _appLayer.memoryReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, + applicationLayer().memoryReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, _memory.toAbsolute(memoryAddress)); } @@ -256,27 +128,18 @@ void BauSystemB::memoryExtWriteIndication(Priority priority, HopCountType hopTyp { _memory.writeMemory(memoryAddress, number, data); - _appLayer.memoryExtWriteResponse(AckRequested, priority, hopType, asap, secCtrl, ReturnCodes::Success, number, memoryAddress, _memory.toAbsolute(memoryAddress)); + 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) { - _appLayer.memoryExtReadResponse(AckRequested, priority, hopType, asap, secCtrl, ReturnCodes::Success, number, memoryAddress, _memory.toAbsolute(memoryAddress)); + applicationLayer().memoryExtReadResponse(AckRequested, priority, hopType, asap, secCtrl, ReturnCodes::Success, number, memoryAddress, _memory.toAbsolute(memoryAddress)); } void BauSystemB::doMasterReset(EraseCode eraseCode, uint8_t channel) { - _addrTable.masterReset(eraseCode, channel); - _assocTable.masterReset(eraseCode, channel); - _groupObjTable.masterReset(eraseCode, channel); + _deviceObj.masterReset(eraseCode, channel); _appProgram.masterReset(eraseCode, channel); -#ifdef USE_DATASECURE - // If erase code is FactoryReset or FactoryResetWithoutIA, set FDSK as toolkey again - // and disable security mode. - // FIXME: the A_RestartResponse PDU has still to be sent with the current toolkey. - // Idea: use local confirmation of sent A_RestartResponse PDU to trigger writing the FDSK afterwards - _secIfObj.masterReset(eraseCode, channel); -#endif } void BauSystemB::restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, RestartType restartType, EraseCode eraseCode, uint8_t channel) @@ -290,7 +153,7 @@ void BauSystemB::restartRequestIndication(Priority priority, HopCountType hopTyp uint8_t errorCode = checkmasterResetValidity(eraseCode, channel); // We send the restart response now before actually applying the reset values // Processing time is kRestartProcessTime (example 3 seconds) that we require for the applying the master reset with restart - _appLayer.restartResponse(AckRequested, priority, hopType, secCtrl, errorCode, (errorCode == 0) ? kRestartProcessTime : 0); + applicationLayer().restartResponse(AckRequested, priority, hopType, secCtrl, errorCode, (errorCode == 0) ? kRestartProcessTime : 0); doMasterReset(eraseCode, channel); } else @@ -307,12 +170,12 @@ void BauSystemB::restartRequestIndication(Priority priority, HopCountType hopTyp void BauSystemB::authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint32_t key) { - _appLayer.authorizeResponse(AckRequested, priority, hopType, asap, secCtrl, 0); + 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) { - _appLayer.userMemoryReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, + applicationLayer().userMemoryReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, _memory.toAbsolute(memoryAddress)); } @@ -336,7 +199,7 @@ void BauSystemB::propertyDescriptionReadIndication(Priority priority, HopCountTy if (obj) obj->readPropertyDescription(pid, propertyIndex, writeEnable, type, numberOfElements, access); - _appLayer.propertyDescriptionReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, pid, propertyIndex, + applicationLayer().propertyDescriptionReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, pid, propertyIndex, writeEnable, type, numberOfElements, access); } @@ -362,7 +225,7 @@ void BauSystemB::propertyValueExtWriteIndication(Priority priority, HopCountType if (confirmed) { - _appLayer.propertyValueExtWriteConResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, numberOfElements, startIndex, returnCode); + applicationLayer().propertyValueExtWriteConResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, numberOfElements, startIndex, returnCode); } } @@ -390,7 +253,7 @@ void BauSystemB::propertyValueReadIndication(Priority priority, HopCountType hop if (elementCount == 0) size = 0; - _appLayer.propertyValueReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, propertyId, elementCount, + applicationLayer().propertyValueReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, propertyId, elementCount, startIndex, data, size); } @@ -418,7 +281,7 @@ void BauSystemB::propertyValueExtReadIndication(Priority priority, HopCountType if (elementCount == 0) size = 0; - _appLayer.propertyValueExtReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, elementCount, + applicationLayer().propertyValueExtReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, elementCount, startIndex, data, size); } @@ -441,7 +304,7 @@ void BauSystemB::functionPropertyCommandIndication(Priority priority, HopCountTy } } - _appLayer.functionPropertyStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, propertyId, resultData, resultLength); + 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, @@ -463,7 +326,7 @@ void BauSystemB::functionPropertyStateIndication(Priority priority, HopCountType } } - _appLayer.functionPropertyStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, propertyId, resultData, resultLength); + 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, @@ -519,7 +382,7 @@ void BauSystemB::functionPropertyExtCommandIndication(Priority priority, HopCoun resultData[0] = ReturnCodes::GenericError; } - _appLayer.functionPropertyExtStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, resultData, resultLength); + 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, @@ -566,13 +429,13 @@ void BauSystemB::functionPropertyExtStateIndication(Priority priority, HopCountT resultData[0] = ReturnCodes::GenericError; } - _appLayer.functionPropertyExtStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, resultData, resultLength); + applicationLayer().functionPropertyExtStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, resultData, resultLength); } void BauSystemB::individualAddressReadIndication(HopCountType hopType, const SecurityControl &secCtrl) { if (_deviceObj.progMode()) - _appLayer.individualAddressReadResponse(AckRequested, hopType, secCtrl); + applicationLayer().individualAddressReadResponse(AckRequested, hopType, secCtrl); } void BauSystemB::individualAddressWriteIndication(HopCountType hopType, const SecurityControl &secCtrl, uint16_t newaddress) @@ -598,85 +461,10 @@ void BauSystemB::individualAddressSerialNumberReadIndication(Priority priority, if (!memcmp(knxSerialNumber, _deviceObj.propertyData(PID_SERIAL_NUMBER), 6)) { uint8_t emptyDomainAddress[6] = {0x00}; - _appLayer.IndividualAddressSerialNumberReadResponse(priority, hopType, secCtrl, emptyDomainAddress, knxSerialNumber); + applicationLayer().IndividualAddressSerialNumberReadResponse(priority, hopType, secCtrl, emptyDomainAddress, knxSerialNumber); } } -void BauSystemB::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 BauSystemB::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 BauSystemB::groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl &secCtrl) -{ -#ifdef USE_DATASECURE - DataSecurity requiredGoSecurity; - - // Get security flags from Security Interface Object for this group object - requiredGoSecurity = _secIfObj.getGroupObjectSecurity(asap); - - if (secCtrl.dataSecurity != requiredGoSecurity) - { - println("GroupValueRead: access denied due to wrong security flags"); - return; - } -#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 BauSystemB::groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl &secCtrl, uint8_t* data, - uint8_t dataLength) -{ - GroupObject& go = _groupObjTable.get(asap); - - if (!go.communicationEnable() || !go.responseUpdateEnable()) - return; - - updateGroupObject(go, data, dataLength); -} - -void BauSystemB::groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl &secCtrl, uint8_t * data, uint8_t dataLength) -{ -#ifdef USE_DATASECURE - DataSecurity requiredGoSecurity; - - // Get security flags from Security Interface Object for this group object - requiredGoSecurity = _secIfObj.getGroupObjectSecurity(asap); - - if (secCtrl.dataSecurity != requiredGoSecurity) - { - println("GroupValueWrite: access denied due to wrong security flags"); - return; - } -#endif - GroupObject& go = _groupObjTable.get(asap); - - if (!go.communicationEnable() || !go.writeEnable()) - return; - - updateGroupObject(go, data, dataLength); -} - void BauSystemB::addSaveRestore(SaveRestore* obj) { _memory.addSaveRestore(obj); @@ -684,12 +472,12 @@ void BauSystemB::addSaveRestore(SaveRestore* obj) bool BauSystemB::restartRequest(uint16_t asap, const SecurityControl secCtrl) { - if (_appLayer.isConnected()) + if (applicationLayer().isConnected()) return false; _restartState = Connecting; // order important, has to be set BEFORE connectRequest _restartSecurity = secCtrl; - _appLayer.connectRequest(asap, SystemPriority); - _appLayer.deviceDescriptorReadRequest(AckRequested, SystemPriority, NetworkLayerParameter, asap, secCtrl, 0); + applicationLayer().connectRequest(asap, SystemPriority); + applicationLayer().deviceDescriptorReadRequest(AckRequested, SystemPriority, NetworkLayerParameter, asap, secCtrl, 0); return true; } @@ -721,7 +509,7 @@ void BauSystemB::nextRestartState() /* connection confirmed, we send restartRequest, but we wait a moment (sending ACK etc)... */ if (millis() - _restartDelay > 30) { - _appLayer.restartRequest(AckRequested, SystemPriority, NetworkLayerParameter, _restartSecurity); + applicationLayer().restartRequest(AckRequested, SystemPriority, NetworkLayerParameter, _restartSecurity); _restartState = Restarted; _restartDelay = millis(); } @@ -730,7 +518,7 @@ void BauSystemB::nextRestartState() /* restart is finished, we send a discommect */ if (millis() - _restartDelay > 30) { - _appLayer.disconnectRequest(SystemPriority); + applicationLayer().disconnectRequest(SystemPriority); _restartState = Idle; } default: @@ -753,7 +541,7 @@ void BauSystemB::systemNetworkParameterReadIndication(Priority priority, HopCoun if (_deviceObj.progMode() && (objectType == OT_DEVICE) && (propertyId == PID_SERIAL_NUMBER)) { // Send reply. testResult data is KNX serial number - _appLayer.systemNetworkParameterReadResponse(priority, hopType, secCtrl, objectType, propertyId, + applicationLayer().systemNetworkParameterReadResponse(priority, hopType, secCtrl, objectType, propertyId, testInfo, testInfoLength, (uint8_t*)_deviceObj.propertyData(PID_SERIAL_NUMBER), 6); } break; diff --git a/src/knx/bau_systemB.h b/src/knx/bau_systemB.h index b485942..290f839 100644 --- a/src/knx/bau_systemB.h +++ b/src/knx/bau_systemB.h @@ -2,10 +2,6 @@ #include "config.h" #include "bau.h" -#include "device_object.h" -#include "address_table_object.h" -#include "association_table_object.h" -#include "group_object_table_object.h" #include "security_interface_object.h" #include "application_program_object.h" #include "application_layer.h" @@ -20,17 +16,19 @@ class BauSystemB : protected BusAccessUnit { public: BauSystemB(Platform& platform); - virtual void loop(); - DeviceObject& deviceObject(); - GroupObjectTableObject& groupObjectTable(); + virtual void loop() = 0; + virtual bool configured() = 0; + virtual bool enabled() = 0; + virtual void enabled(bool value) = 0; + ApplicationProgramObject& parameters(); + DeviceObject& deviceObject(); + Memory& memory(); - bool configured(); - bool enabled(); - void enabled(bool value); void readMemory(); void writeMemory(); void addSaveRestore(SaveRestore* obj); + bool restartRequest(uint16_t asap, const SecurityControl secCtrl); uint8_t checkmasterResetValidity(EraseCode eraseCode, uint8_t channel); @@ -42,7 +40,10 @@ class BauSystemB : protected BusAccessUnit uint8_t* data, uint32_t length) override; protected: - virtual DataLinkLayer& dataLinkLayer() = 0; + virtual ApplicationLayer& applicationLayer() = 0; + virtual InterfaceObject* getInterfaceObject(uint8_t idx) = 0; + virtual InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_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, @@ -80,26 +81,13 @@ class BauSystemB : protected BusAccessUnit 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 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 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; - virtual InterfaceObject* getInterfaceObject(uint8_t idx) = 0; - virtual InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance) = 0; - void sendNextGroupTelegram(); - void updateGroupObject(GroupObject& go, uint8_t* data, uint8_t length); void nextRestartState(); - virtual void doMasterReset(EraseCode eraseCode, uint8_t channel); enum RestartState @@ -110,22 +98,10 @@ class BauSystemB : protected BusAccessUnit Restarted }; - DeviceObject _deviceObj; Memory _memory; - AddressTableObject _addrTable; - AssociationTableObject _assocTable; - GroupObjectTableObject _groupObjTable; + DeviceObject _deviceObj; ApplicationProgramObject _appProgram; Platform& _platform; -#ifdef USE_DATASECURE - SecureApplicationLayer _appLayer; - SecurityInterfaceObject _secIfObj; -#else - ApplicationLayer _appLayer; -#endif - TransportLayer _transLayer; - NetworkLayer _netLayer; - bool _configured = true; RestartState _restartState = Idle; SecurityControl _restartSecurity; uint32_t _restartDelay = 0; diff --git a/src/knx/bau_systemB_coupler.cpp b/src/knx/bau_systemB_coupler.cpp new file mode 100644 index 0000000..c649378 --- /dev/null +++ b/src/knx/bau_systemB_coupler.cpp @@ -0,0 +1,62 @@ +#include "bau_systemB_coupler.h" +#include "bits.h" +#include +#include + +BauSystemBCoupler::BauSystemBCoupler(Platform& platform) : + BauSystemB(platform), + _platform(platform), +#ifdef USE_DATASECURE + _appLayer(_deviceObj, _secIfObj, *this), +#else + _appLayer(*this), +#endif + _transLayer(_appLayer), + _netLayer(_deviceObj, _transLayer) +{ + _appLayer.transportLayer(_transLayer); + _transLayer.networkLayer(_netLayer); + _memory.addSaveRestore(&_deviceObj); + _memory.addSaveRestore(&_appProgram); +#ifdef USE_DATASECURE + _memory.addSaveRestore(&_secIfObj); +#endif + +} + +ApplicationLayer& BauSystemBCoupler::applicationLayer() +{ + return _appLayer; +} + +void BauSystemBCoupler::loop() +{ + _transLayer.loop(); +#ifdef USE_DATASECURE + _appLayer.loop(); +#endif +} + +bool BauSystemBCoupler::configured() +{ + // _configured is set to true initially, if the device was configured with ETS it will be set to true after restart + + if (!_configured) + return false; + + _configured = _appProgram.loadState() == LS_LOADED; +#ifdef USE_DATASECURE + _configured &= _secIfObj.loadState() == LS_LOADED; +#endif + + return _configured; +} + +void BauSystemBCoupler::doMasterReset(EraseCode eraseCode, uint8_t channel) +{ + BauSystemB::doMasterReset(eraseCode, channel); + +#ifdef USE_DATASECURE + _secIfObj.masterReset(eraseCode, channel); +#endif +} diff --git a/src/knx/bau_systemB_coupler.h b/src/knx/bau_systemB_coupler.h new file mode 100644 index 0000000..f9dbacc --- /dev/null +++ b/src/knx/bau_systemB_coupler.h @@ -0,0 +1,40 @@ +#pragma once + +#include "config.h" +#include "bau_systemB.h" +#include "device_object.h" +#include "security_interface_object.h" +#include "application_program_object.h" +#include "router_object.h" +#include "application_layer.h" +#include "secure_application_layer.h" +#include "transport_layer.h" +#include "network_layer_coupler.h" +#include "data_link_layer.h" +#include "platform.h" +#include "memory.h" + +class BauSystemBCoupler : public BauSystemB +{ + public: + BauSystemBCoupler(Platform& platform); + virtual void loop() override; + virtual bool configured() override; + + protected: + virtual ApplicationLayer& applicationLayer() override; + + virtual void doMasterReset(EraseCode eraseCode, uint8_t channel) override; + + Platform& _platform; + +#ifdef USE_DATASECURE + SecureApplicationLayer _appLayer; + SecurityInterfaceObject _secIfObj; +#else + ApplicationLayer _appLayer; +#endif + TransportLayer _transLayer; + NetworkLayerCoupler _netLayer; + bool _configured = true; +}; diff --git a/src/knx/bau_systemB_device.cpp b/src/knx/bau_systemB_device.cpp new file mode 100644 index 0000000..3574b34 --- /dev/null +++ b/src/knx/bau_systemB_device.cpp @@ -0,0 +1,226 @@ +#include "bau_systemB_device.h" +#include "bits.h" +#include +#include + +BauSystemBDevice::BauSystemBDevice(Platform& platform) : + BauSystemB(platform), + _addrTable(_memory), + _assocTable(_memory), _groupObjTable(_memory), +#ifdef USE_DATASECURE + _appLayer(_deviceObj, _secIfObj, *this), +#else + _appLayer(*this), +#endif + _transLayer(_appLayer), _netLayer(_deviceObj, _transLayer) +{ + _appLayer.transportLayer(_transLayer); + _appLayer.associationTableObject(_assocTable); +#ifdef USE_DATASECURE + _appLayer.groupAddressTable(_addrTable); +#endif + _transLayer.networkLayer(_netLayer); + _transLayer.groupAddressTable(_addrTable); + + _memory.addSaveRestore(&_deviceObj); + _memory.addSaveRestore(&_addrTable); + _memory.addSaveRestore(&_assocTable); + _memory.addSaveRestore(&_groupObjTable); +#ifdef USE_DATASECURE + _memory.addSaveRestore(&_secIfObj); +#endif +} + +ApplicationLayer& BauSystemBDevice::applicationLayer() +{ + return _appLayer; +} + +GroupObjectTableObject& BauSystemBDevice::groupObjectTable() +{ + return _groupObjTable; +} + +void BauSystemBDevice::loop() +{ + _transLayer.loop(); + sendNextGroupTelegram(); + nextRestartState(); +#ifdef USE_DATASECURE + _appLayer.loop(); +#endif +} + +void BauSystemBDevice::sendNextGroupTelegram() +{ + if(!configured()) + return; + + static uint16_t startIdx = 1; + + GroupObjectTableObject& table = _groupObjTable; + uint16_t objCount = table.entryCount(); + + for (uint16_t asap = startIdx; asap <= objCount; asap++) + { + GroupObject& go = table.get(asap); + + ComFlag flag = go.commFlag(); + if (flag != ReadRequest && flag != WriteRequest) + continue; + + if (!go.communicationEnable()) + continue; + + SecurityControl goSecurity; + goSecurity.toolAccess = false; // Secured group communication never uses the toolkey. ETS knows all keys, also the group keys. + +#ifdef USE_DATASECURE + // Get security flags from Security Interface Object for this group object + goSecurity.dataSecurity = _secIfObj.getGroupObjectSecurity(asap); +#else + goSecurity.dataSecurity = DataSecurity::none; +#endif + + if (flag == WriteRequest && go.transmitEnable()) + { + uint8_t* data = go.valueRef(); + _appLayer.groupValueWriteRequest(AckRequested, asap, go.priority(), NetworkLayerParameter, goSecurity, data, + go.sizeInTelegram()); + } + else if (flag == ReadRequest) + { + _appLayer.groupValueReadRequest(AckRequested, asap, go.priority(), NetworkLayerParameter, goSecurity); + } + + go.commFlag(Transmitting); + + startIdx = asap + 1; + return; + } + + startIdx = 1; +} + +void BauSystemBDevice::updateGroupObject(GroupObject & go, uint8_t * data, uint8_t length) +{ + uint8_t* goData = go.valueRef(); + if (length != go.valueSize()) + { + go.commFlag(Error); + return; + } + + memcpy(goData, data, length); + + go.commFlag(Updated); + GroupObjectUpdatedHandler handler = go.callback(); + if (handler) + handler(go); +} + +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; + +#ifdef USE_DATASECURE + _configured &= _secIfObj.loadState() == LS_LOADED; +#endif + + return _configured; +} + +void BauSystemBDevice::doMasterReset(EraseCode eraseCode, uint8_t channel) +{ + BauSystemB::doMasterReset(eraseCode, channel); + + _addrTable.masterReset(eraseCode, channel); + _assocTable.masterReset(eraseCode, channel); + _groupObjTable.masterReset(eraseCode, channel); +#ifdef USE_DATASECURE + _secIfObj.masterReset(eraseCode, channel); +#endif +} + +void BauSystemBDevice::groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl &secCtrl, uint8_t * data, uint8_t dataLength, bool status) +{ + GroupObject& go = _groupObjTable.get(asap); + if (status) + go.commFlag(Ok); + else + go.commFlag(Error); +} + +void BauSystemBDevice::groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl &secCtrl, bool status) +{ + GroupObject& go = _groupObjTable.get(asap); + if (status) + go.commFlag(Ok); + else + go.commFlag(Error); +} + +void BauSystemBDevice::groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl &secCtrl) +{ +#ifdef USE_DATASECURE + DataSecurity requiredGoSecurity; + + // Get security flags from Security Interface Object for this group object + requiredGoSecurity = _secIfObj.getGroupObjectSecurity(asap); + + if (secCtrl.dataSecurity != requiredGoSecurity) + { + println("GroupValueRead: access denied due to wrong security flags"); + return; + } +#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) +{ + GroupObject& go = _groupObjTable.get(asap); + + if (!go.communicationEnable() || !go.responseUpdateEnable()) + return; + + updateGroupObject(go, data, 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; + + // Get security flags from Security Interface Object for this group object + requiredGoSecurity = _secIfObj.getGroupObjectSecurity(asap); + + if (secCtrl.dataSecurity != requiredGoSecurity) + { + println("GroupValueWrite: access denied due to wrong security flags"); + return; + } +#endif + GroupObject& go = _groupObjTable.get(asap); + + if (!go.communicationEnable() || !go.writeEnable()) + return; + + updateGroupObject(go, data, dataLength); +} diff --git a/src/knx/bau_systemB_device.h b/src/knx/bau_systemB_device.h new file mode 100644 index 0000000..ab645fe --- /dev/null +++ b/src/knx/bau_systemB_device.h @@ -0,0 +1,57 @@ +#pragma once + +#include "config.h" +#include "bau_systemB.h" +#include "device_object.h" +#include "address_table_object.h" +#include "association_table_object.h" +#include "group_object_table_object.h" +#include "security_interface_object.h" +#include "application_program_object.h" +#include "application_layer.h" +#include "secure_application_layer.h" +#include "transport_layer.h" +#include "network_layer_device.h" +#include "data_link_layer.h" +#include "platform.h" +#include "memory.h" + +class BauSystemBDevice : public BauSystemB +{ + public: + BauSystemBDevice(Platform& platform); + virtual void loop() override; + virtual bool configured() override; + GroupObjectTableObject& groupObjectTable(); + + protected: + virtual 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 sendNextGroupTelegram(); + void updateGroupObject(GroupObject& go, uint8_t* data, uint8_t length); + + virtual void doMasterReset(EraseCode eraseCode, uint8_t channel) override; + + AddressTableObject _addrTable; + AssociationTableObject _assocTable; + GroupObjectTableObject _groupObjTable; +#ifdef USE_DATASECURE + SecureApplicationLayer _appLayer; + SecurityInterfaceObject _secIfObj; +#else + ApplicationLayer _appLayer; +#endif + TransportLayer _transLayer; + NetworkLayerDevice _netLayer; + + bool _configured = true; +}; diff --git a/src/knx/bits.cpp b/src/knx/bits.cpp index b47d65f..a1e5941 100644 --- a/src/knx/bits.cpp +++ b/src/knx/bits.cpp @@ -1,4 +1,5 @@ #include "bits.h" +#include // for memcpy() const uint8_t* popByte(uint8_t& b, const uint8_t* data) { @@ -105,3 +106,32 @@ uint64_t sixBytesToUInt64(uint8_t* data) } return l; } + +// The CRC of the Memory Control Block Table Property is a CRC16-CCITT with the following +// parameters: +// Width = 16 bit +// Truncated polynomial = 1021h +// Initial value = FFFFh +// Input date is NOT reflected. +// Output CRC is NOT reflected. +// No XOR is performed on the output CRC. +// EXAMPLE The correct CRC16-CCITT of the string ‘123456789’ is E5CCh. + +uint16_t crc16Ccitt(uint8_t* input, uint16_t length) +{ + uint32_t polynom = 0x1021; + uint8_t padded[length+2]; + + memcpy(padded, input, length); + memset(padded+length, 0x00, 2); + + uint32_t result = 0xffff; + for (uint32_t i = 0; i < 8 * (uint32_t)sizeof(padded); i++) { + result <<= 1; + uint32_t nextBit = (padded[i / 8] >> (7 - (i % 8))) & 0x1; + result |= nextBit; + if ((result & 0x10000) != 0) + result ^= polynom; + } + return result & 0xffff; +} diff --git a/src/knx/bits.h b/src/knx/bits.h index 637f494..bfaea22 100644 --- a/src/knx/bits.h +++ b/src/knx/bits.h @@ -90,3 +90,5 @@ void printHex(const char* suffix, const uint8_t *data, size_t length); void sixBytesFromUInt64(uint64_t num, uint8_t* toByteArray); uint64_t sixBytesToUInt64(uint8_t* data); + +uint16_t crc16Ccitt(uint8_t* input, uint16_t length); diff --git a/src/knx/cemi_frame.cpp b/src/knx/cemi_frame.cpp index 13e7c79..7e0d31a 100644 --- a/src/knx/cemi_frame.cpp +++ b/src/knx/cemi_frame.cpp @@ -366,7 +366,7 @@ APDU& CemiFrame::apdu() bool CemiFrame::valid() const { uint8_t addInfoLen = _data[1]; - uint8_t apduLen = _data[1 + _data[1] + NPDU_LPDU_DIFF]; + uint8_t apduLen = _data[_data[1] + NPDU_LPDU_DIFF]; if (_length != 0 && _length != (addInfoLen + apduLen + NPDU_LPDU_DIFF + 2)) return false; diff --git a/src/knx/cemi_frame.h b/src/knx/cemi_frame.h index fc21501..8c82d43 100644 --- a/src/knx/cemi_frame.h +++ b/src/knx/cemi_frame.h @@ -89,4 +89,6 @@ class CemiFrame uint8_t _rfInfo = 0; uint8_t _rfLfn = 0xFF; // RF Data Link layer frame number #endif -}; \ No newline at end of file + + uint8_t _sourceInterfaceIndex; +}; diff --git a/src/knx/cemi_server.cpp b/src/knx/cemi_server.cpp index 54baab5..bd9a8b3 100644 --- a/src/knx/cemi_server.cpp +++ b/src/knx/cemi_server.cpp @@ -56,21 +56,24 @@ void CemiServer::dataConfirmationToTunnel(CemiFrame& frame) void CemiServer::dataIndicationToTunnel(CemiFrame& frame) { -#if MEDIUM_TYPE == 2 + bool isRf = _dataLinkLayer->mediumType() == DptMedium::KNX_RF; + uint8_t data[frame.dataLength() + (isRf ? 10 : 0)]; - uint8_t data[frame.dataLength() + 10]; - data[0] = L_data_ind; // Message Code - data[1] = 0x0A; // Total additional info length - data[2] = 0x02; // RF add. info: type - data[3] = 0x08; // RF add. info: length - data[4] = frame.rfInfo(); // RF add. info: info field (batt ok, bidir) - pushByteArray(frame.rfSerialOrDoA(), 6, &data[5]); // RF add. info:Serial or Domain Address - data[11] = frame.rfLfn(); // RF add. info: link layer frame number - memcpy(&data[12], &((frame.data())[2]), frame.dataLength() - 2); -#else - uint8_t data[frame.dataLength()]; - memcpy(&data[0], frame.data(), frame.dataLength()); -#endif + if (isRf) + { + data[0] = L_data_ind; // Message Code + data[1] = 0x0A; // Total additional info length + data[2] = 0x02; // RF add. info: type + data[3] = 0x08; // RF add. info: length + data[4] = frame.rfInfo(); // RF add. info: info field (batt ok, bidir) + pushByteArray(frame.rfSerialOrDoA(), 6, &data[5]); // RF add. info:Serial or Domain Address + data[11] = frame.rfLfn(); // RF add. info: link layer frame number + memcpy(&data[12], &((frame.data())[2]), frame.dataLength() - 2); + } + else + { + memcpy(&data[0], frame.data(), frame.dataLength()); + } CemiFrame tmpFrame(data, sizeof(data)); @@ -87,6 +90,8 @@ void CemiServer::dataIndicationToTunnel(CemiFrame& frame) void CemiServer::frameReceived(CemiFrame& frame) { + bool isRf = _dataLinkLayer->mediumType() == DptMedium::KNX_RF; + switch(frame.messageCode()) { case L_data_req: @@ -98,35 +103,36 @@ void CemiServer::frameReceived(CemiFrame& frame) frame.sourceAddress(_clientAddress); } -#if MEDIUM_TYPE == 2 - // Check if we have additional info for RF - if (((frame.data())[1] == 0x0A) && // Additional info total length: we only handle one additional info of type RF - ((frame.data())[2] == 0x02) && // Additional info type: RF - ((frame.data())[3] == 0x08) ) // Additional info length of type RF: 8 bytes (fixed) + if (isRf) { - frame.rfInfo((frame.data())[4]); - // Use the values provided in the RF additonal info - if ( ((frame.data())[5] != 0x00) || ((frame.data())[6] != 0x00) || ((frame.data())[7] != 0x00) || - ((frame.data())[8] != 0x00) || ((frame.data())[9] != 0x00) || ((frame.data())[10] != 0x00) ) + // Check if we have additional info for RF + if (((frame.data())[1] == 0x0A) && // Additional info total length: we only handle one additional info of type RF + ((frame.data())[2] == 0x02) && // Additional info type: RF + ((frame.data())[3] == 0x08) ) // Additional info length of type RF: 8 bytes (fixed) { - frame.rfSerialOrDoA(&((frame.data())[5])); - } // else leave the nullptr as it is - frame.rfLfn((frame.data())[11]); - } + frame.rfInfo((frame.data())[4]); + // Use the values provided in the RF additonal info + if ( ((frame.data())[5] != 0x00) || ((frame.data())[6] != 0x00) || ((frame.data())[7] != 0x00) || + ((frame.data())[8] != 0x00) || ((frame.data())[9] != 0x00) || ((frame.data())[10] != 0x00) ) + { + frame.rfSerialOrDoA(&((frame.data())[5])); + } // else leave the nullptr as it is + frame.rfLfn((frame.data())[11]); + } - // If the cEMI client does not provide a link layer frame number (LFN), - // we use our own counter. - // Note: There is another link layer frame number counter inside the RF data link layer class! - // That counter is solely for the local application! - // If we set a LFN here, the data link layer counter is NOT used! - if (frame.rfLfn() == 0xFF) - { - // Set Data Link Layer Frame Number - frame.rfLfn(_frameNumber); - // Link Layer frame number counts 0..7 - _frameNumber = (_frameNumber + 1) & 0x7; + // If the cEMI client does not provide a link layer frame number (LFN), + // we use our own counter. + // Note: There is another link layer frame number counter inside the RF data link layer class! + // That counter is solely for the local application! + // If we set a LFN here, the data link layer counter is NOT used! + if (frame.rfLfn() == 0xFF) + { + // Set Data Link Layer Frame Number + frame.rfLfn(_frameNumber); + // Link Layer frame number counts 0..7 + _frameNumber = (_frameNumber + 1) & 0x7; + } } -#endif print("L_data_req: src: "); print(frame.sourceAddress(), HEX); diff --git a/src/knx/cemi_server_object.cpp b/src/knx/cemi_server_object.cpp index 3b4bc1b..140c414 100644 --- a/src/knx/cemi_server_object.cpp +++ b/src/knx/cemi_server_object.cpp @@ -8,26 +8,51 @@ CemiServerObject::CemiServerObject() { - uint16_t mediumType = 0; -#if MEDIUM_TYPE == 0 - mediumType = 2; // TP1 supported -#elif MEDIUM_TYPE == 2 - mediumType = 16; // RF supported -#elif MEDIUM_TYPE == 5 - mediumType = 32; // IP supported -#endif - Property* properties[] = { new DataProperty( PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_CEMI_SERVER ), - new DataProperty( PID_MEDIUM_TYPE, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0, mediumType), + new DataProperty( PID_MEDIUM_TYPE, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0, (uint16_t)0), new DataProperty( PID_COMM_MODE, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint16_t)0), new DataProperty( PID_COMM_MODES_SUPPORTED, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0, (uint16_t)0x100), - new DataProperty( PID_MEDIUM_AVAILABILITY, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0, mediumType), + new DataProperty( PID_MEDIUM_AVAILABILITY, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0, (uint16_t)0), // cEMI additional info types supported by this cEMI server: only 0x02 (RF Control Octet and Serial Number or DoA) new DataProperty( PID_ADD_INFO_TYPES, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint8_t)0x02) }; initializeProperties(sizeof(properties), properties); } + +void CemiServerObject::setMediumTypeAsSupported(DptMedium dptMedium) +{ + uint16_t mediaTypesSupported; + property(PID_MEDIUM_TYPE)->read(mediaTypesSupported); + + switch(dptMedium) + { + case DptMedium::KNX_IP: + mediaTypesSupported |= 1 << 1; + break; + case DptMedium::KNX_RF: + mediaTypesSupported |= 1 << 4; + break; + case DptMedium::KNX_TP1: + mediaTypesSupported |= 1 << 5; + break; + case DptMedium::KNX_PL110: + mediaTypesSupported |= 1 << 2; + break; + } + + property(PID_MEDIUM_TYPE)->write(mediaTypesSupported); + // We also set the medium as available too + property(PID_MEDIUM_AVAILABILITY)->write(mediaTypesSupported); +} + +void CemiServerObject::clearSupportedMediaTypes() +{ + property(PID_MEDIUM_TYPE)->write((uint16_t) 0); + // We also set the medium as not available too + property(PID_MEDIUM_AVAILABILITY)->write((uint16_t) 0); +} + #endif diff --git a/src/knx/cemi_server_object.h b/src/knx/cemi_server_object.h index 9287c5d..726f82e 100644 --- a/src/knx/cemi_server_object.h +++ b/src/knx/cemi_server_object.h @@ -9,5 +9,9 @@ class CemiServerObject: public InterfaceObject { public: CemiServerObject(); + + void setMediumTypeAsSupported(DptMedium dptMedium); + void clearSupportedMediaTypes(); }; -#endif \ No newline at end of file + +#endif diff --git a/src/knx/config.h b/src/knx/config.h index 1b03cd0..21063a9 100644 --- a/src/knx/config.h +++ b/src/knx/config.h @@ -12,16 +12,56 @@ #define GPIO_GDO0_PIN 24 // GPIO 24 (GPIO_GEN5) -> WiringPi: 5 -> Pin number on header: 18 #endif -//#define MEDIUM_TYPE 2 +// 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 #ifdef USE_USB #define USE_CEMI_SERVER #endif +// KNX Data Secure Options #define USE_DATASECURE #endif + +#if !defined(MASK_VERSION) +#error MASK_VERSION must be defined! See config.j for possible values! +#endif + diff --git a/src/knx/data_link_layer.cpp b/src/knx/data_link_layer.cpp index 877783d..3412e61 100644 --- a/src/knx/data_link_layer.cpp +++ b/src/knx/data_link_layer.cpp @@ -3,12 +3,11 @@ #include "bits.h" #include "platform.h" #include "device_object.h" -#include "address_table_object.h" #include "cemi_server.h" +#include "cemi_frame.h" -DataLinkLayer::DataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, - NetworkLayer& layer, Platform& platform) : - _deviceObject(devObj), _groupAddressTable(addrTab), _networkLayer(layer), _platform(platform) +DataLinkLayer::DataLinkLayer(DeviceObject& devObj, NetworkLayerEntity& netLayerEntity, Platform& platform) : + _deviceObject(devObj), _networkLayerEntity(netLayerEntity), _platform(platform) { } @@ -33,19 +32,19 @@ void DataLinkLayer::dataRequestFromTunnel(CemiFrame& frame) } #endif -void DataLinkLayer::dataRequest(AckType ack, AddressType addrType, uint16_t destinationAddr, FrameFormat format, Priority priority, NPDU& npdu) +void DataLinkLayer::dataRequest(AckType ack, AddressType addrType, uint16_t destinationAddr, uint16_t sourceAddr, FrameFormat format, Priority priority, NPDU& npdu) { // Normal data requests and broadcasts will always be transmitted as (domain) broadcast with domain address for open media (e.g. RF medium) // The domain address "simulates" a closed medium (such as TP) on an open medium (such as RF or PL) // See 3.2.5 p.22 - sendTelegram(npdu, ack, destinationAddr, addrType, format, priority, Broadcast); + sendTelegram(npdu, ack, destinationAddr, addrType, sourceAddr, format, priority, Broadcast); } -void DataLinkLayer::systemBroadcastRequest(AckType ack, FrameFormat format, Priority priority, NPDU& npdu) +void DataLinkLayer::systemBroadcastRequest(AckType ack, FrameFormat format, Priority priority, NPDU& npdu, uint16_t sourceAddr) { // System Broadcast requests will always be transmitted as broadcast with KNX serial number for open media (e.g. RF medium) // See 3.2.5 p.22 - sendTelegram(npdu, ack, 0, GroupAddress, format, priority, SysBroadcast); + sendTelegram(npdu, ack, 0, GroupAddress, sourceAddr, format, priority, SysBroadcast); } void DataLinkLayer::dataConReceived(CemiFrame& frame, bool success) @@ -74,11 +73,11 @@ void DataLinkLayer::dataConReceived(CemiFrame& frame, bool success) if (addrType == GroupAddress && destination == 0) if (systemBroadcast == SysBroadcast) - _networkLayer.systemBroadcastConfirm(ack, type, priority, source, npdu, success); + _networkLayerEntity.systemBroadcastConfirm(ack, type, priority, source, npdu, success); else - _networkLayer.broadcastConfirm(ack, type, priority, source, npdu, success); + _networkLayerEntity.broadcastConfirm(ack, type, priority, source, npdu, success); else - _networkLayer.dataConfirm(ack, addrType, destination, type, priority, source, npdu, success); + _networkLayerEntity.dataConfirm(ack, addrType, destination, type, priority, source, npdu, success); frame.messageCode(backupMsgCode); } @@ -109,43 +108,26 @@ void DataLinkLayer::frameRecieved(CemiFrame& frame) if (addrType == GroupAddress && destination == 0) { if (systemBroadcast == SysBroadcast) - _networkLayer.systemBroadcastIndication(ack, type, npdu, priority, source); + _networkLayerEntity.systemBroadcastIndication(ack, type, npdu, priority, source); else - _networkLayer.broadcastIndication(ack, type, npdu, priority, source); + _networkLayerEntity.broadcastIndication(ack, type, npdu, priority, source); } else { - if (addrType == InduvidualAddress && destination != _deviceObject.induvidualAddress()) - return; - - if (addrType == GroupAddress && !_groupAddressTable.contains(destination)) - return; - -// if (frame.npdu().octetCount() > 0) -// { -// _print("-> DLL "); -// frame.apdu().printPDU(); -// } - - _networkLayer.dataIndication(ack, addrType, destination, type, npdu, priority, source); + _networkLayerEntity.dataIndication(ack, addrType, destination, type, npdu, priority, source); } } -bool DataLinkLayer::sendTelegram(NPDU & npdu, AckType ack, uint16_t destinationAddr, AddressType addrType, FrameFormat format, Priority priority, SystemBroadcast systemBroadcast) +bool DataLinkLayer::sendTelegram(NPDU & npdu, AckType ack, uint16_t destinationAddr, AddressType addrType, uint16_t sourceAddr, FrameFormat format, Priority priority, SystemBroadcast systemBroadcast) { CemiFrame& frame = npdu.frame(); frame.messageCode(L_data_ind); frame.destinationAddress(destinationAddr); - frame.sourceAddress(_deviceObject.induvidualAddress()); + frame.sourceAddress(sourceAddr); frame.addressType(addrType); frame.priority(priority); frame.repetition(RepititionAllowed); -#if (MEDIUM_TYPE == 5)||(MEDIUM_TYPE == 0) - // Make sure to always send as normal Broadcast on closed media (TP and IP) - frame.systemBroadcast(Broadcast); -#else frame.systemBroadcast(systemBroadcast); -#endif if (npdu.octetCount() <= 15) frame.frameType(StandardFrame); diff --git a/src/knx/data_link_layer.h b/src/knx/data_link_layer.h index 28ba679..3fbaa1e 100644 --- a/src/knx/data_link_layer.h +++ b/src/knx/data_link_layer.h @@ -4,15 +4,16 @@ #include #include "device_object.h" -#include "address_table_object.h" #include "knx_types.h" -#include "network_layer.h" +#include "network_layer_entity.h" #include "cemi_server.h" +class Platform; + class DataLinkLayer { public: - DataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, NetworkLayer& layer, + DataLinkLayer(DeviceObject& devObj, NetworkLayerEntity& netLayerEntity, Platform& platform); #ifdef USE_CEMI_SERVER @@ -22,22 +23,22 @@ class DataLinkLayer #endif // from network layer - void dataRequest(AckType ack, AddressType addrType, uint16_t destinationAddr, FrameFormat format, + 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); + 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 frameRecieved(CemiFrame& frame); void dataConReceived(CemiFrame& frame, bool success); - bool sendTelegram(NPDU& npdu, AckType ack, uint16_t destinationAddr, AddressType addrType, FrameFormat format, Priority priority, SystemBroadcast systemBroadcast); + bool sendTelegram(NPDU& npdu, AckType ack, uint16_t destinationAddr, AddressType addrType, uint16_t sourceAddr, FrameFormat format, Priority priority, SystemBroadcast systemBroadcast); virtual bool sendFrame(CemiFrame& frame) = 0; uint8_t* frameData(CemiFrame& frame); DeviceObject& _deviceObject; - AddressTableObject& _groupAddressTable; - NetworkLayer& _networkLayer; + NetworkLayerEntity& _networkLayerEntity; Platform& _platform; #ifdef USE_CEMI_SERVER CemiServer* _cemiServer; diff --git a/src/knx/device_object.cpp b/src/knx/device_object.cpp index 0bcb866..d62e672 100644 --- a/src/knx/device_object.cpp +++ b/src/knx/device_object.cpp @@ -35,7 +35,7 @@ DeviceObject::DeviceObject() 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)0), + new DataProperty(PID_ROUTING_COUNT, true, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv3, (uint8_t)6), 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 { @@ -284,7 +284,10 @@ void DeviceObject::rfDomainAddress(uint8_t* value) prop->write(value); } - - - - +uint8_t DeviceObject::defaultHopCount() +{ + Property* prop = property(PID_ROUTING_COUNT); + uint8_t value; + prop->read(value); + return (value >> 4) & 0x07; +} diff --git a/src/knx/device_object.h b/src/knx/device_object.h index 023d840..12e6c8a 100644 --- a/src/knx/device_object.h +++ b/src/knx/device_object.h @@ -36,7 +36,8 @@ public: void maxApduLength(uint16_t value); const uint8_t* rfDomainAddress(); void rfDomainAddress(uint8_t* value); + uint8_t defaultHopCount(); private: uint8_t _prgMode = 0; uint16_t _ownAddress = 0; -}; \ No newline at end of file +}; diff --git a/src/knx/ip_data_link_layer.cpp b/src/knx/ip_data_link_layer.cpp index 13fbdfa..9954356 100644 --- a/src/knx/ip_data_link_layer.cpp +++ b/src/knx/ip_data_link_layer.cpp @@ -1,11 +1,11 @@ -#include "ip_data_link_layer.h" - +#include "config.h" #ifdef USE_IP +#include "ip_data_link_layer.h" + #include "bits.h" #include "platform.h" #include "device_object.h" -#include "address_table_object.h" #include "knx_ip_routing_indication.h" #include "knx_ip_search_request.h" #include "knx_ip_search_response.h" @@ -18,8 +18,8 @@ #define MIN_LEN_CEMI 10 -IpDataLinkLayer::IpDataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, IpParameterObject& ipParam, - NetworkLayer& layer, Platform& platform) : DataLinkLayer(devObj, addrTab, layer, platform), _ipParameters(ipParam) +IpDataLinkLayer::IpDataLinkLayer(DeviceObject& devObj, IpParameterObject& ipParam, + NetworkLayerEntity &netLayerEntity, Platform& platform) : DataLinkLayer(devObj, netLayerEntity, platform), _ipParameters(ipParam) { } @@ -100,6 +100,10 @@ bool IpDataLinkLayer::enabled() const return _enabled; } +DptMedium IpDataLinkLayer::mediumType() const +{ + return DptMedium::KNX_IP; +} bool IpDataLinkLayer::sendBytes(uint8_t* bytes, uint16_t length) { diff --git a/src/knx/ip_data_link_layer.h b/src/knx/ip_data_link_layer.h index 11c0fca..997a696 100644 --- a/src/knx/ip_data_link_layer.h +++ b/src/knx/ip_data_link_layer.h @@ -2,6 +2,7 @@ #include "config.h" #ifdef USE_IP + #include #include "data_link_layer.h" #include "ip_parameter_object.h" @@ -11,12 +12,13 @@ class IpDataLinkLayer : public DataLinkLayer using DataLinkLayer::_deviceObject; public: - IpDataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, IpParameterObject& ipParam, NetworkLayer& layer, + IpDataLinkLayer(DeviceObject& devObj, IpParameterObject& ipParam, NetworkLayerEntity& netLayerEntity, Platform& platform); void loop(); void enabled(bool value); bool enabled() const; + virtual DptMedium mediumType() const override; private: bool _enabled = false; @@ -25,4 +27,4 @@ class IpDataLinkLayer : public DataLinkLayer IpParameterObject& _ipParameters; }; -#endif \ No newline at end of file +#endif diff --git a/src/knx/knx_types.h b/src/knx/knx_types.h index f92b60c..3f8b291 100644 --- a/src/knx/knx_types.h +++ b/src/knx/knx_types.h @@ -149,6 +149,10 @@ enum ApduType SystemNetworkParameterResponse = 0x1c9, SystemNetworkParameterWrite = 0x1ca, // Open media specific Application Layer Services on System Broadcast communication mode + DomainAddressWrite = 0x3e0, + DomainAddressRead = 0x3e1, + DomainAddressResponse = 0x3e2, + DomainAddressSelectiveRead = 0x3e3, DomainAddressSerialNumberRead = 0x3ec, DomainAddressSerialNumberResponse = 0x3ed, DomainAddressSerialNumberWrite = 0x3ee, @@ -228,3 +232,13 @@ enum EraseCode ResetLinks = 0x06, FactoryResetWithoutIA = 0x07 }; + +enum DptMedium +{ + // DPT_Medium (20.1004), range 0-255 + // All other values are reserved. + KNX_TP1 = 0x00, + KNX_PL110 = 0x01, + KNX_RF = 0x02, + KNX_IP = 0x05 +}; diff --git a/src/knx/network_layer.cpp b/src/knx/network_layer.cpp index 869c4fc..05f8aac 100644 --- a/src/knx/network_layer.cpp +++ b/src/knx/network_layer.cpp @@ -1,17 +1,16 @@ #include "network_layer.h" +#include "device_object.h" +#include "data_link_layer.h" #include "tpdu.h" #include "cemi_frame.h" -#include "data_link_layer.h" #include "bits.h" +#include "apdu.h" -NetworkLayer::NetworkLayer(TransportLayer& layer): _transportLayer(layer) +NetworkLayer::NetworkLayer(DeviceObject &deviceObj, TransportLayer& layer) : + _deviceObj(deviceObj), + _transportLayer(layer) { - -} - -void NetworkLayer::dataLinkLayer(DataLinkLayer& layer) -{ - _dataLinkLayer = &layer; + _hopCount = _deviceObj.defaultHopCount(); } uint8_t NetworkLayer::hopCount() const @@ -19,120 +18,26 @@ uint8_t NetworkLayer::hopCount() const return _hopCount; } -void NetworkLayer::hopCount(uint8_t value) +bool NetworkLayer::isApciSystemBroadcast(APDU& apdu) { - _hopCount = value & 0x7; -} - -void NetworkLayer::dataIndication(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source) -{ - HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; - if (addrType == InduvidualAddress) + switch (apdu.type()) { - //if (npdu.octetCount() > 0) - //{ - // print.print("<- NL "); - // npdu.frame().apdu().printPDU(); - //} - _transportLayer.dataIndividualIndication(destination, hopType, priority, source, npdu.tpdu()); - return; + // Application Layer Services on System Broadcast communication mode + case SystemNetworkParameterRead: + case SystemNetworkParameterResponse: + case SystemNetworkParameterWrite: + // Open media specific Application Layer Services on System Broadcast communication mode + case DomainAddressSerialNumberRead: + case DomainAddressSerialNumberResponse: + case DomainAddressSerialNumberWrite: + case DomainAddressRead: + case DomainAddressSelectiveRead: + case DomainAddressResponse: + case DomainAddressWrite: + return true; + default: + return false; } - // group-address type - if (destination != 0) - { - _transportLayer.dataGroupIndication(destination, hopType, priority, source, npdu.tpdu()); - return; - } - // destination == 0 - _transportLayer.dataBroadcastIndication(hopType, priority, source, npdu.tpdu()); + return false; } -void NetworkLayer::dataConfirm(AckType ack, AddressType addressType, uint16_t destination, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status) -{ - HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; - if (addressType == InduvidualAddress) - { - _transportLayer.dataIndividualConfirm(ack, destination, hopType, priority, npdu.tpdu(), status); - return; - } - // group-address type - if (destination != 0) - { - _transportLayer.dataGroupConfirm(ack, source, destination, hopType, priority, npdu.tpdu(), status); - return; - } - // destination == 0 - _transportLayer.dataBroadcastConfirm(ack, hopType, priority, npdu.tpdu(), status); -} - -void NetworkLayer::broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source) -{ - HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; - _transportLayer.dataBroadcastIndication(hopType, priority, source, npdu.tpdu()); -} - -void NetworkLayer::broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status) -{ - HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; - _transportLayer.dataBroadcastConfirm(ack, hopType, priority, npdu.tpdu(), status); -} - -void NetworkLayer::systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source) -{ - HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; - _transportLayer.dataSystemBroadcastIndication(hopType, priority, source, npdu.tpdu()); -} - -void NetworkLayer::systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status) -{ - HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; - _transportLayer.dataSystemBroadcastConfirm(ack, hopType, npdu.tpdu(), priority, status); -} - -void NetworkLayer::dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) -{ - //if (tpdu.apdu().length() > 0) - //{ - // print.print("-> NL "); - // tpdu.apdu().printPDU(); - //} - sendDataRequest(tpdu, hopType, ack, destination, priority, InduvidualAddress); -} - -void NetworkLayer::sendDataRequest(TPDU &tpdu, HopCountType hopType, AckType ack, uint16_t destination, Priority priority, AddressType addrType) -{ - NPDU& npdu = tpdu.frame().npdu(); - - if (hopType == UnlimitedRouting) - npdu.hopCount(7); - else - npdu.hopCount(_hopCount); - - FrameFormat frameFormat = npdu.octetCount() > 15 ? ExtendedFrame : StandardFrame; - - _dataLinkLayer->dataRequest(ack, addrType, destination, frameFormat, priority, npdu); -} - -void NetworkLayer::dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) -{ - sendDataRequest(tpdu, hopType, ack, destination, priority, GroupAddress); -} - -void NetworkLayer::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) -{ - sendDataRequest(tpdu, hopType, ack, 0, priority, GroupAddress); -} - -void NetworkLayer::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) -{ - NPDU& npdu = tpdu.frame().npdu(); - - if (hopType == UnlimitedRouting) - npdu.hopCount(7); - else - npdu.hopCount(_hopCount); - - FrameFormat frameFormat = npdu.octetCount() > 15 ? ExtendedFrame : StandardFrame; - - _dataLinkLayer->systemBroadcastRequest(ack, frameFormat, priority, npdu); -} diff --git a/src/knx/network_layer.h b/src/knx/network_layer.h index 0b1f88e..e12c846 100644 --- a/src/knx/network_layer.h +++ b/src/knx/network_layer.h @@ -4,38 +4,43 @@ #include "knx_types.h" #include "npdu.h" #include "transport_layer.h" -class DataLinkLayer; +#include "network_layer_entity.h" + +class DeviceObject; +class APDU; class NetworkLayer { + friend class NetworkLayerEntity; + public: - NetworkLayer(TransportLayer& layer); + NetworkLayer(DeviceObject& deviceObj, TransportLayer& layer); - void dataLinkLayer(DataLinkLayer& layer); uint8_t hopCount() const; - void hopCount(uint8_t value); - - // 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); + bool isApciSystemBroadcast(APDU& apdu); // from transport layer - void dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu); - void dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu); - void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu); - void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu); + 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: - void sendDataRequest(TPDU& tpdu, HopCountType hopType, AckType ack, uint16_t destination, Priority priority, AddressType addrType); - uint8_t _hopCount = 6; - DataLinkLayer* _dataLinkLayer = 0; - TransportLayer& _transportLayer; + 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 new file mode 100644 index 0000000..968f499 --- /dev/null +++ b/src/knx/network_layer_coupler.cpp @@ -0,0 +1,456 @@ +#include "network_layer_coupler.h" +#include "device_object.h" +#include "router_object.h" +#include "tpdu.h" +#include "cemi_frame.h" +#include "bits.h" + +NetworkLayerCoupler::NetworkLayerCoupler(DeviceObject &deviceObj, + TransportLayer& layer) : + NetworkLayer(deviceObj, layer), + _netLayerEntities { {*this, kPrimaryIfIndex}, {*this, kSecondaryIfIndex} } +{ + _currentAddress = deviceObj.induvidualAddress(); + evaluateCouplerType(); +} + +NetworkLayerEntity& NetworkLayerCoupler::getPrimaryInterface() +{ + return _netLayerEntities[0]; +} + +NetworkLayerEntity& NetworkLayerCoupler::getSecondaryInterface() +{ + return _netLayerEntities[1]; +} + +void NetworkLayerCoupler::rtObj(RouterObject& rtObj) +{ + _rtObjPrimary = &rtObj; + _rtObjSecondary = nullptr; +} + +void NetworkLayerCoupler::rtObjPrimary(RouterObject& rtObjPrimary) +{ + _rtObjPrimary = &rtObjPrimary; +} + +void NetworkLayerCoupler::rtObjSecondary(RouterObject& rtObjSecondary) +{ + _rtObjSecondary = &rtObjSecondary; +} + +void NetworkLayerCoupler::evaluateCouplerType() +{ + // Check coupler mode + if ((_deviceObj.induvidualAddress() & 0x00FF) == 0x00) + { + // Device is a router + // Check if line coupler or backbone coupler + if ((_deviceObj.induvidualAddress() & 0x0F00) == 0x0) + { + // Device is a backbone coupler -> individual address: x.0.0 + _couplerType = BackboneCoupler; + } + else + { + // Device is a line coupler -> individual address: x.y.0 + _couplerType = LineCoupler; + } + } + else + { + // Device is not a router, check if TP1 bridge or TP1 repeater +/* + if (PID_L2_COUPLER_TYPE.BIT0 == 0) + { + //then Device is TP1 Bridge + couplerType = TP1Bridge; + } + else + { + // Device is TP1 Repeater + couplerType = TP1Repeater; + } +*/ + } +} + +bool NetworkLayerCoupler::isGroupAddressInFilterTable(uint16_t groupAddress) +{ + if (_rtObjSecondary == nullptr) + return (_rtObjPrimary!= nullptr) ? _rtObjPrimary->isGroupAddressInFilterTable(groupAddress) : false; + else + { + return _rtObjSecondary->isGroupAddressInFilterTable(groupAddress); + } +} + +bool NetworkLayerCoupler::isRoutedIndividualAddress(uint16_t individualAddress) +{ + // TODO: ACKs for frames with individual addresses of the sub line (secondary I/F) + // Check spec. about his + // See PID_MAIN_LCCONFIG/PID_SUB_LCCONFIG: PHYS_IACK + // 0 = not used + // 1 = normal mode (all frames that will be routed or that are addressed to the Coupler itself will be acknowledged) + // 2 = all frames will be acknowledged (useful only to avoid the repetitions of misrouted frames) + // 3 = all frames on point-to-point connectionless – or connection-oriented communication mode shall be negatively acknowledge (NACK). + // This shall serve for protection purposes. (It is useful to prevent all parameterisation in one Subnetwork; the Coupler shall be protected + // too. A typical use case is the protection of a Subnetwork that is located outside a building) + + // Also ACK for our own individual address + if (individualAddress == _deviceObj.induvidualAddress()) + return true; + + // use 2 for now + return true; +} + +void NetworkLayerCoupler::sendMsgHopCount(AckType ack, AddressType addrType, uint16_t destination, NPDU& npdu, Priority priority, + SystemBroadcast broadcastType, uint8_t sourceInterfaceIndex, uint16_t source) +{ + // If we have a frame from open medium on secondary side (e.g. RF) to primary side, then shall use the hop count of the primary router object + if ((_rtObjPrimary != nullptr) && (_rtObjSecondary != nullptr) && (sourceInterfaceIndex == kSecondaryIfIndex)) + { + DptMedium mediumType = getSecondaryInterface().mediumType(); + if (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); + } + } + } + else // Normal hopCount between main and sub line and vice versa + { + if (npdu.hopCount() == 0) + { + // IGNORE_ACKED + return; + } + if (npdu.hopCount() < 7) + { + // ROUTE_DECREMENTED + npdu.hopCount(npdu.hopCount() - 1); + } + else if (npdu.hopCount() == 7) + { + // ROUTE_UNMODIFIED + } +} + + // Use other interface + uint8_t interfaceIndex = (sourceInterfaceIndex == kSecondaryIfIndex) ? kPrimaryIfIndex : kSecondaryIfIndex; + if (sourceInterfaceIndex == 0) + print("Routing from P->S: "); + else + print("Routing from S->P: "); + print(source, HEX); print(" -> "); print(destination, HEX); + print(" - "); + npdu.frame().apdu().printPDU(); + _netLayerEntities[interfaceIndex].sendDataRequest(npdu, ack, destination, source, priority, addrType, broadcastType); +} + +// TODO: for later: improve by putting routing algorithms in its own class/functions and only instantiate required algorithm (line vs. coupler) +// TODO: we could also do the sanity checks here, i.e. check if sourceAddress is really coming in from correct srcIfIdx, etc. (see PID_COUPL_SERV_CONTROL: EN_SNA_INCONSISTENCY_CHECK) +void NetworkLayerCoupler::routeDataIndividual(AckType ack, uint16_t destination, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIndex) +{ + // TODO: improve: we have to be notified about anything that might affect routing decision + // Ugly: we could ALWAYS evaluate coupler type for every received frame + if (_currentAddress != _deviceObj.induvidualAddress()) + { + evaluateCouplerType(); + } + + // See KNX spec.: Network Layer (03/03/03) and AN161 (Coupler model 2.0) + /* + * C hop count value contained in the N-protocol header + * D low order octet of the Destination Address, i.e. Device Address part + * G Group Address + * SD low nibble of high order octet plus low order octet, i.e. Line Address + Device Address + * Z high nibble of high order octet of the Destination Address, i.e. Area Address + * ZS high order octet of the Destination Address, i.e. hierarchy information part: Area Address + Line Address + */ + uint16_t ownSNA = _deviceObj.induvidualAddress() & 0xFF00; // Own subnetwork address (area + line) + uint16_t ownAA = _deviceObj.induvidualAddress() & 0xF000; // Own area address + uint16_t ZS = destination & 0xFF00; // destination subnetwork address (area + line) + uint16_t Z = destination & 0xF000; // destination area address + uint16_t D = destination & 0x00FF; // destination device address (without subnetwork part) + uint16_t SD = destination & 0x0FFF; // destination device address (with line part, but without area part) + + if (_couplerType == LineCoupler) + { + // Main line to sub line routing + if (srcIfIndex == kPrimaryIfIndex) + { + if (ZS != ownSNA) + { + // IGNORE_TOTALLY + return; + } + + if (D == 0) + { + // FORWARD_LOCALLY + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + _transportLayer.dataIndividualIndication(destination, hopType, priority, source, npdu.tpdu()); + } + else + { // ROUTE_XXX + sendMsgHopCount(ack, AddressType::InduvidualAddress, destination, npdu, priority, Broadcast, srcIfIndex, source); + } + return; + } + + // Sub line to main line routing + if (srcIfIndex == kSecondaryIfIndex) + { + if (ZS != ownSNA) + { + // ROUTE_XXX + sendMsgHopCount(ack, AddressType::InduvidualAddress, destination, npdu, priority, Broadcast, srcIfIndex, source); + } + else if (D == 0) + { + // FORWARD_LOCALLY + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + _transportLayer.dataIndividualIndication(destination, hopType, priority, source, npdu.tpdu()); + } + else + { + // IGNORE_TOTALLY + } + return; + } + + // Local to main or sub line + if (srcIfIndex == kLocalIfIndex) + { + // if destination is not within our subnet then send via primary interface, else via secondary interface + uint8_t destIfidx = (ZS != ownSNA) ? kPrimaryIfIndex : kSecondaryIfIndex; + _netLayerEntities[destIfidx].sendDataRequest(npdu, ack, destination, source, priority, AddressType::InduvidualAddress, Broadcast); + return; + } + } + + if (_couplerType == BackboneCoupler) + { + // Backbone line to main line routing + if (srcIfIndex == kPrimaryIfIndex) + { + if (Z != ownAA) + { + // IGNORE_TOTALLY + return; + } + + if (SD == 0) + { + // FORWARD_LOCALLY + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + _transportLayer.dataIndividualIndication(destination, hopType, priority, source, npdu.tpdu()); + } + else + { + // ROUTE_XXX + sendMsgHopCount(ack, AddressType::InduvidualAddress, destination, npdu, priority, Broadcast, srcIfIndex, source); + } + return; + } + + // Main line to backbone line routing + if (srcIfIndex == kSecondaryIfIndex) + { + if (Z != ownAA) + { + // ROUTE_XXX + sendMsgHopCount(ack, AddressType::InduvidualAddress, destination, npdu, priority, Broadcast, srcIfIndex, source); + } + else if(SD == 0) + { + // FORWARD_LOCALLY + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + _transportLayer.dataIndividualIndication(destination, hopType, priority, source, npdu.tpdu()); + } + else + { + // IGNORE_TOTALLY + } + return; + } + + // Local to main or sub line + if (srcIfIndex == kLocalIfIndex) + { + // if destination is not within our area then send via primary interface, else via secondary interface + uint8_t destIfidx = (Z != ownAA) ? kPrimaryIfIndex : kSecondaryIfIndex; + _netLayerEntities[destIfidx].sendDataRequest(npdu, ack, destination, source, priority, AddressType::InduvidualAddress, Broadcast); + return; + } + } +} + +void NetworkLayerCoupler::dataIndication(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) +{ + // routing for individual addresses + if (addrType == InduvidualAddress) + { + routeDataIndividual(ack, destination, npdu, priority, source, srcIfIdx); + return; + } + + // routing for group addresses + // TODO: check new AN189 + // "AN189 only makes that group messages with hop count 7 cannot bypass the Filter Table unfiltered, + // what made the Security Proxy(AN192) useless; now, hc 7 Telegrams are filtered as any other and the value is decremented. + if (isGroupAddressInFilterTable(destination)) + { + // ROUTE_XXX + sendMsgHopCount(ack, addrType, destination, npdu, priority, Broadcast, srcIfIdx, source); + return; + } + else + { + // IGNORE_TOTALLY + return; + } + + println("Unhandled routing case! Should not happen!"); +} + +void NetworkLayerCoupler::dataConfirm(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) +{ + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + + // Check if received frame is an echo from our sent frame, we are a normal device in this case + if (source == _deviceObj.induvidualAddress()) + { + if (addrType == InduvidualAddress) + { + _transportLayer.dataIndividualConfirm(ack, destination, hopType, priority, npdu.tpdu(), status); + return; + } + // else: we do not have any local group communication, so do not handle this + } + + // Do not process the frame any further if it was a routed frame sent from network layer +} + +void NetworkLayerCoupler::broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) +{ + // Send it to our local stack first + { + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + DptMedium mediumType = _netLayerEntities[srcIfIdx].mediumType(); + + // for closed media like TP1 and IP + if ( ((mediumType == DptMedium::KNX_TP1) || (mediumType == DptMedium::KNX_IP)) && + isApciSystemBroadcast(npdu.tpdu().apdu())) + { + npdu.frame().systemBroadcast(SysBroadcast); + _transportLayer.dataSystemBroadcastIndication(hopType, priority, source, npdu.tpdu()); + return; + } + + _transportLayer.dataBroadcastIndication(hopType, priority, source, npdu.tpdu()); + } + + // Route to other interface + sendMsgHopCount(ack, GroupAddress, 0, npdu, priority, Broadcast, srcIfIdx, source); +} + +void NetworkLayerCoupler::broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) +{ + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + + // Check if received frame is an echo from our sent frame, we are a normal device in this case + if (source == _deviceObj.induvidualAddress()) + { + _transportLayer.dataBroadcastConfirm(ack, hopType, priority, npdu.tpdu(), status); + } + // Do not process the frame any further +} + +void NetworkLayerCoupler::systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) +{ + // Send it to our local stack first + { + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + _transportLayer.dataSystemBroadcastIndication(hopType, priority, source, npdu.tpdu()); + } + // Route to other interface + sendMsgHopCount(ack, GroupAddress, 0, npdu, priority, SysBroadcast, srcIfIdx, source); +} + +void NetworkLayerCoupler::systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) +{ + // Check if received frame is an echo from our sent frame, we are a normal device in this case + if (source == _deviceObj.induvidualAddress()) + { + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + _transportLayer.dataSystemBroadcastConfirm(ack, hopType, npdu.tpdu(), priority, status); + } + // Do not process the frame any further +} + +void NetworkLayerCoupler::dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) +{ + NPDU& npdu = tpdu.frame().npdu(); + + if (hopType == UnlimitedRouting) + npdu.hopCount(7); + else + npdu.hopCount(hopCount()); + + //if (tpdu.apdu().length() > 0) + //{ + // print.print("-> NL "); + // tpdu.apdu().printPDU(); + //} + routeDataIndividual(ack, destination, npdu, priority, _deviceObj.induvidualAddress(), kLocalIfIndex); +} + +void NetworkLayerCoupler::dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) +{ + NPDU& npdu = tpdu.frame().npdu(); + + if (hopType == UnlimitedRouting) + npdu.hopCount(7); + else + npdu.hopCount(hopCount()); + + // If the group address is in the filter table, then we route it to the primary side too + if (isGroupAddressInFilterTable(destination)) + { + _netLayerEntities[kPrimaryIfIndex].sendDataRequest(npdu, ack, destination, _deviceObj.induvidualAddress(), priority, GroupAddress, Broadcast); + } + // We send it to our sub line in any case + _netLayerEntities[kSecondaryIfIndex].sendDataRequest(npdu, ack, destination, _deviceObj.induvidualAddress(), priority, GroupAddress, Broadcast); +} + +void NetworkLayerCoupler::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) +{ + NPDU& npdu = tpdu.frame().npdu(); + + if (hopType == UnlimitedRouting) + npdu.hopCount(7); + else + npdu.hopCount(hopCount()); + + _netLayerEntities[kPrimaryIfIndex].sendDataRequest(npdu, ack, 0, _deviceObj.induvidualAddress(), priority, GroupAddress, Broadcast); + _netLayerEntities[kSecondaryIfIndex].sendDataRequest(npdu, ack, 0, _deviceObj.induvidualAddress(), priority, GroupAddress, Broadcast); +} + +void NetworkLayerCoupler::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) +{ + NPDU& npdu = tpdu.frame().npdu(); + + if (hopType == UnlimitedRouting) + npdu.hopCount(7); + else + npdu.hopCount(hopCount()); + + _netLayerEntities[kPrimaryIfIndex].sendDataRequest(npdu, ack, 0, _deviceObj.induvidualAddress(), priority, GroupAddress, SysBroadcast); + _netLayerEntities[kSecondaryIfIndex].sendDataRequest(npdu, ack, 0, _deviceObj.induvidualAddress(), priority, GroupAddress, SysBroadcast); +} diff --git a/src/knx/network_layer_coupler.h b/src/knx/network_layer_coupler.h new file mode 100644 index 0000000..47de6dc --- /dev/null +++ b/src/knx/network_layer_coupler.h @@ -0,0 +1,75 @@ +#pragma once + +#include +#include "knx_types.h" +#include "npdu.h" +#include "transport_layer.h" +#include "network_layer_entity.h" +#include "network_layer.h" + +class DeviceObject; +class RouterObject; + +class NetworkLayerCoupler : public NetworkLayer +{ + friend class NetworkLayerEntity; + + public: + NetworkLayerCoupler(DeviceObject& deviceObj, TransportLayer& layer); + + NetworkLayerEntity& getPrimaryInterface(); + NetworkLayerEntity& getSecondaryInterface(); + + bool isRoutedIndividualAddress(uint16_t individualAddress); + + 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 + virtual void dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override; + virtual void dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override; + virtual void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override; + virtual 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 + virtual void dataIndication(AckType ack, AddressType addType, uint16_t destination, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source, uint8_t srcIfIdx) override; + virtual void dataConfirm(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, Priority priority, + uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override; + virtual void broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source, uint8_t srcIfIdx) override; + virtual void broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override; + virtual void systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source, uint8_t srcIfIdx) override; + virtual 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); + + // Support a maximum of two physical interfaces for couplers + NetworkLayerEntity _netLayerEntities[2]; + + RouterObject* _rtObjPrimary {nullptr}; + RouterObject* _rtObjSecondary {nullptr}; + + CouplerType _couplerType; + uint16_t _currentAddress; +}; diff --git a/src/knx/network_layer_device.cpp b/src/knx/network_layer_device.cpp new file mode 100644 index 0000000..704daac --- /dev/null +++ b/src/knx/network_layer_device.cpp @@ -0,0 +1,148 @@ +#include "network_layer_device.h" +#include "device_object.h" +#include "tpdu.h" +#include "cemi_frame.h" +#include "bits.h" + +NetworkLayerDevice::NetworkLayerDevice(DeviceObject &deviceObj, TransportLayer& layer) : + NetworkLayer(deviceObj, layer), + _netLayerEntities { {*this, kInterfaceIndex} } +{ +} + +NetworkLayerEntity& NetworkLayerDevice::getInterface() +{ + return _netLayerEntities[kInterfaceIndex]; +} + +void NetworkLayerDevice::dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) +{ + NPDU& npdu = tpdu.frame().npdu(); + + if (hopType == UnlimitedRouting) + npdu.hopCount(7); + else + npdu.hopCount(hopCount()); + + //if (tpdu.apdu().length() > 0) + //{ + // print.print("-> NL "); + // tpdu.apdu().printPDU(); + //} + _netLayerEntities[kInterfaceIndex].sendDataRequest(npdu, ack, destination, _deviceObj.induvidualAddress(), priority, InduvidualAddress, Broadcast); +} + +void NetworkLayerDevice::dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) +{ + NPDU& npdu = tpdu.frame().npdu(); + + if (hopType == UnlimitedRouting) + npdu.hopCount(7); + else + npdu.hopCount(hopCount()); + + _netLayerEntities[kInterfaceIndex].sendDataRequest(npdu, ack, destination, _deviceObj.induvidualAddress(), priority, GroupAddress, Broadcast); +} + +void NetworkLayerDevice::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) +{ + NPDU& npdu = tpdu.frame().npdu(); + + if (hopType == UnlimitedRouting) + npdu.hopCount(7); + else + npdu.hopCount(hopCount()); + + _netLayerEntities[kInterfaceIndex].sendDataRequest(npdu, ack, 0, _deviceObj.induvidualAddress(), priority, GroupAddress, Broadcast); +} + +void NetworkLayerDevice::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) +{ + // for closed media like TP1 and IP + bool isClosedMedium = (_netLayerEntities[kInterfaceIndex].mediumType() == DptMedium::KNX_TP1) || (_netLayerEntities[kInterfaceIndex].mediumType() == DptMedium::KNX_IP); + SystemBroadcast broadcastType = (isClosedMedium && isApciSystemBroadcast(tpdu.apdu()) ? Broadcast : SysBroadcast); + + NPDU& npdu = tpdu.frame().npdu(); + + if (hopType == UnlimitedRouting) + npdu.hopCount(7); + else + npdu.hopCount(hopCount()); + + _netLayerEntities[kInterfaceIndex].sendDataRequest(npdu, ack, 0, _deviceObj.induvidualAddress(), priority, GroupAddress, broadcastType); +} + +void NetworkLayerDevice::dataIndication(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) +{ + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + + if (addrType == InduvidualAddress) + { + if (destination != _deviceObj.induvidualAddress()) + return; + + _transportLayer.dataIndividualIndication(destination, hopType, priority, source, npdu.tpdu()); + return; + } + + // group-address type + if (destination != 0) + { + _transportLayer.dataGroupIndication(destination, hopType, priority, source, npdu.tpdu()); + return; + } +} + +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 == InduvidualAddress) + { + _transportLayer.dataIndividualConfirm(ack, destination, hopType, priority, npdu.tpdu(), status); + return; + } + // group-address type + if (destination != 0) + { + _transportLayer.dataGroupConfirm(ack, source, destination, hopType, priority, npdu.tpdu(), status); + return; + } +} + +void NetworkLayerDevice::broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) +{ + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + DptMedium mediumType = _netLayerEntities[srcIfIdx].mediumType(); + + // for closed media like TP1 and IP there is no system broadcast + // however we must be able to access those APCI via broadcast mode + // so we "translate" it to system broadcast like a coupler does when routing + // between closed and open media + if ( ((mediumType == DptMedium::KNX_TP1) || (mediumType == DptMedium::KNX_IP)) && + isApciSystemBroadcast(npdu.tpdu().apdu())) + { + npdu.frame().systemBroadcast(SysBroadcast); + _transportLayer.dataSystemBroadcastIndication(hopType, priority, source, npdu.tpdu()); + return; + } + + _transportLayer.dataBroadcastIndication(hopType, priority, source, npdu.tpdu()); +} + +void NetworkLayerDevice::broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) +{ + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + _transportLayer.dataBroadcastConfirm(ack, hopType, priority, npdu.tpdu(), status); +} + +void NetworkLayerDevice::systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx) +{ + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + _transportLayer.dataSystemBroadcastIndication(hopType, priority, source, npdu.tpdu()); +} + +void NetworkLayerDevice::systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) +{ + HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter; + _transportLayer.dataSystemBroadcastConfirm(ack, hopType, npdu.tpdu(), priority, status); +} diff --git a/src/knx/network_layer_device.h b/src/knx/network_layer_device.h new file mode 100644 index 0000000..ad7f70c --- /dev/null +++ b/src/knx/network_layer_device.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include "knx_types.h" +#include "npdu.h" +#include "transport_layer.h" +#include "network_layer_entity.h" +#include "network_layer.h" + +class DeviceObject; + +class NetworkLayerDevice : public NetworkLayer +{ + friend class NetworkLayerEntity; + + public: + NetworkLayerDevice(DeviceObject& deviceObj, TransportLayer& layer); + + NetworkLayerEntity& getInterface(); + + // from transport layer + virtual void dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override; + virtual void dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override; + virtual void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override; + virtual void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override; + + private: + // from entities + virtual void dataIndication(AckType ack, AddressType addType, uint16_t destination, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source, uint8_t srcIfIdx) override; + virtual void dataConfirm(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, Priority priority, + uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override; + virtual void broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source, uint8_t srcIfIdx) override; + virtual void broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override; + virtual void systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, + Priority priority, uint16_t source, uint8_t srcIfIdx) override; + virtual 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 new file mode 100644 index 0000000..6e51736 --- /dev/null +++ b/src/knx/network_layer_entity.cpp @@ -0,0 +1,64 @@ +#include "network_layer.h" +#include "network_layer_entity.h" +#include "tpdu.h" +#include "data_link_layer.h" +#include "bits.h" + +NetworkLayerEntity::NetworkLayerEntity(NetworkLayer &netLayer, uint8_t entityIndex) : _netLayer(netLayer), _entityIndex(entityIndex) +{ +} + +void NetworkLayerEntity::dataLinkLayer(DataLinkLayer& layer) +{ + _dataLinkLayer = &layer; +} + +DataLinkLayer& NetworkLayerEntity::dataLinkLayer() +{ + return *_dataLinkLayer; +} + +DptMedium NetworkLayerEntity::mediumType() const +{ + return _dataLinkLayer->mediumType(); +} + +void NetworkLayerEntity::dataIndication(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source) +{ + _netLayer.dataIndication(ack, addrType, destination, format, npdu, priority, source, _entityIndex); +} + +void NetworkLayerEntity::dataConfirm(AckType ack, AddressType addressType, uint16_t destination, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status) +{ + _netLayer.dataConfirm(ack, addressType, destination, format, priority, source, npdu, status, _entityIndex); +} + +void NetworkLayerEntity::broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source) +{ + _netLayer.broadcastIndication(ack, format, npdu, priority, source, _entityIndex); +} + +void NetworkLayerEntity::broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status) +{ + _netLayer.broadcastConfirm(ack, format, priority, source, npdu, status, _entityIndex); +} + +void NetworkLayerEntity::systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source) +{ + _netLayer.systemBroadcastIndication(ack, format, npdu, priority, source, _entityIndex); +} + +void NetworkLayerEntity::systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status) +{ + _netLayer.systemBroadcastConfirm(ack, format, priority, source, npdu, status, _entityIndex); +} + +void NetworkLayerEntity::sendDataRequest(NPDU &npdu, AckType ack, uint16_t destination, uint16_t source, Priority priority, AddressType addrType, SystemBroadcast systemBroadcast) +{ + FrameFormat frameFormat = npdu.octetCount() > 15 ? ExtendedFrame : StandardFrame; + + if (systemBroadcast == Broadcast) + _dataLinkLayer->dataRequest(ack, addrType, destination, source, frameFormat, priority, npdu); + else + _dataLinkLayer->systemBroadcastRequest(ack, frameFormat, priority, npdu, source); +} diff --git a/src/knx/network_layer_entity.h b/src/knx/network_layer_entity.h new file mode 100644 index 0000000..e20d611 --- /dev/null +++ b/src/knx/network_layer_entity.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include "knx_types.h" +#include "npdu.h" + +class DataLinkLayer; +class NetworkLayer; + +class NetworkLayerEntity +{ + friend class NetworkLayerCoupler; + friend class NetworkLayerDevice; + + public: + NetworkLayerEntity(NetworkLayer &netLayer, uint8_t entityIndex); + + void dataLinkLayer(DataLinkLayer& layer); + DataLinkLayer& dataLinkLayer(); + + DptMedium mediumType() const; + + // 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); + + DataLinkLayer* _dataLinkLayer = 0; + NetworkLayer& _netLayer; + uint8_t _entityIndex; +}; diff --git a/src/knx/property.h b/src/knx/property.h index 17104c9..56c6b24 100644 --- a/src/knx/property.h +++ b/src/knx/property.h @@ -174,6 +174,22 @@ enum PropertyID PID_GO_SECURITY_FLAGS = 61, // Defines the required security requirements for each group object PID_ROLE_TABLE = 62, // Role table PID_TOOL_SEQUENCE_NUMBER_SENDING = 250, // Sequence Number used for the next outgoing secure communication (Tool Access only, non-standardized!) + + /** Router Object */ + PID_MEDIUM_STATUS = 51, + PID_MAIN_LCCONFIG = 52, + PID_SUB_LCCONFIG = 53, + PID_MAIN_LCGRPCONFIG = 54, + PID_SUB_LCGRPCONFIG = 55, + PID_ROUTETABLE_CONTROL = 56, + PID_COUPLER_SERVICES_CONTROL = 57, + PID_MAX_APDU_LENGTH_ROUTER = 58, + PID_L2_COUPLER_TYPE = 59, // Only interesting for mask 0x0912 (TP1/TP1 coupler) + PID_HOP_COUNT = 61, // Only interesting in primary if other medium(secondary) is open medium without hopcount + PID_MEDIUM = 63, + PID_FILTER_TABLE_USE = 67, + PID_RF_ENABLE_SBC = 112, // Exists only if medium for this router object is RF (PDT_FUNCTION) + PID_IP_ENABLE_SBC = 120, // Exists only if medium for this router object is IP (PDT_FUNCTION) }; enum LoadState diff --git a/src/knx/rf_data_link_layer.cpp b/src/knx/rf_data_link_layer.cpp index 0c06de1..fb3b3be 100644 --- a/src/knx/rf_data_link_layer.cpp +++ b/src/knx/rf_data_link_layer.cpp @@ -73,9 +73,9 @@ bool RfDataLinkLayer::sendFrame(CemiFrame& frame) return true; } -RfDataLinkLayer::RfDataLinkLayer(DeviceObject& devObj, RfMediumObject& rfMediumObj, AddressTableObject& addrTab, - NetworkLayer& layer, Platform& platform) - : DataLinkLayer(devObj, addrTab, layer, platform), +RfDataLinkLayer::RfDataLinkLayer(DeviceObject& devObj, RfMediumObject& rfMediumObj, + NetworkLayerEntity &netLayerEntity, Platform& platform) + : DataLinkLayer(devObj, netLayerEntity, platform), _rfMediumObj(rfMediumObj), _rfPhy(*this, platform) { @@ -269,6 +269,11 @@ bool RfDataLinkLayer::enabled() const return _enabled; } +DptMedium RfDataLinkLayer::mediumType() const +{ + return DptMedium::KNX_RF; +} + void RfDataLinkLayer::fillRfFrame(CemiFrame& frame, uint8_t* data) { uint16_t crc; @@ -377,4 +382,4 @@ void RfDataLinkLayer::loadNextTxFrame(uint8_t** sendBuffer, uint16_t* sendBuffer delete tx_frame; } -#endif \ No newline at end of file +#endif diff --git a/src/knx/rf_data_link_layer.h b/src/knx/rf_data_link_layer.h index 5508fdd..849d12a 100644 --- a/src/knx/rf_data_link_layer.h +++ b/src/knx/rf_data_link_layer.h @@ -16,16 +16,16 @@ class RfDataLinkLayer : public DataLinkLayer friend class RfPhysicalLayer; using DataLinkLayer::_deviceObject; - using DataLinkLayer::_groupAddressTable; using DataLinkLayer::_platform; public: - RfDataLinkLayer(DeviceObject& devObj, RfMediumObject& rfMediumObj, AddressTableObject& addrTab, NetworkLayer& layer, - Platform& platform); + RfDataLinkLayer(DeviceObject& devObj, RfMediumObject& rfMediumObj, NetworkLayerEntity& netLayerEntity, + Platform& platform); void loop(); void enabled(bool value); bool enabled() const; + virtual DptMedium mediumType() const override; private: bool _enabled = false; @@ -60,4 +60,4 @@ class RfDataLinkLayer : public DataLinkLayer uint16_t calcCrcRF(uint8_t* buffer, uint32_t offset, uint32_t len); }; -#endif \ No newline at end of file +#endif diff --git a/src/knx/rf_medium_object.cpp b/src/knx/rf_medium_object.cpp index be4d511..fb143f3 100644 --- a/src/knx/rf_medium_object.cpp +++ b/src/knx/rf_medium_object.cpp @@ -1,12 +1,12 @@ +#include "config.h" +#ifdef USE_RF + #include #include "rf_medium_object.h" #include "bits.h" #include "data_property.h" #include "function_property.h" -#include "config.h" -#ifdef USE_RF - RfMediumObject::RfMediumObject() { uint8_t rfDomainAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // see KNX RF S-Mode AN160 p.11 @@ -57,4 +57,4 @@ void RfMediumObject::rfDomainAddress(const uint8_t* value) Property* prop = property(PID_RF_DOMAIN_ADDRESS); prop->write(value); } -#endif \ No newline at end of file +#endif diff --git a/src/knx/rf_medium_object.h b/src/knx/rf_medium_object.h index a07e03b..8a1500a 100644 --- a/src/knx/rf_medium_object.h +++ b/src/knx/rf_medium_object.h @@ -2,6 +2,7 @@ #include "config.h" #ifdef USE_RF + #include "interface_object.h" class RfMediumObject: public InterfaceObject @@ -15,4 +16,4 @@ 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 \ No newline at end of file +#endif diff --git a/src/knx/rf_physical_layer.cpp b/src/knx/rf_physical_layer.cpp index f01e301..2881685 100644 --- a/src/knx/rf_physical_layer.cpp +++ b/src/knx/rf_physical_layer.cpp @@ -174,27 +174,6 @@ bool RfPhysicalLayer::manchDecode(uint8_t *encodedData, uint8_t *decodedData) return true; } -int RfPhysicalLayer::crc16(uint8_t* buffer, int offset, int 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 - int pn = 0x13d65; // 1 0011 1101 0110 0101 - - // for much data, using a lookup table would be a way faster CRC calculation - int crc = 0; - for (int i = offset; i < offset + length; i++) { - int bite = buffer[i] & 0xff; - for (int 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; -} - uint8_t RfPhysicalLayer::sIdle() { uint8_t marcState; diff --git a/src/knx/rf_physical_layer.h b/src/knx/rf_physical_layer.h index 01a3c44..ceb3196 100644 --- a/src/knx/rf_physical_layer.h +++ b/src/knx/rf_physical_layer.h @@ -206,7 +206,6 @@ class RfPhysicalLayer void manchEncode(uint8_t *uncodedData, uint8_t *encodedData); bool manchDecode(uint8_t *encodedData, uint8_t *decodedData); - int crc16(uint8_t* buffer, int offset, int length); void powerDownCC1101(); void setOutputPowerLevel(int8_t dBm); diff --git a/src/knx/router_object.cpp b/src/knx/router_object.cpp new file mode 100644 index 0000000..1bc1d5b --- /dev/null +++ b/src/knx/router_object.cpp @@ -0,0 +1,505 @@ +#include "config.h" + +#include +#include "router_object.h" +#include "bits.h" +#include "memory.h" +#include "data_property.h" +#include "callback_property.h" +#include "function_property.h" + +// Filter Table Realization Type 3 +// The Filter Table Realisation Type 3 shall be organised as a memory mapped bit-field of +// 65536 bits and thus 8 192 octets. Each bit shall uniquely correspond to one Group Address. +// The full 16 bit KNX GA encoding range shall be supported. +// +// octet_address = GA_value div 8 +// bit_position = GA_value mod 8 +static constexpr uint16_t kFilterTableSize = 65536 / 8; // Each group address is represented by one bit + +enum RouteTableServices +{ + ClearRoutingTable = 0x01, // no info bytes + SetRoutingTable = 0x02, // no info bytes + ClearGroupAddress = 0x03, // 4 bytes: start address and end address + SetGroupAddress = 0x04, // 4 bytes: start address and end address +}; + +RouterObject::RouterObject(Memory& memory) + : TableObject(memory) +{ +} + +void RouterObject::initialize1x(DptMedium mediumType, uint16_t maxApduSize) +{ + // Object index property is not included for coupler model 1.x, so value is "don't care". + initialize(CouplerModel::Model_1x, 200, mediumType, RouterObjectType::Single, maxApduSize); +} + +void RouterObject::initialize20(uint8_t objIndex, DptMedium mediumType, RouterObjectType rtType, uint16_t maxApduSize) +{ + initialize(CouplerModel::Model_20, objIndex, mediumType, rtType, maxApduSize); +} + +void RouterObject::initialize(CouplerModel model, uint8_t objIndex, DptMedium mediumType, RouterObjectType rtType, uint16_t maxApduSize) +{ + bool useHopCount = false; + bool useTable = true; + + if (model == CouplerModel::Model_20) + { + useHopCount = (rtType == RouterObjectType::Primary); + useTable = (rtType == RouterObjectType::Secondary); + } + + // These properties are always present + Property* fixedProperties[] = + { + new DataProperty( PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t) OT_ROUTER ), + new DataProperty( PID_MEDIUM_STATUS, false, PDT_GENERIC_01, 1, ReadLv3 | WriteLv0, (uint16_t) 0 ), // 0 means communication is possible, could be set by datalink layer or bau to 1 (comm impossible) + new DataProperty( PID_MAX_APDU_LENGTH_ROUTER, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, maxApduSize ), + }; + uint8_t fixedPropertiesCount = sizeof(fixedProperties) / sizeof(Property*); + + // Only present if coupler model is 1.x + Property* model1xProperties[] = + { + // TODO: implement filtering based on this config here + new DataProperty( PID_MAIN_LCCONFIG, true, PDT_BITSET8, 1, ReadLv3 | WriteLv0, (uint8_t) 0 ), // Primary: data individual (connless and connorient) + broadcast + new DataProperty( PID_SUB_LCCONFIG, true, PDT_BITSET8, 1, ReadLv3 | WriteLv0, (uint8_t) 0 ), // Secondary: data individual (connless and connorient) + broadcast + new DataProperty( PID_MAIN_LCGRPCONFIG, true, PDT_BITSET8, 1, ReadLv3 | WriteLv0, (uint8_t) 0 ), // Primary: data group + new DataProperty( PID_SUB_LCGRPCONFIG, true, PDT_BITSET8, 1, ReadLv3 | WriteLv0, (uint8_t) 0 ), // Secondary: data group + }; + uint8_t model1xPropertiesCount = sizeof(model1xProperties) / sizeof(Property*); + + // Only present if coupler model is 2.0 + // One router object per interface, currently only TP1/RF coupler specified + Property* model20Properties[] = + { + new DataProperty( PID_OBJECT_INDEX, false, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv0, objIndex ), // Must be set by concrete BAUxxxx! + new DataProperty( PID_MEDIUM, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint8_t) mediumType ), + }; + uint8_t model20PropertiesCount = sizeof(model20Properties) / sizeof(Property*); + + Property* tableProperties[] = + { + new DataProperty( PID_COUPLER_SERVICES_CONTROL, true, PDT_GENERIC_01, 1, ReadLv3 | WriteLv0, (uint8_t) 0), // written by ETS TODO: implement + new DataProperty( PID_MCB_TABLE, false, PDT_GENERIC_08, 1, ReadLv3 | WriteLv0), // TODO: improve: move to TableObject once segment size handling is clear + new DataProperty( PID_FILTER_TABLE_USE, true, PDT_BINARY_INFORMATION, 1, ReadLv3 | WriteLv0, (uint16_t) 0 ), // default: invalid filter table, do not use, written by ETS + 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); + }) + }; + uint8_t tablePropertiesCount = sizeof(tableProperties) / sizeof(Property*); + + size_t allPropertiesCount = fixedPropertiesCount; + allPropertiesCount += (model == CouplerModel::Model_1x) ? model1xPropertiesCount : model20PropertiesCount; + allPropertiesCount += useHopCount ? 1 : 0; + allPropertiesCount += useTable ? tablePropertiesCount : 0; + allPropertiesCount += ((mediumType == DptMedium::KNX_RF) || (mediumType == DptMedium::KNX_IP)) ? 1 : 0; // PID_RF_ENABLE_SBC and PID_IP_ENABLE_SBC + + Property* allProperties[allPropertiesCount]; + + memcpy(&allProperties[0], &fixedProperties[0], sizeof(fixedProperties)); + + uint8_t i = fixedPropertiesCount; + + if (model == CouplerModel::Model_1x) + { + memcpy(&allProperties[i], model1xProperties, sizeof(model1xProperties)); + i += model1xPropertiesCount; + } + else + { + memcpy(&allProperties[i], model20Properties, sizeof(model20Properties)); + i += model20PropertiesCount; + } + + if (useHopCount) + { + // TODO: Primary side: 5 for line coupler, 4 for backbone coupler, only exists if secondary is open medium without hop count + // Do we need to set a default value here or is it written by ETS? + allProperties[i++] = new DataProperty( PID_HOP_COUNT, true, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t) 5); + } + + if (useTable) + { + memcpy(&allProperties[i], tableProperties, sizeof(tableProperties)); + i += tablePropertiesCount; + } + + if (mediumType == DptMedium::KNX_RF) + { + allProperties[i++] = new FunctionProperty(this, PID_RF_ENABLE_SBC, + // Command Callback of PID_RF_ENABLE_SBC + [](RouterObject* obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void { + obj->functionRfEnableSbc(true, data, length, resultData, resultLength); + }, + // State Callback of PID_RF_ENABLE_SBC + [](RouterObject* obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void { + obj->functionRfEnableSbc(false, data, length, resultData, resultLength); + }); + } + else if (mediumType == DptMedium::KNX_IP) + { + allProperties[i++] = new FunctionProperty(this, PID_IP_ENABLE_SBC, + // Command Callback of PID_IP_ENABLE_SBC + [](RouterObject* obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void { + obj->functionIpEnableSbc(true, data, length, resultData, resultLength); + }, + // State Callback of PID_IP_ENABLE_SBC + [](RouterObject* obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void { + obj->functionIpEnableSbc(false, data, length, resultData, resultLength); + }); + } + + if (useTable) + TableObject::initializeProperties(sizeof(allProperties), allProperties); + else + InterfaceObject::initializeProperties(sizeof(allProperties), allProperties); +} + +const uint8_t* RouterObject::restore(const uint8_t* buffer) +{ + buffer = TableObject::restore(buffer); + + _filterTableGroupAddresses = (uint16_t*)data(); + + return buffer; +} + +void RouterObject::commandClearSetRoutingTable(bool bitIsSet) +{ + for (uint16_t i = 0; i < kFilterTableSize; i++) + { + data()[i] = bitIsSet ? 0xFF : 0x00; + } +} + +bool RouterObject::statusClearSetRoutingTable(bool bitIsSet) +{ + for (uint16_t i = 0; i < kFilterTableSize; i++) + { + if (data()[i] != (bitIsSet ? 0xFF : 0x00)) + return false; + } + return true; +} + +void RouterObject::commandClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet) +{ + uint16_t startOctet = startAddress / 8; + uint8_t startBitPosition = startAddress % 8; + uint16_t endOctet = endAddress / 8; + uint8_t endBitPosition = endAddress % 8; + + if (startOctet == endOctet) + { + for (uint8_t bitPos = startBitPosition; bitPos <= endBitPosition; bitPos++) + { + if (bitIsSet) + data()[startOctet] |= 1 << bitPos; + else + data()[startOctet] &= ~(1 << bitPos); + } + return; + } + + for (uint16_t i = startOctet; i <= endOctet; i++) + { + if (i == startOctet) + { + for (uint8_t bitPos = startBitPosition; bitPos <= 7; bitPos++) + { + if (bitIsSet) + data()[i] |= 1 << bitPos; + else + data()[i] &= ~(1 << bitPos); + } + } + else if (i == endOctet) + { + for (uint8_t bitPos = 0; bitPos <= endBitPosition; bitPos++) + { + if (bitIsSet) + data()[i] |= 1 << bitPos; + else + data()[i] &= ~(1 << bitPos); + } + } + else + { + if (bitIsSet) + data()[i] = 0xFF; + else + data()[i] = 0x00; + } + } +} + +bool RouterObject::statusClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet) +{ + uint16_t startOctet = startAddress / 8; + uint8_t startBitPosition = startAddress % 8; + uint16_t endOctet = endAddress / 8; + uint8_t endBitPosition = endAddress % 8; + + if (startOctet == endOctet) + { + for (uint8_t bitPos = startBitPosition; bitPos <= endBitPosition; bitPos++) + { + if (bitIsSet) + { + if ((data()[startOctet] & (1 << bitPos)) == 0) + return false; + } + else + { + if ((data()[startOctet] & (1 << bitPos)) != 0) + return false; + } + } + return true; + } + + for (uint16_t i = startOctet; i <= endOctet; i++) + { + if (i == startOctet) + { + for (uint8_t bitPos = startBitPosition; bitPos <= 7; bitPos++) + { + if (bitIsSet) + { + if ((data()[i] & (1 << bitPos)) == 0) + return false; + } + else + { + if ((data()[i] & (1 << bitPos)) != 0) + return false; + } + } + } + else if (i == endOctet) + { + for (uint8_t bitPos = 0; bitPos <= endBitPosition; bitPos++) + { + if (bitIsSet) + { + if ((data()[i] & (1 << bitPos)) == 0) + return false; + } + else + { + if ((data()[i] & (1 << bitPos)) != 0) + return false; + } + } + } + else + { + if (data()[i] != (bitIsSet ? 0xFF : 0x00)) + return false; + } + } + + return true; +} + +void RouterObject::functionRouteTableControl(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) +{ + RouteTableServices srvId = (RouteTableServices) data[1]; + + if (isCommand) + { + switch(srvId) + { + case ClearRoutingTable: + commandClearSetRoutingTable(false); + resultData[0] = ReturnCodes::Success; + resultData[1] = srvId; + resultLength = 2; + return; + case SetRoutingTable: + commandClearSetRoutingTable(true); + resultData[0] = ReturnCodes::Success; + resultData[1] = srvId; + resultLength = 2; + return; + case ClearGroupAddress: + { + uint16_t startAddress; + uint16_t endAddress; + popWord(startAddress, &data[2]); + popWord(endAddress, &data[4]); + commandClearSetGroupAddress(startAddress, endAddress, false); + resultData[0] = ReturnCodes::Success; + resultData[1] = srvId; + pushWord(startAddress, &resultData[2]); + pushWord(endAddress, &resultData[4]); + resultLength = 6; + return; + } + case SetGroupAddress: + { + uint16_t startAddress; + uint16_t endAddress; + popWord(startAddress, &data[2]); + popWord(endAddress, &data[4]); + commandClearSetGroupAddress(startAddress, endAddress, true); + resultData[0] = ReturnCodes::Success; + resultData[1] = srvId; + pushWord(startAddress, &resultData[2]); + pushWord(endAddress, &resultData[4]); + resultLength = 6; + return; + } + } + } + else + { + switch(srvId) + { + case ClearRoutingTable: + resultData[0] = statusClearSetRoutingTable(false) ? ReturnCodes::Success : ReturnCodes::GenericError; + resultData[1] = srvId; + resultLength = 2; + return; + case SetRoutingTable: + resultData[0] = statusClearSetRoutingTable(true) ? ReturnCodes::Success : ReturnCodes::GenericError; + resultData[1] = srvId; + resultLength = 2; + return; + case ClearGroupAddress: + { + uint16_t startAddress; + uint16_t endAddress; + popWord(startAddress, &data[2]); + popWord(endAddress, &data[4]); + resultData[0] = statusClearSetGroupAddress(startAddress, endAddress, false) ? ReturnCodes::Success : ReturnCodes::GenericError; + resultData[1] = srvId; + pushWord(startAddress, &resultData[2]); + pushWord(endAddress, &resultData[4]); + resultLength = 6; + return; + } + case SetGroupAddress: + { + uint16_t startAddress; + uint16_t endAddress; + popWord(startAddress, &data[2]); + popWord(endAddress, &data[4]); + resultData[0] = statusClearSetGroupAddress(startAddress, endAddress, true) ? ReturnCodes::Success : ReturnCodes::GenericError; + resultData[1] = srvId; + pushWord(startAddress, &resultData[2]); + pushWord(endAddress, &resultData[4]); + resultLength = 6; + return; + } + } + } + + // We should not get here + resultData[0] = ReturnCodes::GenericError; + resultData[1] = srvId; + resultLength = 2; +} + +void RouterObject::functionRfEnableSbc(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) +{ + if (isCommand) + { + _rfSbcRoutingEnabled = (data[0] == 1) ? true : false; + } + + resultData[0] = ReturnCodes::Success; + resultData[1] = _rfSbcRoutingEnabled ? 1 : 0; + resultLength = 2; +} + +bool RouterObject::isRfSbcRoutingEnabled() +{ + return _rfSbcRoutingEnabled; +} + +// TODO: check if IP SBC works the same way, just copied from RF +void RouterObject::functionIpEnableSbc(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) +{ + if (isCommand) + { + _ipSbcRoutingEnabled = (data[0] == 1) ? true : false; + } + + resultData[0] = ReturnCodes::Success; + resultData[1] = _ipSbcRoutingEnabled ? 1 : 0; + resultLength = 2; +} + +// TODO: check if IP SBC works the same way, just copied from RF +bool RouterObject::isIpSbcRoutingEnabled() +{ + return _ipSbcRoutingEnabled; +} + +void RouterObject::beforeStateChange(LoadState& newState) +{ + if (newState != LS_LOADED) + return; + + // calculate crc16-ccitt for PID_MCB_TABLE + updateMcb(); + + _filterTableGroupAddresses = (uint16_t*)data(); +} + +void RouterObject::updateMcb() +{ + uint8_t mcb[propertySize(PID_MCB_TABLE)]; + + static constexpr uint32_t segmentSize = kFilterTableSize; + uint16_t crc16 = crc16Ccitt(data(), segmentSize); + + pushInt(segmentSize, &mcb[0]); // Segment size + pushByte(0x00, &mcb[4]); // CRC control byte -> 0: always valid -> according to coupler spec. it shall always be a valid CRC + pushByte(0xFF, &mcb[5]); // Read access 4 bits + Write access 4 bits (unknown: value taken from real coupler device) + pushWord(crc16, &mcb[6]); // CRC-16 CCITT of filter table + + property(PID_MCB_TABLE)->write(mcb); +} + +void RouterObject::masterReset(EraseCode eraseCode, uint8_t channel) +{ + if (eraseCode == FactoryReset) + { + // TODO: handle different erase codes + println("Factory reset of router object with filter table requested."); + } +} + +bool RouterObject::isGroupAddressInFilterTable(uint16_t groupAddress) +{ + if (loadState() != LS_LOADED) + return false; + + uint8_t filterTableUse = 0x00; + if (property(PID_FILTER_TABLE_USE)->read(filterTableUse) == 0) + return false; + + if ((filterTableUse&0x01) == 1) + { + // octet_address = GA_value div 8 + // bit_position = GA_value mod 8 + uint16_t octetAddress = groupAddress / 8; + uint8_t bitPosition = groupAddress % 8; + + return (data()[octetAddress] & (1 << bitPosition)) == (1 << bitPosition); + } + + return false; +} diff --git a/src/knx/router_object.h b/src/knx/router_object.h new file mode 100644 index 0000000..22faa56 --- /dev/null +++ b/src/knx/router_object.h @@ -0,0 +1,60 @@ +#pragma once + +#include "config.h" + +#include "table_object.h" +#include "knx_types.h" + +class Memory; + +enum CouplerModel +{ + Model_1x, + Model_20 +}; + +enum RouterObjectType +{ + Primary, + Secondary, + Single // Not used, just a placeholder for better readability for coupler model 1.x +}; + +class RouterObject : public TableObject +{ +public: + RouterObject(Memory& memory); + + void initialize1x(DptMedium mediumType, uint16_t maxApduSize); + void initialize20(uint8_t objIndex, DptMedium mediumType, RouterObjectType rtType, uint16_t maxApduSize); + void initialize(CouplerModel model, uint8_t objIndex, DptMedium mediumType, RouterObjectType rtType, uint16_t maxApduSize); + + bool isGroupAddressInFilterTable(uint16_t groupAddress); + + bool isRfSbcRoutingEnabled(); + bool isIpSbcRoutingEnabled(); + + virtual void masterReset(EraseCode eraseCode, uint8_t channel) override; + + const uint8_t* restore(const uint8_t* buffer) override; + +protected: + virtual void beforeStateChange(LoadState& newState) override; + +private: + // Function properties + void functionRouteTableControl(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength); + void functionRfEnableSbc(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength); + void functionIpEnableSbc(bool isCommand, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength); + + void commandClearSetRoutingTable(bool bitIsSet); + bool statusClearSetRoutingTable(bool bitIsSet); + void commandClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet); + bool statusClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet); + + void updateMcb(); + + bool _rfSbcRoutingEnabled = false; + bool _ipSbcRoutingEnabled = false; + uint16_t* _filterTableGroupAddresses = 0; +}; diff --git a/src/knx/secure_application_layer.cpp b/src/knx/secure_application_layer.cpp index a5dfbc1..69bad03 100644 --- a/src/knx/secure_application_layer.cpp +++ b/src/knx/secure_application_layer.cpp @@ -23,18 +23,25 @@ static constexpr uint8_t kSecureDataPdu = 0; static constexpr uint8_t kSecureSyncRequest = 2; static constexpr uint8_t kSecureSyncResponse = 3; -SecureApplicationLayer::SecureApplicationLayer(DeviceObject &deviceObj, SecurityInterfaceObject &secIfObj, AssociationTableObject& assocTable, AddressTableObject &addrTab, BusAccessUnit& bau): - ApplicationLayer(assocTable, bau), +SecureApplicationLayer::SecureApplicationLayer(DeviceObject &deviceObj, SecurityInterfaceObject &secIfObj, BusAccessUnit& bau): + ApplicationLayer(bau), _secIfObj(secIfObj), - _deviceObj(deviceObj), - _addrTab(addrTab) + _deviceObj(deviceObj) { } +void SecureApplicationLayer::groupAddressTable(AddressTableObject &addrTable) +{ + _addrTab = &addrTable; +} + /* from transport layer */ void SecureApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) { + if (_addrTab == nullptr) + return; + println("dataGroupIndication"); if (apdu.type() == SecureService) @@ -293,12 +300,15 @@ void SecureApplicationLayer::dataConnectedConfirm(uint16_t tsap) void SecureApplicationLayer::dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) { + if (_addrTab == nullptr) + return; + println("dataGroupRequest"); if (secCtrl.dataSecurity != DataSecurity::none) { apdu.frame().sourceAddress(_deviceObj.induvidualAddress()); - apdu.frame().destinationAddress(_addrTab.getGroupAddress(tsap)); + apdu.frame().destinationAddress(_addrTab->getGroupAddress(tsap)); apdu.frame().addressType(GroupAddress); uint16_t secureApduLength = apdu.length() + 3 + 6 + 4; // 3(TPCI,APCI,SCF) + sizeof(seqNum) + apdu.length() + 4 @@ -507,7 +517,10 @@ void SecureApplicationLayer::blockCtr0(uint8_t* buffer, uint8_t* seqNum, uint16_ uint16_t SecureApplicationLayer::groupAddressIndex(uint16_t groupAddr) { - return _addrTab.getTsap(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); } const uint8_t* SecureApplicationLayer::securityKey(uint16_t addr, bool isGroupAddress) @@ -1238,24 +1251,6 @@ bool SecureApplicationLayer::createSecureApdu(APDU& plainApdu, APDU& secureApdu, return false; } -void SecureApplicationLayer::clearFailureLog() -{ - println("clearFailureLog()"); -} - -void SecureApplicationLayer::getFailureCounters(uint8_t* data) -{ - memset(data, 0, 8); - println("getFailureCounters()"); -} - -uint8_t SecureApplicationLayer::getFromFailureLogByIndex(uint8_t index, uint8_t* data, uint8_t maxDataLen) -{ - print("getFromFailureLogByIndex(): Index: "); - println(index); - return 0; -} - uint64_t SecureApplicationLayer::getRandomNumber() { return 0x000102030405; // TODO: generate random number diff --git a/src/knx/secure_application_layer.h b/src/knx/secure_application_layer.h index 856904e..39b5fc5 100644 --- a/src/knx/secure_application_layer.h +++ b/src/knx/secure_application_layer.h @@ -28,11 +28,9 @@ class SecureApplicationLayer : public ApplicationLayer * @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, AssociationTableObject& assocTable, AddressTableObject& addrTab, BusAccessUnit& bau); + SecureApplicationLayer(DeviceObject& deviceObj, SecurityInterfaceObject& secIfObj, BusAccessUnit& bau); - void clearFailureLog(); - void getFailureCounters(uint8_t* data); - uint8_t getFromFailureLogByIndex(uint8_t index, uint8_t* data, uint8_t maxDataLen); + void groupAddressTable(AddressTableObject& addrTable); // from transport layer virtual void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) override; @@ -150,5 +148,5 @@ class SecureApplicationLayer : public ApplicationLayer SecurityInterfaceObject& _secIfObj; DeviceObject& _deviceObj; - AddressTableObject& _addrTab; + AddressTableObject* _addrTab = nullptr; }; diff --git a/src/knx/security_interface_object.cpp b/src/knx/security_interface_object.cpp index 92b67c4..2d03530 100644 --- a/src/knx/security_interface_object.cpp +++ b/src/knx/security_interface_object.cpp @@ -97,7 +97,7 @@ SecurityInterfaceObject::SecurityInterfaceObject() uint8_t info = data[2]; if (id == 0 && info == 0) { - obj->_secAppLayer->clearFailureLog(); + obj->clearFailureLog(); resultData[0] = ReturnCodes::Success; resultData[1] = id; resultLength = 2; @@ -123,7 +123,7 @@ SecurityInterfaceObject::SecurityInterfaceObject() resultData[0] = ReturnCodes::Success; resultData[1] = id; resultData[2] = info; - obj->_secAppLayer->getFailureCounters(&resultData[3]); // Put 8 bytes in the buffer + obj->getFailureCounters(&resultData[3]); // Put 8 bytes in the buffer resultLength = 3 + 8; return; } @@ -132,7 +132,7 @@ SecurityInterfaceObject::SecurityInterfaceObject() { 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->_secAppLayer->getFromFailureLogByIndex(index, &resultData[2], maxBufferSize); + uint8_t numBytes = obj->getFromFailureLogByIndex(index, &resultData[2], maxBufferSize); if ( numBytes > 0) { resultData[0] = ReturnCodes::Success; @@ -163,11 +163,6 @@ SecurityInterfaceObject::SecurityInterfaceObject() initializeProperties(sizeof(properties), properties); } -void SecurityInterfaceObject::secureApplicationLayer(SecureApplicationLayer& secAppLayer) -{ - _secAppLayer = &secAppLayer; -} - uint8_t* SecurityInterfaceObject::save(uint8_t* buffer) { buffer = pushByte(_state, buffer); @@ -206,11 +201,34 @@ bool SecurityInterfaceObject::isSecurityModeEnabled() return _securityModeEnabled; } +void SecurityInterfaceObject::clearFailureLog() +{ + println("clearFailureLog()"); +} + +void SecurityInterfaceObject::getFailureCounters(uint8_t* data) +{ + memset(data, 0, 8); + println("getFailureCounters()"); +} + +uint8_t SecurityInterfaceObject::getFromFailureLogByIndex(uint8_t index, uint8_t* data, uint8_t maxDataLen) +{ + print("getFromFailureLogByIndex(): Index: "); + println(index); + return 0; +} + bool SecurityInterfaceObject::isLoaded() { return _state == LS_LOADED; } +LoadState SecurityInterfaceObject::loadState() +{ + return _state; +} + void SecurityInterfaceObject::loadEvent(const uint8_t* data) { switch (_state) diff --git a/src/knx/security_interface_object.h b/src/knx/security_interface_object.h index 754f2ea..53f5314 100644 --- a/src/knx/security_interface_object.h +++ b/src/knx/security_interface_object.h @@ -6,15 +6,11 @@ #include "interface_object.h" #include "knx_types.h" -class SecureApplicationLayer; - class SecurityInterfaceObject: public InterfaceObject { public: SecurityInterfaceObject(); - void secureApplicationLayer(SecureApplicationLayer& secAppLayer); - virtual void masterReset(EraseCode eraseCode, uint8_t channel) override; bool isSecurityModeEnabled(); @@ -39,10 +35,12 @@ public: uint16_t saveSize() override; private: - SecureApplicationLayer* _secAppLayer = nullptr; - void setSecurityMode(bool enabled); + void clearFailureLog(); + void getFailureCounters(uint8_t* data); + uint8_t getFromFailureLogByIndex(uint8_t index, uint8_t* data, uint8_t maxDataLen); + void errorCode(ErrorCode errorCode); void loadEvent(const uint8_t* data); diff --git a/src/knx/tpuart_data_link_layer.cpp b/src/knx/tpuart_data_link_layer.cpp index 98f8c29..e719bc2 100644 --- a/src/knx/tpuart_data_link_layer.cpp +++ b/src/knx/tpuart_data_link_layer.cpp @@ -1,5 +1,7 @@ -#include "tpuart_data_link_layer.h" +#include "config.h" #ifdef USE_TP + +#include "tpuart_data_link_layer.h" #include "bits.h" #include "platform.h" #include "device_object.h" @@ -265,23 +267,19 @@ void TpUartDataLinkLayer::loop() if (!_isEcho) { uint8_t c = 0x10; - //ceck if individual or group address - if ((buffer[6] & 0x80) == 0) + + // The bau knows everything and could either check the address table object (normal device) + // or any filter tables (coupler) to see if we are addressed. + + //check if individual or group address + bool isGroupAddress = (buffer[6] & 0x80) != 0; + uint16_t addr = getWord(buffer + 4); + + if (_cb.isAckRequired(addr, isGroupAddress)) { - //individual - if (_deviceObject.induvidualAddress() == getWord(buffer + 4)) - { - c |= 0x01; - } - } - else - { - //group - if (_groupAddressTable.contains(getWord(buffer + 4)) || getWord(buffer + 4) == 0) - { - c |= 0x01; - } + c |= 0x01; } + _platform.writeUart(c); } } @@ -412,9 +410,12 @@ void TpUartDataLinkLayer::stopChip() #endif } -TpUartDataLinkLayer::TpUartDataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, - NetworkLayer& layer, Platform& platform) - : DataLinkLayer(devObj, addrTab, layer, platform) +TpUartDataLinkLayer::TpUartDataLinkLayer(DeviceObject& devObj, + NetworkLayerEntity &netLayerEntity, + Platform& platform, + ITpUartCallBacks& cb) + : DataLinkLayer(devObj, netLayerEntity, platform), + _cb(cb) { } @@ -467,6 +468,11 @@ bool TpUartDataLinkLayer::enabled() const return _enabled; } +DptMedium TpUartDataLinkLayer::mediumType() const +{ + return DptMedium::KNX_TP1; +} + bool TpUartDataLinkLayer::sendSingleFrameByte() { uint8_t cmd[2]; @@ -548,4 +554,4 @@ void TpUartDataLinkLayer::loadNextTxFrame() } delete tx_frame; } -#endif \ No newline at end of file +#endif diff --git a/src/knx/tpuart_data_link_layer.h b/src/knx/tpuart_data_link_layer.h index e84bc3e..61fe533 100644 --- a/src/knx/tpuart_data_link_layer.h +++ b/src/knx/tpuart_data_link_layer.h @@ -1,26 +1,33 @@ #pragma once #include "config.h" - #ifdef USE_TP + #include #include "data_link_layer.h" #define MAX_KNX_TELEGRAM_SIZE 263 +class ITpUartCallBacks +{ +public: + virtual ~ITpUartCallBacks() = default; + virtual bool isAckRequired(uint16_t address, bool isGrpAddr) = 0; +}; + class TpUartDataLinkLayer : public DataLinkLayer { using DataLinkLayer::_deviceObject; - using DataLinkLayer::_groupAddressTable; using DataLinkLayer::_platform; public: - TpUartDataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, NetworkLayer& layer, - Platform& platform); + TpUartDataLinkLayer(DeviceObject& devObj, NetworkLayerEntity& netLayerEntity, + Platform& platform, ITpUartCallBacks& cb); void loop(); void enabled(bool value); bool enabled() const; + virtual DptMedium mediumType() const override; private: bool _enabled = false; @@ -62,5 +69,7 @@ class TpUartDataLinkLayer : public DataLinkLayer void dataConBytesReceived(uint8_t* buffer, uint16_t length, bool success); bool resetChip(); void stopChip(); + + ITpUartCallBacks& _cb; }; -#endif \ No newline at end of file +#endif diff --git a/src/knx/transport_layer.cpp b/src/knx/transport_layer.cpp index 176ff74..1e3a7f8 100644 --- a/src/knx/transport_layer.cpp +++ b/src/knx/transport_layer.cpp @@ -7,8 +7,8 @@ #include "bits.h" #include -TransportLayer::TransportLayer(ApplicationLayer& layer, AddressTableObject& gat): _savedFrame(0), - _savedFrameConnecting(0), _applicationLayer(layer), _groupAddressTable(gat) +TransportLayer::TransportLayer(ApplicationLayer& layer): _savedFrame(0), + _savedFrameConnecting(0), _applicationLayer(layer) { _currentState = Closed; } @@ -18,6 +18,11 @@ void TransportLayer::networkLayer(NetworkLayer& layer) _networkLayer = &layer; } +void TransportLayer::groupAddressTable(AddressTableObject &addrTable) +{ + _groupAddressTable = &addrTable; +} + void TransportLayer::dataIndividualIndication(uint16_t destination, HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu) { //if (tpdu.apdu().length() > 0) @@ -361,7 +366,10 @@ void TransportLayer::dataIndividualConfirm(AckType ack, uint16_t destination, Ho void TransportLayer::dataGroupIndication(uint16_t destination, HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu) { - uint16_t tsap = _groupAddressTable.getTsap(destination); + if (_groupAddressTable == nullptr) + return; + + uint16_t tsap = _groupAddressTable->getTsap(destination); if (tsap == 0) return; @@ -395,7 +403,10 @@ void TransportLayer::dataSystemBroadcastConfirm(AckType ack, HopCountType hopTyp void TransportLayer::dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) { - uint16_t groupAdress = _groupAddressTable.getGroupAddress(tsap); + if (_groupAddressTable == nullptr) + return; + + uint16_t groupAdress = _groupAddressTable->getGroupAddress(tsap); TPDU& tpdu = apdu.frame().tpdu(); _networkLayer->dataGroupRequest(ack, groupAdress, hopType, priority, tpdu); } diff --git a/src/knx/transport_layer.h b/src/knx/transport_layer.h index 76bf861..8814cc3 100644 --- a/src/knx/transport_layer.h +++ b/src/knx/transport_layer.h @@ -16,8 +16,9 @@ enum StateType { Closed, OpenIdle, OpenWait, Connecting }; class TransportLayer { public: - TransportLayer(ApplicationLayer& layer, AddressTableObject& gat); + 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); @@ -115,6 +116,6 @@ private: uint8_t _maxRepCount = 3; #pragma endregion ApplicationLayer& _applicationLayer; - AddressTableObject& _groupAddressTable; + AddressTableObject* _groupAddressTable; NetworkLayer* _networkLayer; }; diff --git a/src/knx_facade.cpp b/src/knx_facade.cpp index a26089c..fb95b18 100644 --- a/src/knx_facade.cpp +++ b/src/knx_facade.cpp @@ -3,38 +3,43 @@ #include "knx/bits.h" #ifdef ARDUINO_ARCH_SAMD - // predefined global instance for TP or RF - #ifdef MEDIUM_TYPE - #if MEDIUM_TYPE == 0 - KnxFacade knx; - #elif MEDIUM_TYPE == 2 - KnxFacade knx; - #else - #error "Only TP and RF supported for Arduino SAMD platform!" - #endif + // predefined global instance for TP or RF or TP/RF coupler + #if MASK_VERSION == 0x07B0 + KnxFacade knx; + #elif MASK_VERSION == 0x27B0 + KnxFacade knx; + #elif MASK_VERSION == 0x2920 + KnxFacade knx; #else - #error "No medium type specified for platform Arduino_SAMD! Please set MEDIUM_TYPE! (TP:0, RF:2, IP:5)" + #error Mask version not supported on ARDUINO_ARCH_SAMD #endif + #elif ARDUINO_ARCH_ESP8266 // predefined global instance for IP only - KnxFacade knx; -#elif ARDUINO_ARCH_ESP32 - // predefined global instance for TP or IP - #ifdef MEDIUM_TYPE - #if MEDIUM_TYPE == 0 - KnxFacade knx; - #elif MEDIUM_TYPE == 5 - KnxFacade knx; - #else - #error "Only TP and IP supported for Arduino ESP32 platform!" - #endif + #if MASK_VERSION == 0x57B0 + KnxFacade knx; #else - // Compatibility - KnxFacade knx; - //#error "No medium type specified for platform Arduino ESP32! Please set MEDIUM_TYPE! (TP:0, RF:2, IP:5)" + #error Mask version not supported on ARDUINO_ARCH_ESP8266 #endif + +#elif ARDUINO_ARCH_ESP32 + // predefined global instance for TP or IP or TP/IP coupler + #if MASK_VERSION == 0x07B0 + KnxFacade knx; + #elif MASK_VERSION == 0x57B0 + KnxFacade knx; + #elif MASK_VERSION == 0x091A + KnxFacade knx; + #else + #error Mask version not supported on ARDUINO_ARCH_ESP8266 + #endif + #elif ARDUINO_ARCH_STM32 - KnxFacade knx; + #if MASK_VERSION == 0x07B0 + KnxFacade knx; + #else + #error Mask version not supported on ARDUINO_ARCH_STM32 + #endif #elif __linux__ // no predefined global instance #endif diff --git a/src/knx_facade.h b/src/knx_facade.h index 923195f..e35334a 100644 --- a/src/knx_facade.h +++ b/src/knx_facade.h @@ -2,15 +2,12 @@ #include "knx/bits.h" #include "knx/config.h" -// Set default medium type to TP if no external definitions was given -#ifndef MEDIUM_TYPE -#define MEDIUM_TYPE 0 -#endif #ifdef ARDUINO_ARCH_SAMD #include "samd_platform.h" #include "knx/bau07B0.h" #include "knx/bau27B0.h" + #include "knx/bau2920.h" #elif ARDUINO_ARCH_ESP8266 #include "esp_platform.h" #include "knx/bau57B0.h" @@ -19,6 +16,7 @@ #include "esp32_platform.h" #include "knx/bau07B0.h" #include "knx/bau57B0.h" + #include "knx/bau091A.h" #elif ARDUINO_ARCH_STM32 #include "stm32_platform.h" #include "knx/bau07B0.h" @@ -27,6 +25,9 @@ #include "linux_platform.h" #include "knx/bau57B0.h" #include "knx/bau27B0.h" + #include "knx/bau07B0.h" + #include "knx/bau091A.h" + #include "knx/bau2920.h" #endif void buttonUp(); @@ -267,10 +268,12 @@ template class KnxFacade : private SaveRestore return _bau.parameters().getInt(addr); } +#if (MASK_VERSION == 0x07B0) || (MASK_VERSION == 0x27B0) || (MASK_VERSION == 0x57B0) GroupObject& getGroupObject(uint16_t goNr) { return _bau.groupObjectTable().get(goNr); } +#endif void restart(uint16_t individualAddress) { @@ -319,37 +322,41 @@ template class KnxFacade : private SaveRestore }; #ifdef ARDUINO_ARCH_SAMD - // predefined global instance for TP or RF - #ifdef MEDIUM_TYPE - #if MEDIUM_TYPE == 0 - extern KnxFacade knx; - #elif MEDIUM_TYPE == 2 - extern KnxFacade knx; - #else - #error "Only TP and RF supported for Arduino SAMD platform!" - #endif + // predefined global instance for TP or RF or TP/RF coupler + #if MASK_VERSION == 0x07B0 + extern KnxFacade knx; + #elif MASK_VERSION == 0x27B0 + extern KnxFacade knx; + #elif MASK_VERSION == 0x2920 + extern KnxFacade knx; #else - #error "No medium type specified for Arduino_SAMD platform! Please set MEDIUM_TYPE! (TP:0, RF:2, IP:5)" + #error "Mask version not supported on ARDUINO_ARCH_SAMD" #endif #elif ARDUINO_ARCH_ESP8266 // predefined global instance for IP only - extern KnxFacade knx; -#elif ARDUINO_ARCH_ESP32 - // predefined global instance for TP or IP - #ifdef MEDIUM_TYPE - #if MEDIUM_TYPE == 0 - extern KnxFacade knx; - #elif MEDIUM_TYPE == 5 - extern KnxFacade knx; - #else - #error "Only TP and IP supported for Arduino ESP32 platform!" - #endif + #if MASK_VERSION == 0x57B0 + extern KnxFacade knx; #else - #error "No medium type specified for Arduino ESP32 platform! Please set MEDIUM_TYPE! (TP:0, RF:2, IP:5)" + #error "Mask version not supported on ARDUINO_ARCH_ESP8266" + #endif +#elif ARDUINO_ARCH_ESP32 + // predefined global instance for TP or IP or TP/IP coupler + #if MASK_VERSION == 0x07B0 + extern KnxFacade knx; + #elif MASK_VERSION == 0x57B0 + extern KnxFacade knx; + #elif MASK_VERSION == 0x091A + extern KnxFacade knx; + #else + #error "Mask version not supported on ARDUINO_ARCH_ESP32" #endif #elif ARDUINO_ARCH_STM32 // predefined global instance for TP only - extern KnxFacade knx; + #if MASK_VERSION == 0x07B0 + extern KnxFacade knx; + #else + #error Mask version not supported on ARDUINO_ARCH_STM32 + #endif #elif __linux__ // no predefined global instance #endif