├── .gitignore ├── .vscode ├── arduino.json ├── settings.json └── c_cpp_properties.json ├── library.properties ├── README.md ├── examples ├── DemoSketch │ ├── kdevice_DemoSketch.h │ ├── EEPROM_24AA256.h │ ├── DemoSketch.kdevice.xml │ └── DemoSketch.ino ├── DemoSketch_without_pins │ ├── kdevice_DemoSketch.h │ ├── EEPROM_24AA256.h │ ├── DemoSketch.kdevice.xml │ └── DemoSketch_without_pins.ino └── Communication_test │ └── Communication_test.ino ├── .gitlab-ci.yml ├── src ├── KnxDptConstants.h ├── .clang-format ├── RingBuff.h ├── DebugUtil.h ├── System.h ├── DebugUtil.cpp ├── KnxComObject.cpp ├── KnxTelegram.cpp ├── KnxComObject.h ├── KnxDevice.h ├── KnxTelegram.h ├── KonnektingDevice.h ├── KnxTpUart.h ├── KnxDataPointTypes.h └── KnxDevice.cpp ├── setup-build-env.sh ├── knx_conversionhelper.html ├── keywords.txt └── doxygen-config /.gitignore: -------------------------------------------------------------------------------- 1 | /doc/ 2 | /docs/ 3 | arduino-cli-build/ 4 | bin/ 5 | .vscode/ -------------------------------------------------------------------------------- /.vscode/arduino.json: -------------------------------------------------------------------------------- 1 | { 2 | "board": "arduino:samd:arduino_zero_native", 3 | "port": "/dev/ttyACM0" 4 | } -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=KONNEKTING Device Library 2 | version=1.0.0-BETA5 3 | author=Alexander Christian 4 | maintainer=Alexander Christian 5 | sentence=A library that enables creating KNX devices powered by Arduino. 6 | paragraph=Requires an KNX Transceiver connected via UART 7 | category=Communication 8 | url=http://www.konnekting.de/ 9 | architectures=avr, esp8266, samd, stm32 10 | includes=KonnektingDevice.h 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KONNEKTING Device Library 2 | This is a library for Arduino boards, that allow creating own DIY KNX devices, programmable via KNX bus.... 3 | 4 | For more information, please follow the link to our [documentation project](https://github.com/KONNEKTING/KonnektingDocumentation/blob/master/README.md). 5 | 6 | # !!! WARNING !!! 7 | 8 | *If you aren't an expert, stick with the pre-build/packaged releases you can download in Arduino IDE via Library Manager. 9 | Otherwise you might face weird problems and bug-reporting get's worse, because you aren't able to name the version that failed.* 10 | 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "array": "cpp", 4 | "*.tcc": "cpp", 5 | "functional": "cpp", 6 | "istream": "cpp", 7 | "tuple": "cpp", 8 | "utility": "cpp", 9 | "list": "cpp", 10 | "*.tpp": "cpp", 11 | "bitset": "cpp", 12 | "initializer_list": "cpp", 13 | "deque": "cpp", 14 | "unordered_map": "cpp", 15 | "vector": "cpp", 16 | "system_error": "cpp", 17 | "cstddef": "cpp", 18 | "string": "cpp", 19 | "string_view": "cpp", 20 | "type_traits": "cpp", 21 | "chrono": "cpp", 22 | "ratio": "cpp", 23 | "ostream": "cpp" 24 | } 25 | } -------------------------------------------------------------------------------- /examples/DemoSketch/kdevice_DemoSketch.h: -------------------------------------------------------------------------------- 1 | #define MANUFACTURER_ID 57005 2 | #define DEVICE_ID 255 3 | #define REVISION 0 4 | 5 | #define COMOBJ_ledOnOff 0 6 | #define COMOBJ_trigger 1 7 | #define PARAM_blinkDelay 0 8 | 9 | KnxComObject KnxDevice::_comObjectsList[] = { 10 | /* Index 0 - ledOnOff */ KnxComObject(KNX_DPT_1_001, 0x2a), 11 | /* Index 1 - trigger */ KnxComObject(KNX_DPT_1_001, 0x34) 12 | }; 13 | const byte KnxDevice::_numberOfComObjects = sizeof (_comObjectsList) / sizeof (KnxComObject); // do not change this code 14 | 15 | byte KonnektingDevice::_paramSizeList[] = { 16 | /* Index 0 - blinkDelay */ PARAM_UINT16 17 | }; 18 | const int KonnektingDevice::_numberOfParams = sizeof (_paramSizeList); // do not change this code -------------------------------------------------------------------------------- /examples/DemoSketch_without_pins/kdevice_DemoSketch.h: -------------------------------------------------------------------------------- 1 | #define MANUFACTURER_ID 57005 2 | #define DEVICE_ID 255 3 | #define REVISION 0 4 | 5 | #define COMOBJ_ledOnOff 0 6 | #define COMOBJ_trigger 1 7 | #define PARAM_blinkDelay 0 8 | 9 | KnxComObject KnxDevice::_comObjectsList[] = { 10 | /* Index 0 - ledOnOff */ KnxComObject(KNX_DPT_1_001, 0x2a), 11 | /* Index 1 - trigger */ KnxComObject(KNX_DPT_1_001, 0x34) 12 | }; 13 | const byte KnxDevice::_numberOfComObjects = sizeof (_comObjectsList) / sizeof (KnxComObject); // do not change this code 14 | 15 | byte KonnektingDevice::_paramSizeList[] = { 16 | /* Index 0 - blinkDelay */ PARAM_UINT16 17 | }; 18 | const int KonnektingDevice::_numberOfParams = sizeof (_paramSizeList); // do not change this code -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "includePath": [ 6 | "/home/alexander/.arduino15/packages/arduino/tools/**", 7 | "/home/alexander/.arduino15/packages/arduino/hardware/samd/1.8.8/**", 8 | "/home/alexander/.arduino15/packages/arduino/hardware/samd/1.8.9/**" 9 | ], 10 | "forcedInclude": [ 11 | "/home/alexander/.arduino15/packages/arduino/hardware/samd/1.8.8/cores/arduino/Arduino.h", 12 | "/home/alexander/.arduino15/packages/arduino/hardware/samd/1.8.9/cores/arduino/Arduino.h" 13 | ], 14 | "intelliSenseMode": "gcc-x64", 15 | "compilerPath": "/usr/bin/clang", 16 | "cStandard": "c11", 17 | "cppStandard": "c++17" 18 | } 19 | ], 20 | "version": 4 21 | } -------------------------------------------------------------------------------- /examples/DemoSketch_without_pins/EEPROM_24AA256.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // 24AA256 I2C EEPROM 4 | byte readMemory(int index) { 5 | byte data = 0xFF; 6 | if(index >= 0 && index < 32768){ 7 | Wire.beginTransmission(0x50); 8 | Wire.write((int) (index >> 8)); 9 | Wire.write((int) (index & 0xFF)); 10 | Wire.endTransmission(); 11 | Wire.requestFrom(0x50, 1); 12 | if (Wire.available()) { 13 | data = Wire.read(); 14 | } 15 | } 16 | return data; 17 | } 18 | 19 | void writeMemory(int index, byte val) { 20 | if(index >= 0 && index < 32768 && val >= 0 && val < 256){ 21 | Wire.beginTransmission(0x50); 22 | Wire.write((int) (index >> 8)); 23 | Wire.write((int) (index & 0xFF)); 24 | Wire.write(val); 25 | Wire.endTransmission(); 26 | delay(5); 27 | } 28 | } 29 | 30 | void updateMemory(int index, byte val) { 31 | if (readMemory(index) != val) { 32 | writeMemory(index, val); 33 | } 34 | } 35 | 36 | void commitMemory() { 37 | // EEPROM needs no commit, so this function is intentionally left blank 38 | } -------------------------------------------------------------------------------- /examples/DemoSketch/EEPROM_24AA256.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // 24AA256 I2C EEPROM 4 | byte readMemory(int index) { 5 | byte data = 0xFF; 6 | if(index >= 0 && index < 32768){ 7 | Wire.beginTransmission(0x50); 8 | Wire.write((int) (index >> 8)); 9 | Wire.write((int) (index & 0xFF)); 10 | Wire.endTransmission(); 11 | Wire.requestFrom(0x50, 1); 12 | if (Wire.available()) { 13 | data = Wire.read(); 14 | } 15 | } 16 | return data; 17 | } 18 | 19 | void writeMemory(int index, byte val) { 20 | if(index >= 0 && index < 32768 && val >= 0 && val < 256){ 21 | Wire.beginTransmission(0x50); 22 | Wire.write((int) (index >> 8)); 23 | Wire.write((int) (index & 0xFF)); 24 | Wire.write(val); 25 | Wire.endTransmission(); 26 | delay(5); //is it needed?! 27 | } 28 | } 29 | 30 | void updateMemory(int index, byte val) { 31 | if (readMemory(index) != val) { 32 | writeMemory(index, val); 33 | } 34 | } 35 | 36 | void commitMemory() { 37 | // EEPROM needs no commit, so this function is intentionally left blank 38 | } 39 | 40 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: debian:testing 2 | 3 | before_script: 4 | - echo "doing before script ..." 5 | - echo "doing before script ... *DONE*" 6 | 7 | # cache the Arduino CLI setup and config from .pre 8 | cache: 9 | paths: 10 | - Arduino/** 11 | - .arduino15/** 12 | - arduino-cli/** 13 | 14 | install Arduino CLI: 15 | stage: .pre 16 | script: 17 | - ./setup-build-env.sh . 18 | 19 | build DemoSketch: 20 | stage: build 21 | script: 22 | - ./build.sh examples/DemoSketch/DemoSketch.ino arduino:avr:uno 23 | - ./build.sh examples/DemoSketch/DemoSketch.ino arduino:avr:leonardo 24 | - ./build.sh examples/DemoSketch/DemoSketch.ino arduino:samd:mzero_bl 25 | 26 | 27 | build Communication_test: 28 | stage: build 29 | script: 30 | - ./build.sh examples/Communication_test/Communication_test.ino arduino:avr:uno 31 | - ./build.sh examples/Communication_test/Communication_test.ino arduino:avr:leonardo 32 | - ./build.sh examples/Communication_test/Communication_test.ino arduino:samd:mzero_bl 33 | 34 | build DemoSketch_without_pins: 35 | stage: build 36 | script: 37 | - ./build.sh examples/DemoSketch_without_pins/DemoSketch_without_pins.ino arduino:avr:uno 38 | - ./build.sh examples/DemoSketch_without_pins/DemoSketch_without_pins.ino arduino:avr:leonardo 39 | - ./build.sh examples/DemoSketch_without_pins/DemoSketch_without_pins.ino arduino:samd:mzero_bl 40 | 41 | -------------------------------------------------------------------------------- /examples/DemoSketch/DemoSketch.kdevice.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | KONNEKTING 7 | DemoSketch 8 | 9 | 10 | 11 | Blink Delay [500..65535ms] 12 | 13 | 14 | 15 | 16 | 17 | 18 | LED 19 | LED on/off 20 | 1.001 21 | 42 22 | 23 | 24 | Trigger 25 | Trigger with delay 26 | 1.001 27 | 52 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /examples/DemoSketch_without_pins/DemoSketch.kdevice.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | KONNEKTING 7 | DemoSketch 8 | 9 | 10 | 11 | Blink Delay [500..65535ms] 12 | 13 | 14 | 15 | 16 | 17 | 18 | LED 19 | LED on/off 20 | 1.001 21 | 42 22 | 23 | 24 | Trigger 25 | Trigger with delay 26 | 1.001 27 | 52 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/KnxDptConstants.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file KnxDptConstants.h 3 | * 4 | * @section author Author 5 | * 6 | * Written by Alexander Christian. 7 | * 8 | * @section license License 9 | * 10 | * Copyright (C) 2016 Alexander Christian . All rights 11 | * reserved. This file is part of KONNEKTING Device Library. 12 | * 13 | * The KONNEKTING Device Library is free software: you can redistribute 14 | * it and/or modify it under the terms of the GNU General Public License as 15 | * published by the Free Software Foundation, either version 3 of the License, 16 | * or (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program. If not, see . 25 | * 26 | */ 27 | 28 | #define DPT1_001_off 0 29 | #define DPT1_001_on 1 30 | 31 | #define DPT1_002_false 0 32 | #define DPT1_002_true 1 33 | 34 | /** Lock */ 35 | #define DPT1_003_disable 0 36 | 37 | /** Unlock */ 38 | #define DPT1_003_enable 1 39 | 40 | #define DPT1_004_no_ramp 0 41 | #define DPT1_004_ramp 1 42 | 43 | #define DPT1_005_no_alarm 0 44 | #define DPT1_005_alarm 1 45 | 46 | #define DPT1_006_low 0 47 | #define DPT1_006_high 1 48 | 49 | #define DPT1_007_decrease 0 50 | #define DPT1_007_increase 1 51 | 52 | #define DPT1_008_up 0 53 | #define DPT1_008_down 1 54 | 55 | #define DPT1_009_open 0 56 | #define DPT1_009_close 1 57 | 58 | #define DPT1_010_stop 0 59 | #define DPT1_010_start 1 60 | 61 | // State 62 | #define DPT1_011_inactive 0 63 | #define DPT1_011_active 1 64 | -------------------------------------------------------------------------------- /src/.clang-format: -------------------------------------------------------------------------------- 1 | # see https://clang.llvm.org/docs/ClangFormatStyleOptions.html 2 | BasedOnStyle: Google 3 | IndentWidth: 4 4 | TabWidth: 4 5 | ColumnLimit: 0 6 | 7 | # just for reference 8 | # Language: Cpp 9 | # AccessModifierOffset: -4 10 | # AlignEscapedNewlinesLeft: true 11 | # AlignTrailingComments: true 12 | # AllowAllParametersOfDeclarationOnNextLine: true 13 | # AllowShortBlocksOnASingleLine: false 14 | # AllowShortFunctionsOnASingleLine: None 15 | # AllowShortIfStatementsOnASingleLine: false 16 | # AllowShortLoopsOnASingleLine: false 17 | # AlwaysBreakBeforeMultilineStrings: true 18 | # AlwaysBreakTemplateDeclarations: true 19 | # BinPackParameters: false 20 | # BreakBeforeBinaryOperators: false 21 | # BreakBeforeBraces: Allman 22 | # BreakBeforeTernaryOperators: true 23 | # BreakConstructorInitializersBeforeComma: false 24 | # ColumnLimit: 0 25 | # CommentPragmas: '' 26 | # ConstructorInitializerAllOnOneLineOrOnePerLine: true 27 | # ConstructorInitializerIndentWidth: 4 28 | # ContinuationIndentWidth: 4 29 | # DerivePointerAlignment: false 30 | # DisableFormat: false 31 | # ExperimentalAutoDetectBinPacking: false 32 | # IndentCaseLabels: false 33 | # IndentWidth: 4 34 | # IndentWrappedFunctionNames: false 35 | # IndentFunctionDeclarationAfterType: false 36 | # MaxEmptyLinesToKeep: 1 37 | # KeepEmptyLinesAtTheStartOfBlocks: false 38 | # NamespaceIndentation: None 39 | # PenaltyBreakBeforeFirstCallParameter: 1 40 | # PenaltyBreakComment: 300 41 | # PenaltyBreakString: 1000 42 | # PenaltyBreakFirstLessLess: 120 43 | # PenaltyExcessCharacter: 1 44 | # PenaltyReturnTypeOnItsOwnLine: 1000 45 | # PointerAlignment: Left 46 | # SpaceBeforeAssignmentOperators: true 47 | # SpaceBeforeParens: ControlStatements 48 | # SpaceInEmptyParentheses: false 49 | # SpacesBeforeTrailingComments: 1 50 | # SpacesInAngles: false 51 | # SpacesInCStyleCastParentheses: false 52 | # SpacesInContainerLiterals: true 53 | # SpacesInParentheses: false 54 | # Cpp11BracedListStyle: true 55 | # Standard: Cpp11 56 | # TabWidth: 4 57 | # UseTab: Never -------------------------------------------------------------------------------- /src/RingBuff.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KONNEKTING Device Library. 3 | * 4 | * The KONNEKTING Device Library is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef RINGBUFF_H 19 | #define RINGBUFF_H 20 | 21 | #include "Arduino.h" 22 | #include "DebugUtil.h" 23 | 24 | template 25 | class RingBuff { 26 | byte _head; 27 | byte _tail; 28 | T _buffer[size]; // item buffer 29 | byte _size; 30 | byte _itemCount; 31 | 32 | public: 33 | 34 | /** 35 | * Constructor 36 | */ 37 | RingBuff() { 38 | _head = 0; 39 | _tail = 0; 40 | _itemCount = 0; 41 | _size = size; 42 | }; 43 | 44 | 45 | /** 46 | * Append data to tail 47 | * @param appendedData 48 | */ 49 | void append(const T& data) { 50 | if (_itemCount == _size) { // buffer full, overwriting oldest data 51 | incHead(); 52 | } else { 53 | _itemCount++; 54 | } 55 | _buffer[_tail] = data; 56 | incTail(); 57 | } 58 | 59 | /** 60 | * Pop data from head 61 | * @param data the popped data 62 | * @return false, if no items available 63 | */ 64 | boolean pop(T& data) { 65 | if (_itemCount==0) return false; 66 | data = _buffer[_head]; 67 | incHead(); 68 | _itemCount--; 69 | return true; 70 | } 71 | 72 | /** 73 | * Returns number of items in buffer 74 | * @return item count 75 | */ 76 | byte getItemCount(void) const { 77 | return _itemCount; 78 | } 79 | 80 | private: 81 | 82 | void incHead(void) { 83 | _head = (_head + 1) % _size; 84 | } 85 | 86 | void incTail(void) { 87 | _tail = (_tail + 1) % _size; 88 | } 89 | }; 90 | 91 | #endif // RINGBUFF_H 92 | -------------------------------------------------------------------------------- /src/DebugUtil.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KONNEKTING Device Library. 3 | * 4 | * The KONNEKTING Device Library is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef DEBUGUTIL_H 19 | #define DEBUGUTIL_H 20 | 21 | 22 | #include 23 | #ifdef ARDUINO_ARCH_SAMD 24 | #include "stdarg.h" 25 | #endif 26 | 27 | //#define DEBUG // --> This can be forced via arduino-cli build process: --build-property compiler.cpp.extra_flags="-DDEBUG" 28 | 29 | #ifdef DEBUG 30 | #define DEBUG_RAM() Debug.print(F("DEBUG! free ram: %d bytes \n"), Debug.freeRam()); 31 | #define DEBUG_PRINT(...) Debug.print(__VA_ARGS__); 32 | #define DEBUG_PRINTLN(...) Debug.println(__VA_ARGS__); 33 | #else 34 | #define DEBUG_RAM() 35 | #define DEBUG_PRINT(...) 36 | #define DEBUG_PRINTLN(...) 37 | #endif 38 | 39 | #define BYTETOBINARYPATTERN "%d%d%d%d%d%d%d%d" 40 | #define BYTETOBINARY(byte) \ 41 | ((byte & 0x80) ? 1 : 0), \ 42 | ((byte & 0x40) ? 1 : 0), \ 43 | ((byte & 0x20) ? 1 : 0), \ 44 | ((byte & 0x10) ? 1 : 0), \ 45 | ((byte & 0x08) ? 1 : 0), \ 46 | ((byte & 0x04) ? 1 : 0), \ 47 | ((byte & 0x02) ? 1 : 0), \ 48 | ((byte & 0x01) ? 1 : 0) 49 | 50 | 51 | class DebugUtil { 52 | 53 | // Constructor, Destructor 54 | DebugUtil(); // private constructor (singleton design pattern) 55 | 56 | ~DebugUtil() { 57 | } // private destructor (singleton design pattern) 58 | DebugUtil(DebugUtil&); // private copy constructor (singleton design pattern) 59 | 60 | private: 61 | Print* _printstream; 62 | 63 | public: 64 | static DebugUtil Debug; 65 | 66 | void setPrintStream(Stream* printstream); 67 | 68 | int freeRam(); 69 | 70 | void print(const char *format, ...); 71 | void print(const __FlashStringHelper *format, ...); 72 | void println(const char *format, ...); 73 | void println(const __FlashStringHelper *format, ...); 74 | 75 | 76 | }; 77 | 78 | // Reference to the KnxDevice unique instance 79 | extern DebugUtil& Debug; 80 | 81 | #endif // DEBUGUTIL_H 82 | -------------------------------------------------------------------------------- /src/System.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KONNEKTING Device Library. 3 | * 4 | * The KONNEKTING Device Library is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | //#define LOG_SYSTEM 1 18 | 19 | // per known device, set the device's best matching system type 20 | #if defined(ESP8266) || defined(ESP32) 21 | 22 | #if defined(LOG_SYSTEM) 23 | #warning Using KONNEKTING for ESP8266/ESP32 24 | #endif 25 | #define KONNEKTING_SYSTEM_TYPE_DEFAULT 26 | 27 | #elif defined ARDUINO_ARCH_STM32 28 | 29 | #if defined(LOG_SYSTEM) 30 | #warning Using KONNEKTING for STM32 31 | #endif 32 | #define KONNEKTING_SYSTEM_TYPE_DEFAULT 33 | 34 | #elif defined ARDUINO_ARCH_SAMD 35 | 36 | #if defined(LOG_SYSTEM) 37 | #warning Using KONNEKTING for SAMD 38 | #endif 39 | #define KONNEKTING_SYSTEM_TYPE_DEFAULT 40 | 41 | #elif defined __AVR_ATmega32U4__ 42 | 43 | #warning Using KONNEKTING for ATmega32U4 44 | #define KONNEKTING_SYSTEM_TYPE_SIMPLE 45 | #else 46 | 47 | #warning No system, specified, using SIMPLE for now... 48 | #define KONNEKTING_SYSTEM_TYPE_SIMPLE 49 | 50 | #endif 51 | 52 | // per system type, set required stuff 53 | #if defined KONNEKTING_SYSTEM_TYPE_SIMPLE 54 | 55 | #if defined(LOG_SYSTEM) 56 | #warning Using KONNEKTING System Type Simple 57 | #endif 58 | #define KONNEKTING_SYSTEM_TYPE 0x00 59 | #define KONNEKTING_NUMBER_OF_ADDRESSES 128 60 | #define KONNEKTING_NUMBER_OF_ASSOCIATIONS 128 61 | #define KONNEKTING_NUMBER_OF_COMOBJECTS 128 62 | 63 | #define KONNEKTING_NUMBER_OF_PARAMETERS 128 64 | 65 | // start at end of system table 66 | #define KONNEKTING_MEMORYADDRESS_ADDRESSTABLE 64 67 | // start at end of GA-Table 68 | #define KONNEKTING_MEMORYADDRESS_ASSOCIATIONTABLE KONNEKTING_MEMORYADDRESS_ADDRESSTABLE + 1 + (KONNEKTING_NUMBER_OF_ASSOCIATIONS*2) 69 | // start at end of Assoc-Table 70 | #define KONNEKTING_MEMORYADDRESS_COMMOBJECTTABLE KONNEKTING_MEMORYADDRESS_ASSOCIATIONTABLE + 1 + (KONNEKTING_NUMBER_OF_COMOBJECTS*2) 71 | // start at end of CommObj-Table 72 | #define KONNEKTING_MEMORYADDRESS_PARAMETERTABLE KONNEKTING_MEMORYADDRESS_COMMOBJECTTABLE + 1 + KONNEKTING_NUMBER_OF_PARAMETERS 73 | 74 | #elif defined KONNEKTING_SYSTEM_TYPE_DEFAULT 75 | 76 | #if defined(LOG_SYSTEM) 77 | #warning Using KONNEKTING System Type Default 78 | #endif 79 | #define KONNEKTING_SYSTEM_TYPE 0x01 80 | #define KONNEKTING_NUMBER_OF_ADDRESSES 255 81 | #define KONNEKTING_NUMBER_OF_ASSOCIATIONS 255 82 | #define KONNEKTING_NUMBER_OF_COMOBJECTS 255 // one is for prog com obj 83 | 84 | #define KONNEKTING_NUMBER_OF_PARAMETERS 256 85 | 86 | // start at end of system table 87 | #define KONNEKTING_MEMORYADDRESS_ADDRESSTABLE 64 88 | // start at end of GA-Table 89 | #define KONNEKTING_MEMORYADDRESS_ASSOCIATIONTABLE KONNEKTING_MEMORYADDRESS_ADDRESSTABLE + 1 + (KONNEKTING_NUMBER_OF_ASSOCIATIONS*2) 90 | // start at end of Assoc-Table 91 | #define KONNEKTING_MEMORYADDRESS_COMMOBJECTTABLE KONNEKTING_MEMORYADDRESS_ASSOCIATIONTABLE + 1 + (KONNEKTING_NUMBER_OF_COMOBJECTS*2) 92 | // start at end of CommObj-Table 93 | #define KONNEKTING_MEMORYADDRESS_PARAMETERTABLE KONNEKTING_MEMORYADDRESS_COMMOBJECTTABLE + 1 + KONNEKTING_NUMBER_OF_PARAMETERS 94 | 95 | #else 96 | 97 | #error No KONNEKTING System Type set. Cannot continue. 98 | 99 | #endif -------------------------------------------------------------------------------- /src/DebugUtil.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file DebugUtil.cpp 3 | * 4 | * @section author Author 5 | * 6 | * Written by Alexander Christian. 7 | * 8 | * @section license License 9 | * 10 | * Copyright (C) 2016 Alexander Christian . All rights 11 | * reserved. This file is part of KONNEKTING Device Library. 12 | * 13 | * The KONNEKTING Device Library is free software: you can redistribute 14 | * it and/or modify it under the terms of the GNU General Public License as 15 | * published by the Free Software Foundation, either version 3 of the License, 16 | * or (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program. If not, see . 25 | * 26 | */ 27 | 28 | #include "DebugUtil.h" 29 | #include "wiring_private.h" 30 | 31 | #if defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_STM32) 32 | extern "C" char* sbrk(int incr); 33 | extern char *__brkval; 34 | #endif 35 | 36 | // DebugUtil unique instance creation 37 | DebugUtil DebugUtil::Debug; 38 | DebugUtil& Debug = DebugUtil::Debug; 39 | 40 | /* 41 | * Format Help: 42 | * http://www.cplusplus.com/reference/cstdio/printf/ 43 | * 44 | * %i = signed decimal integer 45 | * %u = unsigned decimal integer 46 | * %x = hex 47 | * %X = upper case hex 48 | * %s = string 49 | * %c = character 50 | * 0x%02x = hex representation like 0xff 51 | * %% = % symbol 52 | */ 53 | DebugUtil::DebugUtil() { 54 | } 55 | 56 | void DebugUtil::setPrintStream(Stream* printstream) { 57 | _printstream = printstream; 58 | print(F("DEBUG! free ram: %d bytes \n"), freeRam()); 59 | } 60 | 61 | int DebugUtil::freeRam() { 62 | #if defined(ESP8266) || defined(ESP32) 63 | return ESP.getFreeHeap(); 64 | #elif defined(ARDUINO_ARCH_AVR) 65 | extern int __heap_start, *__brkval; 66 | int v; 67 | return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 68 | #elif defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_STM32) 69 | char top; 70 | return &top - reinterpret_cast(sbrk(0)); 71 | #else 72 | return -1; 73 | #endif 74 | } 75 | 76 | void DebugUtil::print(const char *format, ...) { 77 | if (_printstream) { 78 | char buf[128]; // limit to 128chars 79 | va_list args; 80 | va_start(args, format); 81 | vsnprintf(buf, 128, format, args); 82 | va_end(args); 83 | _printstream->print(buf); 84 | } 85 | 86 | } 87 | 88 | void DebugUtil::print(const __FlashStringHelper *format, ...) { 89 | if (_printstream) { 90 | char buf[128]; // limit to 128chars 91 | va_list args; 92 | va_start(args, format); 93 | 94 | #if defined(__AVR__) || defined(ESP8266) || defined(ARDUINO_ARCH_STM32) 95 | vsnprintf_P(buf, sizeof (buf), (const char *) format, args); // progmem for AVR and ESP8266 96 | #else 97 | vsnprintf(buf, sizeof (buf), (const char *) format, args); // for rest of the world 98 | #endif 99 | va_end(args); 100 | //Serial.print(buf);) 101 | _printstream->print(buf); 102 | } 103 | } 104 | 105 | void DebugUtil::println(const char *format, ...) { 106 | if (_printstream) { 107 | 108 | char buf[128]; // limit to 128chars 109 | va_list args; 110 | va_start(args, format); 111 | vsnprintf(buf, 128, format, args); 112 | va_end(args); 113 | //Serial.println(buf);) 114 | _printstream->println(buf); 115 | } 116 | } 117 | 118 | void DebugUtil::println(const __FlashStringHelper *format, ...) { 119 | if (_printstream) { 120 | 121 | char buf[128]; // limit to 128chars 122 | va_list args; 123 | va_start(args, format); 124 | 125 | #if defined(__AVR__) || defined(ESP8266) || defined(ARDUINO_ARCH_STM32) 126 | vsnprintf_P(buf, sizeof (buf), (const char *) format, args); // progmem for AVR and ESP8266 127 | #else 128 | vsnprintf(buf, sizeof (buf), (const char *) format, args); // for rest of the world 129 | #endif 130 | 131 | va_end(args); 132 | //Serial.println(buf);) 133 | _printstream->println(buf); 134 | } 135 | } 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /src/KnxComObject.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file KnxComObject.cpp 3 | * 4 | * @section author Author 5 | * 6 | * Written by Alexander Christian. 7 | * 8 | * @section license License 9 | * 10 | * Copyright (C) 2016 Alexander Christian . All rights 11 | * reserved. This file is part of KONNEKTING Device Library. 12 | * 13 | * The KONNEKTING Device Library is free software: you can redistribute 14 | * it and/or modify it under the terms of the GNU General Public License as 15 | * published by the Free Software Foundation, either version 3 of the License, 16 | * or (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program. If not, see . 25 | * 26 | */ 27 | 28 | /** 29 | * Handling of the KNX Communication Objects 30 | * @author Alexander Christian 31 | * @depends KnxTelegram 32 | */ 33 | 34 | #include 35 | #include "KnxComObject.h" 36 | 37 | /** 38 | * Calculates telegram data length based on DPT 39 | * @param dptId 40 | * @return length in bytes 41 | */ 42 | byte calcLength(KnxDpt dptId) { 43 | return (pgm_read_byte(&KnxDptFormatToLength[ pgm_read_byte(&KnxDptToFormat[dptId])]) / 8) + 1; 44 | } 45 | 46 | /** 47 | * Contructor 48 | * @param dptId 49 | * @param indicator 50 | */ 51 | KnxComObject::KnxComObject(KnxDpt dptId, byte indicator) 52 | : _dptId(dptId), _indicator(indicator), _dataLength(calcLength(dptId)) { 53 | 54 | if (_indicator & KNX_COM_OBJ_I_INDICATOR) { 55 | // Object with "InitRead" indicator 56 | _validated = false; 57 | } else { 58 | // any other typed object 59 | _validated = true; 60 | } 61 | 62 | if (_dataLength <= 2) { 63 | _longValue = NULL; 64 | } else { 65 | // long value case 66 | _longValue = (byte *) malloc(_dataLength - 1); 67 | for (byte i = 0; i < _dataLength - 1; i++) { 68 | _longValue[i] = 0; 69 | } 70 | } 71 | 72 | } 73 | 74 | /** 75 | * Destructor 76 | */ 77 | KnxComObject::~KnxComObject() { 78 | if (_dataLength > 2) { 79 | free(_longValue); 80 | } 81 | } 82 | 83 | /** 84 | * TODO document me 85 | * @return 86 | */ 87 | bool KnxComObject::isActive() { 88 | return _active; 89 | } 90 | 91 | /** 92 | * Get the com obj value 93 | * Ensure 'value' is sizeOf data-length 94 | * @param value 95 | */ 96 | void KnxComObject::getValue(byte value[]) const { 97 | if (_dataLength <= 2) { 98 | value[0] = _value; // short value case, ReadValue(void) fct should rather be used 99 | } else { 100 | for (byte i = 0; i < _dataLength - 1; i++) { 101 | value[i] = _longValue[i]; // long value case 102 | } 103 | } 104 | } 105 | 106 | /** 107 | * Update comobj value by raw byte[] 108 | * @param other 109 | */ 110 | void KnxComObject::updateValue(const byte other[]) { 111 | if (_dataLength <= 2) { 112 | _value = other[0]; // short value case, UpdateValue(byte) fct should rather be used 113 | } else { 114 | for (byte i = 0; i < _dataLength - 1; i++) { 115 | _longValue[i] = other[i]; // long value case 116 | } 117 | } 118 | _validated = true; 119 | } 120 | 121 | /** 122 | * Update comobj value with payload from telegram 123 | * @param other 124 | * @return KNX_COM_OBJECT_ERROR or KNX_COM_OBJECT_OK 125 | */ 126 | byte KnxComObject::updateValue(const KnxTelegram& other) { 127 | 128 | if (other.getPayloadLength() != getLength()) { 129 | return KNX_COM_OBJECT_ERROR; // Error : telegram payload length differs from com obj one 130 | } 131 | 132 | switch (_dataLength) { 133 | case 1: 134 | _value = other.getFirstPayloadByte(); 135 | break; 136 | case 2: 137 | other.getLongPayload(&_value, 1); 138 | break; 139 | default: 140 | other.getLongPayload(_longValue, _dataLength - 1); 141 | } 142 | 143 | _validated = true; // com object set to valid 144 | return KNX_COM_OBJECT_OK; 145 | } 146 | 147 | /** 148 | * Copy comobj attributes into a telegram 149 | * @param dest 150 | */ 151 | void KnxComObject::copyAttributes(KnxTelegram& dest) const { 152 | dest.changePriority(getPriority()); 153 | dest.setTargetAddress(getAddr()); 154 | dest.setPayloadLength(_dataLength); 155 | } 156 | 157 | /** 158 | * Copy the comobj value into a telegram 159 | * @param dest 160 | */ 161 | void KnxComObject::copyValue(KnxTelegram& dest) const { 162 | switch (_dataLength) { 163 | case 1: 164 | dest.setFirstPayloadByte(_value); 165 | break; 166 | case 2: 167 | dest.setLongPayload(&_value, 1); 168 | break; 169 | default: 170 | dest.setLongPayload(_longValue, _dataLength - 1); 171 | } 172 | } -------------------------------------------------------------------------------- /setup-build-env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # enable following two line to make it run line by line --> for debugging only 3 | #set -x 4 | #trap read debug 5 | 6 | # Check if we're root and re-execute if we're not. 7 | rootcheck () { 8 | if [ $(id -u) != "0" ] 9 | then 10 | echo "!! We require root permissions, restarting with SUDO ..." 11 | echo "" 12 | echo "" 13 | sudo "$0" "$@" # Modified as suggested below. 14 | exit $? 15 | else 16 | echo "-> Ok, we have root permissions." 17 | fi 18 | } 19 | 20 | printCheckmark() { 21 | echo -e "\xe2\x9c\x93" 22 | echo "" 23 | } 24 | 25 | updateLibrary () { 26 | echo -n "-> Copy $PROJECT_DIR to sketchbook libraries "; 27 | mkdir -p $ARDUINO_LIB_DIR/MYLIBRARY 28 | rsync -avzq --exclude 'Arduino' --exclude 'arduino-cli-build' --exclude 'bin' --exclude '.arduino15' $PROJECT_DIR $ARDUINO_LIB_DIR/MYLIBRARY 29 | printCheckmark; 30 | } 31 | 32 | echo "========================================" 33 | echo "Setup Arduino Build Environment " 34 | echo "========================================" 35 | echo 36 | #rootcheck 37 | 38 | # make this script expand alias, see alias usage below... 39 | shopt -s expand_aliases 40 | 41 | WORKING_DIR="${CI_PROJECT_DIR:-./arduino-cli-build}" 42 | 43 | echo "-> WORKING_DIR : $WORKING_DIR" 44 | 45 | PROJECT_DIR=$1 46 | if [ -z $1 ]; then 47 | PROJECT_DIR="."; 48 | fi 49 | 50 | echo "-> PROJECT_DIR : $PROJECT_DIR" 51 | 52 | ARDUINO_DIR=$WORKING_DIR/Arduino 53 | ARDUINO_LIB_DIR=$ARDUINO_DIR/libraries 54 | ARDUINO_15_DIR=$WORKING_DIR/.arduino15 55 | ARDUINO_CLI_DIR=$WORKING_DIR/arduino-cli 56 | PATH="$ARDUINO_CLI_DIR:$PATH" 57 | 58 | if [ -e $ARDUINO_CLI_DIR ]; then 59 | echo "existing setup in $ARDUINO_CLI_DIR detected. Just updateing library" 60 | updateLibrary; 61 | exit; 62 | fi 63 | 64 | #echo -n "-> Cleanup old stuff " 65 | #rm -Rf $WORKING_DIR 66 | #printCheckmark 67 | 68 | 69 | 70 | # setup the build environment: 71 | # * install required command line tools like rsync and curl 72 | # * install Arduino CLI 73 | # * install boards 74 | # * install required Arduino libs (may be something more than we really need, but this does not hurt) 75 | 76 | # install CURL command to be able to install Arduino CLI 77 | if [ -z $(which rsync) ] && [ -z $(which curl) ]; then 78 | echo "-> APT update and install curl+rsync " 79 | if [ $(id -u) != "0" ]; then 80 | # not root, need sudo 81 | sudo apt-get -q -q update 82 | sudo apt-get -y -q -q install curl rsync 83 | else 84 | apt-get -q -q update 85 | apt-get -y -q -q install curl rsync 86 | fi 87 | else 88 | echo -n "-> curl+rsync detected " 89 | fi 90 | printCheckmark 91 | 92 | # install Arduino CLI 93 | echo "-> Install Arduino CLI ..." 94 | mkdir -p $ARDUINO_CLI_DIR 95 | curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=$ARDUINO_CLI_DIR sh 96 | echo -n "-> Install Arduino CLI "; printCheckmark; 97 | 98 | # make local arduino folders and preferences, preferences will be used by ALIAS command, see 'before_script' above 99 | echo -n "-> Configure Arduino CLI " 100 | mkdir -p $ARDUINO_DIR 101 | mkdir -p $ARDUINO_15_DIR 102 | # write preference file 103 | cat >$ARDUINO_CLI_DIR/arduino-cli.yaml < Arduino CLI config dump: " 126 | arduinocli config dump 127 | 128 | # update core board index 129 | echo "-> Update Core index" 130 | arduinocli core update-index 131 | 132 | # install UNO/Leonardo/... 133 | echo "-> Install Arduino AVR core" 134 | arduinocli core install arduino:avr 135 | 136 | # install SAMD core 137 | echo "-> Install SAMD core" 138 | arduinocli core install arduino:samd 139 | 140 | # install ESP8266 core 141 | echo "-> Install Arduino ESP8266 core" 142 | arduinocli core update-index --additional-urls "http://arduino.esp8266.com/stable/package_esp8266com_index.json" 143 | arduinocli core install esp8266:esp8266 --additional-urls "https://arduino.esp8266.com/stable/package_esp8266com_index.json" 144 | 145 | # list installed cores and boards 146 | echo "-> Installed cores: " 147 | arduinocli core list 148 | echo "" 149 | echo -n "-> Installing cores "; printCheckmark; 150 | 151 | echo "-> Installed boards: " 152 | arduinocli board listall 153 | echo "" 154 | echo -n "-> Installing boards "; printCheckmark; 155 | 156 | # install libs 157 | echo "-> Installing libs ..." 158 | arduinocli lib install "OneWire" 159 | arduinocli lib install "DallasTemperature" 160 | arduinocli lib install "SparkFun HTU21D Humidity and Temperature Sensor Breakout" 161 | arduinocli lib install "FlashStorage" 162 | arduinocli lib install "CRC32" 163 | echo -n "-> Installing libs "; printCheckmark; 164 | 165 | # list libs 166 | echo "-> List of installed libs: " 167 | arduinocli lib list 168 | echo "" 169 | 170 | echo -n "-> Setup Arduino Build Environment "; printCheckmark; 171 | -------------------------------------------------------------------------------- /knx_conversionhelper.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 108 | 109 | 110 | 111 | 112 | 113 |

Group Address Calculator

114 | 115 | 116 | 117 | 118 | 123 | 124 | 125 | 126 | 127 | 130 | 131 | 132 | 133 | 134 | 137 | 138 |
GA: 119 | / 120 | / 121 | 122 |
HEX: 128 | 129 |
DEC: 135 | 136 |
139 | 140 |

Individual Address Calculator

141 | 142 | 143 | 144 | 145 | 150 | 151 | 152 | 153 | 154 | 157 | 158 | 159 | 160 | 161 | 164 | 165 |
IA: 146 | . 147 | . 148 | 149 |
HEX: 155 | 156 |
DEC: 162 | 163 |
166 | 167 |

Parameter Type Converter

168 | 169 | 170 | 171 | 173 | 174 | 175 | 177 | 178 | 179 |
UINTx:   Dec:  Hex: 172 |
String:   Readable:  Hex: 176 |
180 | 181 | 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /examples/DemoSketch/DemoSketch.ino: -------------------------------------------------------------------------------- 1 | #define KONNEKTING_SYSTEM_TYPE_SIMPLE 2 | #include 3 | 4 | // include device related configuration code, created by "KONNEKTING CodeGenerator" 5 | #include "kdevice_DemoSketch.h" 6 | 7 | // ################################################ 8 | // ### BOARD CONFIGURATION 9 | // ################################################ 10 | 11 | #ifdef __AVR_ATmega328P__ 12 | // Uno/Nano/ProMini 13 | #define KNX_SERIAL Serial // D0=RX/D1=TX 14 | #define PROG_LED_PIN 11 // External LED 15 | #define TEST_LED LED_BUILTIN // On board LED on pin D13 16 | #define PROG_BUTTON_PIN 3 // pin with interrupt 17 | // ATmega328P has only one UART, lets use virtual one 18 | #include 19 | SoftwareSerial softserial(11, 10); // D11=RX/D10=TX 20 | #define DEBUGSERIAL softserial 21 | 22 | #elif __AVR_ATmega32U4__ 23 | // Leonardo/Micro/ProMicro 24 | #define KNX_SERIAL Serial1 // D0=RX/D1=TX 25 | #define PROG_LED_PIN 11 // External LED 26 | #define TEST_LED LED_BUILTIN // On board LED on pin D13 27 | #define PROG_BUTTON_PIN 3 // pin with interrupt 28 | #define DEBUGSERIAL Serial // USB port 29 | 30 | #elif ARDUINO_ARCH_SAMD 31 | // Zero/M0 32 | #define KNX_SERIAL Serial1 // D0=RX/D1=TX 33 | #define PROG_LED_PIN 11 // External LED 34 | #define TEST_LED LED_BUILTIN // On board LED on pin D13 35 | #define PROG_BUTTON_PIN 3 // pin with interrupt 36 | #define DEBUGSERIAL SerialUSB // USB port 37 | // Arduino Zero has no "real" internal EEPROM, 38 | // so we can use an external I2C EEPROM. 39 | #include "EEPROM_24AA256.h" // external EEPROM 40 | 41 | #elif ARDUINO_ARCH_STM32 42 | // STM32 NUCLEO Boards 43 | // Option Serial interface: "Enabled with generic Serial" should be enabled 44 | // Create a new Serial on Pins PA10 & PA9 45 | // Arduino-Header: D2(PA10)=RX/D8(PA9)=TX 46 | HardwareSerial Serial1(PA10, PA9); 47 | #define KNX_SERIAL Serial1 48 | #define PROG_LED_PIN 11 // External LED 49 | #define TEST_LED LED_BUILTIN // On board LED on pin D13 50 | #define PROG_BUTTON_PIN USER_BTN // On board button 51 | #define DEBUGSERIAL Serial // USB port 52 | 53 | #elif ESP8266 54 | // ESP8266 55 | #define KNX_SERIAL Serial // swaped Serial on D7(GPIO13)=RX/GPIO15(D8)=TX 56 | #define PROG_LED_PIN 14 // External LED 57 | #define TEST_LED 16 // External LED 58 | #define PROG_BUTTON_PIN 0 // Flash/IO0 button 59 | #define DEBUGSERIAL Serial1 // the 2nd serial port with TX only (GPIO2/D4) 60 | 61 | #else 62 | // All other boards 63 | #error "Sorry, you board is not supported" 64 | #endif 65 | 66 | // ################################################ 67 | // ### DEBUG CONFIGURATION 68 | // ################################################ 69 | //#define KDEBUG // comment this line to disable DEBUG mode 70 | #ifdef KDEBUG 71 | #include 72 | #endif 73 | 74 | // ################################################ 75 | // ### Global variables, sketch related 76 | // ################################################ 77 | unsigned long blinkDelay = 2500; // default value 78 | unsigned long lastmillis = millis(); 79 | int laststate = false; 80 | 81 | // ################################################ 82 | // ### SETUP 83 | // ################################################ 84 | 85 | void setup() 86 | { 87 | 88 | // debug related stuff 89 | #ifdef KDEBUG 90 | 91 | // Start debug serial with 115200 bauds 92 | DEBUGSERIAL.begin(115200); 93 | 94 | #if defined(__AVR_ATmega32U4__) || defined(__SAMD21G18A__) 95 | // wait for serial port to connect. Needed for Leonardo/Micro/ProMicro/Zero only 96 | while (!DEBUGSERIAL) 97 | #endif 98 | 99 | // make debug serial port known to debug class 100 | // Means: KONNEKTING will sue the same serial port for console debugging 101 | Debug.setPrintStream(&DEBUGSERIAL); 102 | #endif 103 | 104 | Debug.print(F("KONNEKTING DemoSketch\n")); 105 | 106 | pinMode(TEST_LED, OUTPUT); 107 | 108 | /* 109 | * Only required when using external eeprom (or similar) storage. 110 | * function pointers should match the methods you have implemented above. 111 | * If no external eeprom required, please remove all three Konnekting.setMemory* lines below 112 | */ 113 | #ifdef __SAMD21G18A__ 114 | Wire.begin(); 115 | Konnekting.setMemoryReadFunc(&readMemory); 116 | Konnekting.setMemoryWriteFunc(&writeMemory); 117 | Konnekting.setMemoryUpdateFunc(&updateMemory); 118 | Konnekting.setMemoryCommitFunc(&commitMemory); 119 | #endif 120 | 121 | // Initialize KNX enabled Arduino Board 122 | Konnekting.init(KNX_SERIAL, 123 | PROG_BUTTON_PIN, 124 | PROG_LED_PIN, 125 | MANUFACTURER_ID, 126 | DEVICE_ID, 127 | REVISION); 128 | 129 | // If device has been parametrized with KONNEKTING Suite, read params from EEPROM 130 | // Otherwise continue with global default values from sketch 131 | if (!Konnekting.isFactorySetting()) 132 | { 133 | blinkDelay = (int)Konnekting.getUINT16Param(PARAM_blinkDelay); //blink every xxxx ms 134 | } 135 | 136 | lastmillis = millis(); 137 | 138 | Debug.println(F("Toggle LED every %d ms."), blinkDelay); 139 | Debug.println(F("Setup is ready. go to loop...")); 140 | } 141 | 142 | // ################################################ 143 | // ### LOOP 144 | // ################################################ 145 | 146 | void loop() 147 | { 148 | 149 | // Do KNX related stuff (like sending/receiving KNX telegrams) 150 | // This is required in every KONNEKTING aplication sketch 151 | Knx.task(); 152 | 153 | unsigned long currentmillis = millis(); 154 | 155 | /* 156 | * only do measurements and other sketch related stuff if not in programming mode 157 | * means: only when konnekting is ready for appliction 158 | */ 159 | if (Konnekting.isReadyForApplication()) 160 | { 161 | 162 | if (currentmillis - lastmillis >= blinkDelay) 163 | { 164 | 165 | Debug.println(F("Actual state: %d"), laststate); 166 | Knx.write(COMOBJ_trigger, laststate); 167 | laststate = !laststate; 168 | lastmillis = currentmillis; 169 | 170 | digitalWrite(TEST_LED, HIGH); 171 | Debug.println(F("DONE")); 172 | } 173 | } 174 | } 175 | 176 | // ################################################ 177 | // ### KNX EVENT CALLBACK 178 | // ################################################ 179 | 180 | void knxEvents(byte index) 181 | { 182 | switch (index) 183 | { 184 | 185 | case COMOBJ_ledOnOff: // object index has been updated 186 | 187 | if (Knx.read(COMOBJ_ledOnOff)) 188 | { 189 | digitalWrite(TEST_LED, HIGH); 190 | Debug.println(F("Toggle LED: on")); 191 | } 192 | else 193 | { 194 | digitalWrite(TEST_LED, LOW); 195 | Debug.println(F("Toggle LED: off")); 196 | } 197 | break; 198 | 199 | default: 200 | break; 201 | } 202 | }; 203 | -------------------------------------------------------------------------------- /examples/Communication_test/Communication_test.ino: -------------------------------------------------------------------------------- 1 | // http://library manager/all#Foo @ 1.2.3 2 | #define KONNEKTING_SYSTEM_TYPE_SIMPLE 3 | #include 4 | //#include 5 | //#include 6 | // ################################################ 7 | // ### KNX DEVICE CONFIGURATION 8 | // ################################################ 9 | word individualAddress = P_ADDR(1, 1, 199); 10 | word groupAddressInput = G_ADDR(7, 7, 7); 11 | word groupAddressOutput = G_ADDR(7, 7, 8); 12 | 13 | // ################################################ 14 | // ### BOARD CONFIGURATION 15 | // ################################################ 16 | 17 | #ifdef __AVR_ATmega328P__ 18 | // Uno/Nano/ProMini 19 | #define KNX_SERIAL Serial // D0=RX/D1=TX 20 | #define TEST_LED LED_BUILTIN // On board LED on pin D13 21 | // ATmega328P has only one UART, lets use virtual one 22 | #include 23 | SoftwareSerial softserial(11, 10); // D11=RX/D10=TX 24 | #define DEBUGSERIAL softserial 25 | 26 | #elif __AVR_ATmega32U4__ 27 | // Leonardo/Micro/ProMicro 28 | #define KNX_SERIAL Serial1 // D0=RX/D1=TX 29 | #define TEST_LED LED_BUILTIN // On board LED on pin D13 30 | #define DEBUGSERIAL Serial // USB port 31 | 32 | #elif ARDUINO_ARCH_SAMD 33 | // Zero/M0 34 | #define KNX_SERIAL Serial1 // D0=RX/D1=TX 35 | #define TEST_LED LED_BUILTIN // On board LED on pin D13 36 | #define DEBUGSERIAL SerialUSB // USB port 37 | 38 | #elif ARDUINO_ARCH_STM32 39 | // STM32 NUCLEO Boards 40 | // Option Serial interface: "Enabled with generic Serial" should be enabled 41 | // Create a new Serial on Pins PA10 & PA9 42 | // Arduino-Header: D2(PA10)=RX/D8(PA9)=TX 43 | HardwareSerial Serial1(PA10,PA9); 44 | #define KNX_SERIAL Serial1 45 | #define TEST_LED LED_BUILTIN // On board LED 46 | #define DEBUGSERIAL Serial // USB port 47 | 48 | #elif ESP8266 49 | // ESP8266 50 | #define KNX_SERIAL Serial // swaped Serial on D7(GPIO13)=RX/GPIO15(D8)=TX 51 | #define TEST_LED 16 // External LED 52 | #define DEBUGSERIAL Serial1 // the 2nd serial port with TX only (GPIO2/D4) 53 | 54 | #else 55 | // All other boards 56 | #error "Sorry, you board is not supported" 57 | #endif 58 | 59 | // ################################################ 60 | // ### DEBUG Configuration 61 | // ################################################ 62 | #define KDEBUG // comment this line to disable DEBUG mode 63 | 64 | #ifdef KDEBUG 65 | #include 66 | #endif 67 | 68 | // Define KONNEKTING Device related IDs 69 | #define MANUFACTURER_ID 57005 70 | #define DEVICE_ID 255 71 | #define REVISION 0 72 | 73 | 74 | // Definition of the Communication Objects attached to the device 75 | KnxComObject KnxDevice::_comObjectsList[] = { 76 | /* Suite-Index 0 : */ KnxComObject(KNX_DPT_1_001, COM_OBJ_LOGIC_IN), 77 | /* Suite-Index 1 : */ KnxComObject(KNX_DPT_1_001, COM_OBJ_SENSOR), 78 | }; 79 | const byte KnxDevice::_numberOfComObjects = sizeof (_comObjectsList) / sizeof (KnxComObject); // do no change this code 80 | 81 | // Definition of parameter size 82 | byte KonnektingDevice::_paramSizeList[] = { 83 | /* Param Index 0 */ PARAM_UINT16 84 | }; 85 | const int KonnektingDevice::_numberOfParams = sizeof (_paramSizeList); // do no change this code 86 | 87 | //we do not need a ProgLED, but this function muss be defined 88 | void progLed (bool state){ 89 | //nothing to do here 90 | Debug.println(F("Toggle ProgLED, actual state: %d"),state); 91 | } 92 | 93 | unsigned long sendDelay = 2000; 94 | unsigned long lastmillis = millis(); 95 | bool lastState = false; 96 | bool lastLedState = false; 97 | byte virtualEEPROM[16]; 98 | 99 | 100 | // ################################################ 101 | // ### KNX EVENT CALLBACK 102 | // ################################################ 103 | 104 | void knxEvents(byte index) { 105 | switch (index) { 106 | 107 | case 0: // object index has been updated 108 | Debug.println(F("ComObject 0 received: %d, let's trigger LED state"), Knx.read(0)); 109 | lastLedState = !lastLedState; 110 | digitalWrite(TEST_LED,lastLedState); 111 | break; 112 | 113 | default: 114 | break; 115 | } 116 | } 117 | 118 | byte readMemory(int index){ 119 | return virtualEEPROM[index]; 120 | } 121 | 122 | void writeMemory(int index, byte val) { 123 | virtualEEPROM[index] = val; 124 | } 125 | 126 | void updateMemory(int index, byte val) { 127 | if (readMemory(index) != val) { 128 | writeMemory(index, val); 129 | } 130 | } 131 | 132 | void commitMemory() { 133 | 134 | } 135 | 136 | void setup() { 137 | memset(virtualEEPROM,0xFF,16); 138 | Konnekting.setMemoryReadFunc(&readMemory); 139 | Konnekting.setMemoryWriteFunc(&writeMemory); 140 | Konnekting.setMemoryUpdateFunc(&updateMemory); 141 | Konnekting.setMemoryCommitFunc(&commitMemory); 142 | 143 | // simulating allready programmed Konnekting device: 144 | // in this case we don't need Konnekting Suite 145 | // write hardcoded PA and GAs 146 | writeMemory(0, 0x7F); //Set "not factory" flag 147 | writeMemory(1, (byte)(individualAddress >> 8)); 148 | writeMemory(2, (byte)(individualAddress)); 149 | writeMemory(10, (byte)(groupAddressInput >> 8)); 150 | writeMemory(11, (byte)(groupAddressInput)); 151 | writeMemory(12, 0x80); //activate InputGA 152 | writeMemory(13, (byte)(groupAddressOutput >> 8)); 153 | writeMemory(14, (byte)(groupAddressOutput)); 154 | writeMemory(15, 0x80); //activate OutputGA 155 | 156 | 157 | // debug related stuff 158 | #ifdef KDEBUG 159 | 160 | // Start debug serial with 115200 bauds 161 | DEBUGSERIAL.begin(115200); 162 | 163 | //waiting 3 seconds, so you have enough time to start serial monitor 164 | delay(3000); 165 | 166 | // make debug serial port known to debug class 167 | // Means: KONNEKTING will use the same serial port for console debugging 168 | Debug.setPrintStream(&DEBUGSERIAL); 169 | #endif 170 | 171 | // Initialize KNX enabled Arduino Board 172 | Konnekting.init(KNX_SERIAL, 173 | &progLed, 174 | MANUFACTURER_ID, 175 | DEVICE_ID, 176 | REVISION); 177 | 178 | pinMode(TEST_LED,OUTPUT); 179 | 180 | Debug.println(F("Toggle LED every %d ms."), sendDelay); 181 | Debug.println(F("Setup is ready. Turning LED on and going to loop...")); 182 | 183 | } 184 | 185 | void loop() { 186 | 187 | // Do KNX related stuff (like sending/receiving KNX telegrams) 188 | // This is required in every KONNEKTING aplication sketch 189 | Knx.task(); 190 | 191 | unsigned long currentmillis = millis(); 192 | 193 | /* 194 | * only do measurements and other sketch related stuff if not in programming mode 195 | * means: only when konnekting is ready for appliction 196 | */ 197 | if (Konnekting.isReadyForApplication()) { 198 | 199 | if (currentmillis - lastmillis >= sendDelay) { 200 | 201 | Debug.println(F("Sending: %d"), lastState); 202 | Knx.write(1, lastState); 203 | lastState = !lastState; 204 | lastmillis = currentmillis; 205 | Debug.println(F("DONE\n")); 206 | 207 | } 208 | 209 | } 210 | 211 | } -------------------------------------------------------------------------------- /src/KnxTelegram.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file KnxTelegram.cpp 3 | * 4 | * @section author Author 5 | * 6 | * Written by Alexander Christian. 7 | * 8 | * @section license License 9 | * 10 | * Copyright (C) 2016 Alexander Christian . All rights 11 | * reserved. This file is part of KONNEKTING Device Library. 12 | * 13 | * The KONNEKTING Device Library is free software: you can redistribute 14 | * it and/or modify it under the terms of the GNU General Public License as 15 | * published by the Free Software Foundation, either version 3 of the License, 16 | * or (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program. If not, see . 25 | * 26 | */ 27 | 28 | #include "KnxTelegram.h" 29 | 30 | KnxTelegram::KnxTelegram() { clearTelegram(); }; // Clear telegram with default values 31 | 32 | 33 | void KnxTelegram::clearTelegram(void) 34 | { 35 | // clear telegram with default values : 36 | // std FF, no repeat, normal prio, empty payload 37 | // multicast, routing counter = 6, payload length = 1 38 | memset(_telegram,0,KNX_TELEGRAM_MAX_SIZE); 39 | _controlField = CONTROL_FIELD_DEFAULT_VALUE ; 40 | _routing= ROUTING_FIELD_DEFAULT_VALUE; 41 | } 42 | 43 | 44 | void KnxTelegram::setLongPayload(const byte origin[], byte nbOfBytes) 45 | { 46 | if (nbOfBytes > KNX_TELEGRAM_PAYLOAD_MAX_SIZE-2) nbOfBytes = KNX_TELEGRAM_PAYLOAD_MAX_SIZE-2; 47 | for(byte i=0; i < nbOfBytes; i++) _payloadChecksum[i] = origin[i]; 48 | } 49 | 50 | 51 | void KnxTelegram::clearLongPayload(void) 52 | { 53 | memset(_payloadChecksum,0,KNX_TELEGRAM_PAYLOAD_MAX_SIZE-1); 54 | } 55 | 56 | 57 | void KnxTelegram::getLongPayload(byte destination[], byte nbOfBytes) const 58 | { 59 | if (nbOfBytes > KNX_TELEGRAM_PAYLOAD_MAX_SIZE-2) nbOfBytes = KNX_TELEGRAM_PAYLOAD_MAX_SIZE-2 ; 60 | memcpy(destination, _payloadChecksum, nbOfBytes); 61 | }; 62 | 63 | 64 | byte KnxTelegram::calculateChecksum(void) const 65 | { 66 | byte indexChecksum, xorSum=0; 67 | indexChecksum = KNX_TELEGRAM_HEADER_SIZE + getPayloadLength() + 1; 68 | for (byte i = 0; i < indexChecksum ; i++) xorSum ^= _telegram[i]; // XOR Sum of all the databytes 69 | return (byte)(~xorSum); // Checksum equals 1's complement of databytes XOR sum 70 | } 71 | 72 | 73 | void KnxTelegram::updateChecksum(void) 74 | { 75 | byte indexChecksum, xorSum=0; 76 | indexChecksum = KNX_TELEGRAM_HEADER_SIZE + getPayloadLength() + 1; 77 | for (byte i = 0; i < indexChecksum ; i++) xorSum ^= _telegram[i]; // XOR Sum of all the databytes 78 | _telegram[indexChecksum] = ~xorSum; // Checksum equals 1's complement of databytes XOR sum 79 | } 80 | 81 | 82 | void KnxTelegram::copy(KnxTelegram& dest) const 83 | { 84 | byte length = getTelegramLength(); 85 | memcpy(dest._telegram, _telegram, length); 86 | } 87 | 88 | 89 | void KnxTelegram::copyHeader(KnxTelegram& dest) const 90 | { 91 | memcpy(dest._telegram, _telegram, KNX_TELEGRAM_HEADER_SIZE); 92 | } 93 | 94 | 95 | e_KnxTelegramValidity KnxTelegram::getValidity(void) const 96 | { 97 | if ((_controlField & CONTROL_FIELD_PATTERN_MASK) != CONTROL_FIELD_VALID_PATTERN) return KNX_TELEGRAM_INVALID_CONTROL_FIELD; 98 | if ((_controlField & CONTROL_FIELD_FRAME_FORMAT_MASK) != CONTROL_FIELD_STANDARD_FRAME_FORMAT) return KNX_TELEGRAM_UNSUPPORTED_FRAME_FORMAT; 99 | if (!getPayloadLength()) return KNX_TELEGRAM_INCORRECT_PAYLOAD_LENGTH ; 100 | if ((_commandH & COMMAND_FIELD_PATTERN_MASK) != COMMAND_FIELD_VALID_PATTERN) return KNX_TELEGRAM_INVALID_COMMAND_FIELD; 101 | if ( getChecksum() != calculateChecksum()) return KNX_TELEGRAM_INCORRECT_CHECKSUM ; 102 | byte cmd=getCommand(); 103 | if ( (cmd!=KNX_COMMAND_VALUE_READ) && (cmd!=KNX_COMMAND_VALUE_RESPONSE) 104 | && (cmd!=KNX_COMMAND_VALUE_WRITE) && (cmd!=KNX_COMMAND_MEMORY_WRITE)) return KNX_TELEGRAM_UNKNOWN_COMMAND; 105 | return KNX_TELEGRAM_VALID; 106 | }; 107 | 108 | 109 | void KnxTelegram::info(String& str) const 110 | { 111 | byte payloadLength = getPayloadLength(); 112 | 113 | str+="SrcAddr=" + String(getSourceAddress(),HEX); 114 | str+="\nTargetAddr=" + String(getTargetAddress(),HEX); 115 | str+="\nPayloadLgth=" + String(payloadLength,DEC); 116 | str+="\nCommand="; 117 | switch(getCommand()) 118 | { 119 | case KNX_COMMAND_VALUE_READ : str+="VAL_READ"; break; 120 | case KNX_COMMAND_VALUE_RESPONSE : str+="VAL_RESP"; break; 121 | case KNX_COMMAND_VALUE_WRITE : str+="VAL_WRITE"; break; 122 | case KNX_COMMAND_MEMORY_WRITE : str+="MEM_WRITE"; break; 123 | default : str+="ERR_VAL!"; break; 124 | } 125 | str+="\nPayload=" + String(getFirstPayloadByte(),HEX)+' '; 126 | for (byte i = 0; i < payloadLength-1; i++) str+=String(_payloadChecksum[i], HEX)+' '; 127 | str+='\n'; 128 | } 129 | 130 | 131 | void KnxTelegram::KnxTelegram::infoRaw(String& str) const 132 | { 133 | for (byte i = 0; i < KNX_TELEGRAM_MAX_SIZE; i++) str+=String(_telegram[i], HEX)+' '; 134 | str+='\n'; 135 | } 136 | 137 | 138 | void KnxTelegram::infoVerbose(String& str) const 139 | { 140 | byte payloadLength = getPayloadLength(); 141 | str+= "Repeat="; str+= isRepeated() ? "YES" : "NO"; 142 | str+="\nPrio="; 143 | switch(getPriority()) 144 | { 145 | case KNX_PRIORITY_SYSTEM_VALUE : str+="SYSTEM"; break; 146 | case KNX_PRIORITY_ALARM_VALUE : str+="ALARM"; break; 147 | case KNX_PRIORITY_HIGH_VALUE : str+="HIGH"; break; 148 | case KNX_PRIORITY_NORMAL_VALUE : str+="NORMAL"; break; 149 | default : str+="ERR_VAL!"; break; 150 | } 151 | str+="\nSrcAddr=" + String(getSourceAddress(),HEX); 152 | str+="\nTargetAddr=" + String(getTargetAddress(),HEX); 153 | str+="\nGroupAddr="; if (isMulticast()) str+= "YES"; else str+="NO"; 154 | str+="\nRout.Counter=" + String(getRoutingCounter(),DEC); 155 | str+="\nPayloadLgth=" + String(payloadLength,DEC); 156 | str+="\nTelegramLength=" + String(getTelegramLength(),DEC); 157 | str+="\nCommand="; 158 | switch(getCommand()) 159 | { 160 | case KNX_COMMAND_VALUE_READ : str+="VAL_READ"; break; 161 | case KNX_COMMAND_VALUE_RESPONSE : str+="VAL_RESP"; break; 162 | case KNX_COMMAND_VALUE_WRITE : str+="VAL_WRITE"; break; 163 | case KNX_COMMAND_MEMORY_WRITE : str+="MEM_WRITE"; break; 164 | default : str+="ERR_VAL!"; break; 165 | } 166 | str+="\nPayload=" + String(getFirstPayloadByte(),HEX)+' '; 167 | for (byte i = 0; i < payloadLength-1; i++) str+=String(_payloadChecksum[i], HEX)+' '; 168 | str+="\nValidity="; 169 | switch(getValidity()) 170 | { 171 | case KNX_TELEGRAM_VALID : str+="VALID"; break; 172 | case KNX_TELEGRAM_INVALID_CONTROL_FIELD : str+="INVALID_CTRL_FIELD"; break; 173 | case KNX_TELEGRAM_UNSUPPORTED_FRAME_FORMAT : str+="UNSUPPORTED_FRAME_FORMAT"; break; 174 | case KNX_TELEGRAM_INCORRECT_PAYLOAD_LENGTH : str+="INCORRECT_PAYLOAD_LGTH"; break; 175 | case KNX_TELEGRAM_INVALID_COMMAND_FIELD : str+="INVALID_CMD_FIELD"; break; 176 | case KNX_TELEGRAM_UNKNOWN_COMMAND : str+="UNKNOWN_CMD"; break; 177 | case KNX_TELEGRAM_INCORRECT_CHECKSUM : str+="INCORRECT_CHKSUM"; break; 178 | default : str+="ERR_VAL!"; break; 179 | } 180 | str+='\n'; 181 | } 182 | 183 | // EOF 184 | -------------------------------------------------------------------------------- /src/KnxComObject.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KONNEKTING Device Library. 3 | * 4 | * The KONNEKTING Device Library is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef KNXCOMOBJECT_H 19 | #define KNXCOMOBJECT_H 20 | 21 | #include "KnxDataPointTypes.h" 22 | #include "KnxTelegram.h" 23 | #include "DebugUtil.h" 24 | 25 | // !!!!!!!!!!!!!!! FLAG OPTIONS !!!!!!!!!!!!!!!!! 26 | 27 | // Definition of comobject indicator values 28 | // See "knx.org" for comobject indicators specification 29 | // See: https://redaktion.knx-user-forum.de/lexikon/flags/ 30 | // INDICATOR field : B7 B6 B5 B4 B3 B2 B1 B0 31 | // xx xx C R W T U I 32 | // xx xx K L S Ü A I 33 | #define KNX_COM_OBJ_C_INDICATOR 0x20 // Communication (C) 34 | #define KNX_COM_OBJ_R_INDICATOR 0x10 // Read (R) 35 | #define KNX_COM_OBJ_W_INDICATOR 0x08 // Write (W) 36 | #define KNX_COM_OBJ_T_INDICATOR 0x04 // Transmit (T) 37 | #define KNX_COM_OBJ_U_INDICATOR 0x02 // Update (U) 38 | #define KNX_COM_OBJ_I_INDICATOR 0x01 // Init Read (I) 39 | 40 | // Definition of predefined com obj profiles 41 | // Sensor profile : COM_OBJ_SENSOR 42 | #define COM_OBJ_SENSOR KNX_COM_OBJ_C_R_T_INDICATOR 43 | #define KNX_COM_OBJ_C_R_T_INDICATOR 0x34 // ( Communication | Read | Transmit ) 44 | 45 | // Logic input profile : COM_OBJ_LOGIC_IN 46 | #define COM_OBJ_LOGIC_IN KNX_COM_OBJ_C_W_U_INDICATOR 47 | 48 | #define KNX_COM_OBJ_C_W_U_INDICATOR 0x2A // ( Communication | Write | Update ) 49 | #define KNX_COM_OBJ_C_W_U_T_INDICATOR 0x2E // ( Communication | Write | Update | Transmit ) 50 | 51 | // Logic input to be initialized at bus power-up profile : COM_OBJ_LOGIC_IN_INIT 52 | #define COM_OBJ_LOGIC_IN_INIT KNX_COM_OBJ_C_W_U_I_INDICATOR 53 | #define KNX_COM_OBJ_C_W_U_I_INDICATOR 0x2B // ( Communication | Write | Update | Init) 54 | 55 | #define KNX_COM_OBJECT_OK 0 56 | #define KNX_COM_OBJECT_ERROR 255 57 | 58 | class KnxComObject { 59 | 60 | // set to active if GA has been set 61 | bool _active; 62 | 63 | /** 64 | * Group Address value 65 | */ 66 | word _addr; 67 | 68 | /** 69 | * DPT 70 | */ 71 | byte _dptId; 72 | 73 | /** 74 | * C/R/W/T/U/I indicators 75 | */ 76 | byte _indicator; 77 | 78 | /** 79 | * Com object data length is calculated in the same way as telegram payload length 80 | * (See "knx.org" telegram specification for more details) 81 | */ 82 | byte _dataLength; 83 | 84 | /** 85 | * _validated: used for "InitRead" typed comobjects: 86 | * "false" until the object value is updated 87 | * Other typed comobjects get "true" value immediately 88 | */ 89 | bool _validated; 90 | 91 | union { 92 | // field used in case of short value (1 byte max width, i.e. length <= 2) 93 | struct { 94 | byte _value; 95 | byte _notUSed; 96 | }; 97 | // field used in case of long value (2 bytes width or more, i.e. length > 2) 98 | // The data space is allocated dynamically by the constructor 99 | byte* _longValue; 100 | }; 101 | 102 | public: 103 | // Constructor : 104 | KnxComObject(KnxDpt dptId, byte indicator); 105 | 106 | // Destructor 107 | ~KnxComObject(); 108 | 109 | bool isActive(void); 110 | 111 | // INLINED functions (see definitions later in this file) 112 | word getAddr(void) const; 113 | 114 | /** 115 | * Overwrite address value defined at construction 116 | * The function is used in case of programming 117 | * @param the GA to set 118 | */ 119 | void setAddr(word); 120 | 121 | void setIndicator(byte); 122 | 123 | byte getDptId(void) const; 124 | 125 | e_KnxPriority getPriority(void) const; 126 | 127 | byte getIndicator(void) const; 128 | 129 | bool getValidity(void) const; 130 | 131 | void setValidity(void); 132 | 133 | byte getLength(void) const; 134 | 135 | /** 136 | * Return the com obj value (short value case only) 137 | * @return 138 | */ 139 | byte getValue(void) const; 140 | 141 | /** 142 | * Update the com obj value (short value case only) 143 | * @param newVal 144 | * @return ERROR if the com obj is long value (invalid use case), else return OK 145 | */ 146 | byte updateValue(byte newVal); 147 | 148 | /** 149 | * Toggle the binary value (for com objs with "B1" format) 150 | */ 151 | void toggleValue(void); 152 | 153 | // functions NOT INLINED : 154 | 155 | /** 156 | * Get the com obj value (short and long value cases) 157 | * @param dest 158 | */ 159 | void getValue(byte dest[]) const; 160 | 161 | /** 162 | * Update the com obj value (short and long value cases) 163 | * @param ori 164 | */ 165 | void updateValue(const byte ori[]); 166 | 167 | /** 168 | * Update the com obj value with a telegram payload content 169 | * @param ori 170 | * @return ERROR if the telegram payload length differs from com obj one, else return OK 171 | */ 172 | byte updateValue(const KnxTelegram& ori); 173 | 174 | /** 175 | * Copy the com obj attributes (addr, prio, length) into a telegram object 176 | * @param dest 177 | */ 178 | void copyAttributes(KnxTelegram& dest) const; 179 | 180 | /** 181 | * Copy the com obj value into a telegram object 182 | * @param dest 183 | */ 184 | void copyValue(KnxTelegram& dest) const; 185 | }; 186 | 187 | // --------------- Definition of the INLINE functions ----------------- 188 | 189 | inline word KnxComObject::getAddr(void) const { 190 | return _addr; 191 | } 192 | 193 | inline void KnxComObject::setAddr(word addr) { 194 | _addr = addr; 195 | _active = true; 196 | } 197 | 198 | inline void KnxComObject::setIndicator(byte indicator) { 199 | _indicator = indicator & 0x3F /* mask for bit 0..b5, b6+b7 is not used here*/; 200 | } 201 | 202 | inline byte KnxComObject::getDptId(void) const { 203 | return _dptId; 204 | } 205 | 206 | inline e_KnxPriority KnxComObject::getPriority(void) const { 207 | return KNX_PRIORITY_NORMAL_VALUE; 208 | } 209 | 210 | inline byte KnxComObject::getIndicator(void) const { 211 | return _indicator; 212 | } 213 | 214 | inline bool KnxComObject::getValidity(void) const { 215 | return _validated; 216 | } 217 | 218 | inline void KnxComObject::setValidity(void) { 219 | _validated = true; 220 | } 221 | 222 | inline byte KnxComObject::getLength(void) const { 223 | return _dataLength; 224 | } 225 | 226 | inline byte KnxComObject::getValue(void) const { 227 | return _value; 228 | } 229 | 230 | inline byte KnxComObject::updateValue(byte newValue) { 231 | if (_dataLength > 2) return KNX_COM_OBJECT_ERROR; 232 | _value = newValue; 233 | _validated = true; 234 | return KNX_COM_OBJECT_OK; 235 | } 236 | 237 | inline void KnxComObject::toggleValue(void) { 238 | _value = !_value; 239 | } 240 | 241 | #endif // KNXCOMOBJECT_H 242 | -------------------------------------------------------------------------------- /examples/DemoSketch_without_pins/DemoSketch_without_pins.ino: -------------------------------------------------------------------------------- 1 | #define KONNEKTING_SYSTEM_TYPE_SIMPLE 2 | #include 3 | 4 | // include device related configuration code, created by "KONNEKTING CodeGenerator" 5 | #include "kdevice_DemoSketch.h" 6 | 7 | // ################################################ 8 | // ### BOARD CONFIGURATION 9 | // ################################################ 10 | 11 | #ifdef __AVR_ATmega328P__ 12 | // Uno/Nano/ProMini 13 | #define KNX_SERIAL Serial // D0=RX/D1=TX 14 | #define LED_PROG 11 // External LED 15 | #define LED_BLINK 12 // External LED 16 | #define LED_COMOBJ LED_BUILTIN // On board LED on pin D13 17 | // ATmega328P has only one UART, lets use virtual one 18 | #include 19 | SoftwareSerial softserial(11, 10); // D11=RX/D10=TX 20 | #define DEBUGSERIAL softserial 21 | 22 | #elif __AVR_ATmega32U4__ 23 | // Leonardo/Micro/ProMicro 24 | #define KNX_SERIAL Serial1 // D0=RX/D1=TX 25 | #define LED_PROG 11 // External LED 26 | #define LED_BLINK 12 // External LED 27 | #define LED_COMOBJ LED_BUILTIN // On board LED on pin D13 28 | #define DEBUGSERIAL Serial // USB port 29 | 30 | #elif ARDUINO_ARCH_SAMD 31 | // Zero/M0 32 | #define KNX_SERIAL Serial1 // D0=RX/D1=TX 33 | #define LED_PROG 11 // External LED 34 | #define LED_BLINK 12 // External LED 35 | #define LED_COMOBJ LED_BUILTIN // On board LED on pin D13 36 | #define DEBUGSERIAL SerialUSB // USB port 37 | // Arduino Zero has no "real" internal EEPROM, 38 | // so we can use an external I2C EEPROM. 39 | #include "EEPROM_24AA256.h" // external EEPROM 40 | 41 | #elif ARDUINO_ARCH_STM32 42 | // STM32 NUCLEO Boards 43 | // Option Serial interface: "Enabled with generic Serial" should be enabled 44 | // Create a new Serial on Pins PA10 & PA9 45 | // Arduino-Header: D2(PA10)=RX/D8(PA9)=TX 46 | HardwareSerial Serial1(PA10, PA9); 47 | #define KNX_SERIAL Serial1 48 | #define LED_PROG 11 // External LED 49 | #define LED_BLINK 12 // External LED 50 | #define LED_COMOBJ LED_BUILTIN // On board LED on pin D13 51 | #define DEBUGSERIAL Serial // USB port 52 | 53 | #elif ESP8266 54 | // ESP8266 55 | #define KNX_SERIAL Serial // swaped Serial on D7(GPIO13)=RX/GPIO15(D8)=TX 56 | #define LED_PROG 14 // External LED 57 | #define LED_BLINK 12 // External LED 58 | #define LED_COMOBJ 16 // External LED 59 | #define DEBUGSERIAL Serial1 // the 2nd serial port with TX only (GPIO2/D4) 60 | 61 | #else 62 | // All other boards 63 | #error "Sorry, you board is not supported" 64 | #endif 65 | 66 | // ################################################ 67 | // ### DEBUG CONFIGURATION 68 | // ################################################ 69 | //#define KDEBUG // comment this line to disable DEBUG mode 70 | #ifdef KDEBUG 71 | #include 72 | #endif 73 | 74 | // ################################################ 75 | // ### Global variables, sketch related 76 | // ################################################ 77 | unsigned long blinkDelay = 2500; // default value 78 | unsigned long lastmillis = millis(); 79 | int laststate = false; 80 | 81 | // ################################################ 82 | // ### set ProgLED status 83 | // ################################################ 84 | //this function is used to indicate programming mode. 85 | //you can use LED, LCD display or what ever you want... 86 | void progLed(bool state) 87 | { 88 | digitalWrite(LED_PROG, state); 89 | } 90 | 91 | // ################################################ 92 | // ### SETUP 93 | // ################################################ 94 | 95 | void setup() 96 | { 97 | 98 | // debug related stuff 99 | #ifdef KDEBUG 100 | 101 | // Start debug serial with 115200 bauds 102 | DEBUGSERIAL.begin(115200); 103 | 104 | #if defined(__AVR_ATmega32U4__) || defined(__SAMD21G18A__) 105 | // wait for serial port to connect. for Leonardo/Micro/ProMicro/Zero only 106 | while (!DEBUGSERIAL) 107 | #endif 108 | 109 | // make debug serial port known to debug class 110 | // Means: KONNEKTING will sue the same serial port for console debugging 111 | Debug.setPrintStream(&DEBUGSERIAL); 112 | #endif 113 | 114 | Debug.print(F("KONNEKTING DemoSketch\n")); 115 | pinMode(LED_PROG, OUTPUT); 116 | pinMode(LED_COMOBJ, OUTPUT); 117 | pinMode(LED_BLINK, OUTPUT); 118 | 119 | /* 120 | * Only required when using external eeprom (or similar) storage. 121 | * function pointers should match the methods you have implemented above. 122 | * If no external eeprom required, please remove all three Konnekting.setMemory* lines below 123 | */ 124 | #ifdef __SAMD21G18A__ 125 | Wire.begin(); 126 | Konnekting.setMemoryReadFunc(&readMemory); 127 | Konnekting.setMemoryWriteFunc(&writeMemory); 128 | Konnekting.setMemoryUpdateFunc(&updateMemory); 129 | Konnekting.setMemoryCommitFunc(&commitMemory); 130 | #endif 131 | 132 | // Initialize KNX enabled Arduino Board 133 | Konnekting.init(KNX_SERIAL, 134 | &progLed, 135 | MANUFACTURER_ID, 136 | DEVICE_ID, 137 | REVISION); 138 | 139 | // If device has been parametrized with KONNEKTING Suite, read params from EEPROM 140 | // Otherwise continue with global default values from sketch 141 | if (!Konnekting.isFactorySetting()) 142 | { 143 | blinkDelay = (int)Konnekting.getUINT16Param(PARAM_blinkDelay); //blink every xxxx ms 144 | } 145 | 146 | lastmillis = millis(); 147 | 148 | Debug.println(F("Toggle LED every %d ms."), blinkDelay); 149 | Debug.println(F("Setup is ready. go to loop...")); 150 | 151 | //this is an example, how you can set programming mode 152 | if (Konnekting.isFactorySetting()) 153 | { 154 | Debug.println(F("Device is in factory mode. Starting programming mode...")); 155 | Konnekting.setProgState(true); 156 | } 157 | } 158 | 159 | // ################################################ 160 | // ### LOOP 161 | // ################################################ 162 | 163 | void loop() 164 | { 165 | 166 | // Do KNX related stuff (like sending/receiving KNX telegrams) 167 | // This is required in every KONNEKTING aplication sketch 168 | Knx.task(); 169 | 170 | unsigned long currentmillis = millis(); 171 | 172 | /* 173 | * only do measurements and other sketch related stuff if not in programming mode 174 | * means: only when konnekting is ready for appliction 175 | */ 176 | if (Konnekting.isReadyForApplication()) 177 | { 178 | 179 | if (currentmillis - lastmillis >= blinkDelay) 180 | { 181 | 182 | Debug.println(F("Actual state: %d"), laststate); 183 | Knx.write(COMOBJ_trigger, laststate); 184 | laststate = !laststate; 185 | lastmillis = currentmillis; 186 | 187 | digitalWrite(LED_BLINK, laststate); 188 | Debug.println(F("DONE")); 189 | } 190 | } 191 | } 192 | 193 | // ################################################ 194 | // ### KNX EVENT CALLBACK 195 | // ################################################ 196 | 197 | void knxEvents(byte index) 198 | { 199 | switch (index) 200 | { 201 | case COMOBJ_ledOnOff: // object index has been updated 202 | 203 | if (Knx.read(COMOBJ_ledOnOff)) 204 | { 205 | digitalWrite(LED_COMOBJ, HIGH); 206 | Debug.println(F("Toggle LED: on")); 207 | } 208 | else 209 | { 210 | digitalWrite(LED_COMOBJ, LOW); 211 | Debug.println(F("Toggle LED: off")); 212 | } 213 | break; 214 | 215 | default: 216 | break; 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /src/KnxDevice.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KONNEKTING Device Library. 3 | * 4 | * The KONNEKTING Device Library is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef KNXDEVICE_H 19 | #define KNXDEVICE_H 20 | 21 | #include "Arduino.h" 22 | #include "KnxTelegram.h" 23 | #include "KnxComObject.h" 24 | #include "RingBuff.h" 25 | #include "KnxTpUart.h" 26 | #include "KonnektingDevice.h" 27 | 28 | // !!!!!!!!!!!!!!! FLAG OPTIONS !!!!!!!!!!!!!!!!! 29 | // DEBUG : 30 | //#define KNXDEVICE_DEBUG_INFO // Uncomment to activate info traces 31 | 32 | // Values returned by the KnxDevice functions 33 | enum KnxDeviceStatus { 34 | KNX_DEVICE_OK = 0, 35 | KNX_DEVICE_INVALID_INDEX = 1, 36 | KNX_DEVICE_INIT_ERROR = 2, 37 | KNX_DEVICE_COMOBJ_INACTIVE = 3, 38 | KNX_DEVICE_NOT_IMPLEMENTED = 254, 39 | KNX_DEVICE_ERROR = 255 40 | }; 41 | 42 | // Macro functions for conversion of physical and group addresses 43 | inline word P_ADDR(byte area, byte line, byte busdevice) 44 | { return (word) ( ((area&0xF)<<12) + ((line&0xF)<<8) + busdevice ); } 45 | 46 | inline word G_ADDR(byte maingrp, byte midgrp, byte subgrp) 47 | { return (word) ( ((maingrp&0x1F)<<11) + ((midgrp&0x7)<<8) + subgrp ); } 48 | 49 | #define ACTIONS_QUEUE_SIZE 16 50 | 51 | // KnxDevice internal state 52 | enum InternalDeviceState { 53 | INIT, 54 | IDLE, 55 | TX_ONGOING, 56 | }; 57 | 58 | // Action types 59 | enum TxActionType { 60 | KNX_READ_REQUEST, 61 | KNX_WRITE_REQUEST, 62 | KNX_RESPONSE_REQUEST 63 | }; 64 | 65 | typedef struct TxAction{ 66 | TxActionType command; // Action type to be performed 67 | byte index; // Index of the involved ComObject 68 | union { // Value 69 | // Field used in case of short value (value width <= 1 byte) 70 | struct { 71 | byte byteValue; 72 | byte notUsed; 73 | }; 74 | byte *valuePtr; // Field used in case of long value (width > 1 byte), space is allocated dynamically 75 | }; 76 | } TxAction; 77 | 78 | 79 | // Callback function to catch and treat KNX events 80 | // The definition shall be provided by the end-user 81 | extern void knxEvents(byte); 82 | 83 | 84 | // --------------- Definition of the functions for DPT translation -------------------- 85 | // Functions to convert a DPT format to a standard C type 86 | // NB : only the usual DPT formats are supported (U16, V16, U32, V32, F16 and F32) 87 | template KnxDeviceStatus ConvertFromDpt(const byte dpt[], T& result, byte dptFormat); 88 | 89 | // Functions to convert a standard C type to a DPT format 90 | // NB : only the usual DPT formats are supported (U16, V16, U32, V32, F16 and F32) 91 | template KnxDeviceStatus ConvertToDpt(T value, byte dpt[], byte dptFormat); 92 | 93 | 94 | class KnxDevice { 95 | 96 | // List of Com Objects attached to the KNX Device 97 | // The definition shall be provided by the end-user 98 | static KnxComObject _comObjectsList[]; 99 | 100 | // Nb of attached Com Objects 101 | // The value shall be provided by the end-user 102 | static const byte _numberOfComObjects; 103 | 104 | KnxComObject _progComObj = KnxComObject(KNX_DPT_60000_60000 /* KNX PROGRAM */, KNX_COM_OBJ_C_W_U_T_INDICATOR); 105 | 106 | // Current KnxDevice state 107 | InternalDeviceState _state; 108 | 109 | // TPUART associated to the KNX Device 110 | KnxTpUart *_tpuart; 111 | 112 | // Queue of transmit actions to be performed 113 | RingBuff _txActionList; 114 | 115 | // True when all the Com Object with Init attr have been initialized 116 | bool _initCompleted; 117 | 118 | // Index to the last initiated object 119 | byte _initIndex; 120 | 121 | // Time (in msec) of the last init (read) request on the bus 122 | word _lastInitTimeMillis; 123 | 124 | // Time (in msec) of the last Tpuart Rx activity; 125 | word _lastRXTimeMicros; 126 | 127 | // Time (in msec) of the last Tpuart Tx activity; 128 | word _lastTXTimeMicros; 129 | 130 | // Telegram object used for telegrams sending 131 | KnxTelegram _txTelegram; 132 | 133 | // Reference to the telegram received by the TPUART 134 | KnxTelegram *_rxTelegram; 135 | 136 | // Constructor, Destructor 137 | // private constructor (singleton design pattern) 138 | KnxDevice(); 139 | // private destructor (singleton design pattern) 140 | ~KnxDevice() {} 141 | // private copy constructor (singleton design pattern) 142 | KnxDevice (const KnxDevice&); 143 | 144 | 145 | public: 146 | 147 | // unique KnxDevice instance (singleton design pattern) 148 | static KnxDevice Knx; 149 | 150 | int getNumberOfComObjects(); 151 | 152 | /* 153 | * Start the KNX Device 154 | * return KNX_DEVICE_ERROR (255) if begin() failed 155 | * else return KNX_DEVICE_OK 156 | */ 157 | KnxDeviceStatus begin(HardwareSerial& serial, word physicalAddr); 158 | 159 | /* 160 | * Stop the KNX Device 161 | */ 162 | void end(); 163 | 164 | /* 165 | * KNX device execution task 166 | * This function shall be called in the "loop()" Arduino function 167 | */ 168 | void task(void); 169 | 170 | /* 171 | * Quick method to read a short (<=1 byte) com object 172 | * NB : The returned value will be hazardous in case of use with long objects 173 | */ 174 | byte read(byte objectIndex); 175 | 176 | /* 177 | * Read an usual format com object 178 | * Supported DPT formats are short com object, U16, V16, U32, V32, F16 and F32 179 | */ 180 | template KnxDeviceStatus read(byte objectIndex, T& returnedValue); 181 | 182 | /* 183 | * Read any type of com object (DPT value provided as is) 184 | */ 185 | KnxDeviceStatus read(byte objectIndex, byte returnedValue[]); 186 | 187 | // Update com object functions : 188 | // For all the update functions, the com object value is updated locally 189 | // and a telegram is sent on the KNX bus if the object has both COMMUNICATION & TRANSMIT attributes set 190 | 191 | /* 192 | * Update an usual format com object 193 | * Supported DPT types are short com object, U16, V16, U32, V32, F16 and F32 194 | */ 195 | template KnxDeviceStatus write(byte objectIndex, T value); 196 | 197 | /* 198 | * Update any type of com object (rough DPT value shall be provided) 199 | */ 200 | KnxDeviceStatus write(byte objectIndex, byte valuePtr[]); 201 | 202 | 203 | /* 204 | * Com Object KNX Bus Update request 205 | * Request the local object to be updated with the value from the bus 206 | * NB : the function is asynchroneous, the update completion is notified by the knxEvents() callback 207 | */ 208 | void update(byte objectIndex); 209 | 210 | 211 | /** 212 | * TODO document me 213 | * @return 214 | */ 215 | bool isActive(void) const; 216 | 217 | KnxDeviceStatus setComObjectIndicator(byte index, byte indicator); 218 | KnxDeviceStatus setComObjectAddress(byte index, word addr); 219 | 220 | /* 221 | * Gets the address of an commobjects 222 | */ 223 | word getComObjectAddress(byte index); 224 | 225 | private: 226 | /* 227 | * Static getTpUartEvents() function called by the KnxTpUart layer (callback) 228 | */ 229 | static void getTpUartEvents(KnxTpUartEvent event); 230 | 231 | /* 232 | * Static txTelegramAck() function called by the KnxTpUart layer (callback) 233 | */ 234 | static void txTelegramAck(TpUartTxAck); 235 | 236 | }; 237 | 238 | // Reference to the KnxDevice unique instance 239 | extern KnxDevice& Knx; 240 | 241 | #endif // KNXDEVICE_H 242 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For KONNEKTING 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | Konnekting KEYWORD1 10 | Knx KEYWORD1 11 | Debug KEYWORD1 12 | KnxDevice KEYWORD1 13 | KnxComObject KEYWORD1 14 | KonnektingDevice KEYWORD1 15 | 16 | ####################################### 17 | # Methods and Functions (KEYWORD2) 18 | ####################################### 19 | 20 | readMemory KEYWORD2 21 | writeMemory KEYWORD2 22 | updateMemory KEYWORD2 23 | commitMemory KEYWORD2 24 | setPrintStream KEYWORD2 25 | setMemoryReadFunc KEYWORD2 26 | setMemoryWriteFunc KEYWORD2 27 | setMemoryUpdateFunc KEYWORD2 28 | setMemoryCommitFunc KEYWORD2 29 | setDataOpenWriteFunc KEYWORD2 30 | setDataOpenReadFunc KEYWORD2 31 | setDataWriteFunc KEYWORD2 32 | setDataReadFunc KEYWORD2 33 | setDataRemoveFunc KEYWORD2 34 | setDataCloseFunc KEYWORD2 35 | init KEYWORD2 36 | isActive KEYWORD2 37 | isFactorySetting KEYWORD2 38 | isProgState KEYWORD2 39 | isReadyForApplication KEYWORD2 40 | getFreeEepromOffset KEYWORD2 41 | knxEvents KEYWORD2 42 | task KEYWORD2 43 | getINT8Param KEYWORD2 44 | getUINT8Param KEYWORD2 45 | getINT16Param KEYWORD2 46 | getUINT16Param KEYWORD2 47 | getINT32Param KEYWORD2 48 | getUINT32Param KEYWORD2 49 | getSTRING11Param KEYWORD2 50 | 51 | ####################################### 52 | # Instances (KEYWORD2) 53 | ####################################### 54 | 55 | 56 | ####################################### 57 | # Constants (LITERAL1) 58 | ####################################### 59 | KDEBUG LITERAL1 60 | DEBUGSERIAL LITERAL1 61 | KNX_SERIAL LITERAL1 62 | PROG_BUTTON_PIN LITERAL1 63 | PROG_LED_PIN LITERAL1 64 | MANUFACTURER_ID LITERAL1 65 | DEVICE_ID LITERAL1 66 | REVISION LITERAL1 67 | _comObjectsList LITERAL1 68 | _numberOfComObjects LITERAL1 69 | _paramSizeList LITERAL1 70 | _numberOfParams LITERAL1 71 | PARAM_INT8 LITERAL1 72 | PARAM_UINT8 LITERAL1 73 | PARAM_INT16 LITERAL1 74 | PARAM_UINT16 LITERAL1 75 | PARAM_INT32 LITERAL1 76 | PARAM_UINT32 LITERAL1 77 | PARAM_RAW1 LITERAL1 78 | PARAM_RAW2 LITERAL1 79 | PARAM_RAW3 LITERAL1 80 | PARAM_RAW4 LITERAL1 81 | PARAM_RAW5 LITERAL1 82 | PARAM_RAW6 LITERAL1 83 | PARAM_RAW7 LITERAL1 84 | PARAM_RAW8 LITERAL1 85 | PARAM_RAW9 LITERAL1 86 | PARAM_RAW10 LITERAL1 87 | PARAM_RAW11 LITERAL1 88 | PARAM_STRING11 LITERAL1 89 | KNX_DPT_1_001 LITERAL1 90 | KNX_DPT_1_002 LITERAL1 91 | KNX_DPT_1_003 LITERAL1 92 | KNX_DPT_1_004 LITERAL1 93 | KNX_DPT_1_005 LITERAL1 94 | KNX_DPT_1_006 LITERAL1 95 | KNX_DPT_1_007 LITERAL1 96 | KNX_DPT_1_008 LITERAL1 97 | KNX_DPT_1_009 LITERAL1 98 | KNX_DPT_1_010 LITERAL1 99 | KNX_DPT_1_011 LITERAL1 100 | KNX_DPT_1_012 LITERAL1 101 | KNX_DPT_1_013 LITERAL1 102 | KNX_DPT_1_014 LITERAL1 103 | KNX_DPT_1_015 LITERAL1 104 | KNX_DPT_1_016 LITERAL1 105 | KNX_DPT_1_017 LITERAL1 106 | KNX_DPT_1_018 LITERAL1 107 | KNX_DPT_1_019 LITERAL1 108 | KNX_DPT_1_021 LITERAL1 109 | KNX_DPT_1_022 LITERAL1 110 | KNX_DPT_1_023 LITERAL1 111 | KNX_DPT_1_100 LITERAL1 112 | KNX_DPT_2_001 LITERAL1 113 | KNX_DPT_2_002 LITERAL1 114 | KNX_DPT_2_003 LITERAL1 115 | KNX_DPT_2_004 LITERAL1 116 | KNX_DPT_2_005 LITERAL1 117 | KNX_DPT_2_006 LITERAL1 118 | KNX_DPT_2_007 LITERAL1 119 | KNX_DPT_2_008 LITERAL1 120 | KNX_DPT_2_009 LITERAL1 121 | KNX_DPT_2_010 LITERAL1 122 | KNX_DPT_2_011 LITERAL1 123 | KNX_DPT_2_012 LITERAL1 124 | KNX_DPT_3_007 LITERAL1 125 | KNX_DPT_3_008 LITERAL1 126 | KNX_DPT_4_001 LITERAL1 127 | KNX_DPT_4_002 LITERAL1 128 | KNX_DPT_5_001 LITERAL1 129 | KNX_DPT_5_003 LITERAL1 130 | KNX_DPT_5_004 LITERAL1 131 | KNX_DPT_5_005 LITERAL1 132 | KNX_DPT_5_006 LITERAL1 133 | KNX_DPT_5_010 LITERAL1 134 | KNX_DPT_6_001 LITERAL1 135 | KNX_DPT_6_010 LITERAL1 136 | KNX_DPT_6_020 LITERAL1 137 | KNX_DPT_7_001 LITERAL1 138 | KNX_DPT_7_002 LITERAL1 139 | KNX_DPT_7_003 LITERAL1 140 | KNX_DPT_7_004 LITERAL1 141 | KNX_DPT_7_005 LITERAL1 142 | KNX_DPT_7_006 LITERAL1 143 | KNX_DPT_7_007 LITERAL1 144 | KNX_DPT_7_010 LITERAL1 145 | KNX_DPT_7_011 LITERAL1 146 | KNX_DPT_7_012 LITERAL1 147 | KNX_DPT_7_013 LITERAL1 148 | KNX_DPT_8_001 LITERAL1 149 | KNX_DPT_8_002 LITERAL1 150 | KNX_DPT_8_003 LITERAL1 151 | KNX_DPT_8_004 LITERAL1 152 | KNX_DPT_8_005 LITERAL1 153 | KNX_DPT_8_006 LITERAL1 154 | KNX_DPT_8_007 LITERAL1 155 | KNX_DPT_8_010 LITERAL1 156 | KNX_DPT_8_011 LITERAL1 157 | KNX_DPT_9_001 LITERAL1 158 | KNX_DPT_9_002 LITERAL1 159 | KNX_DPT_9_003 LITERAL1 160 | KNX_DPT_9_004 LITERAL1 161 | KNX_DPT_9_005 LITERAL1 162 | KNX_DPT_9_006 LITERAL1 163 | KNX_DPT_9_007 LITERAL1 164 | KNX_DPT_9_008 LITERAL1 165 | KNX_DPT_9_010 LITERAL1 166 | KNX_DPT_9_011 LITERAL1 167 | KNX_DPT_9_020 LITERAL1 168 | KNX_DPT_9_021 LITERAL1 169 | KNX_DPT_9_022 LITERAL1 170 | KNX_DPT_9_023 LITERAL1 171 | KNX_DPT_9_024 LITERAL1 172 | KNX_DPT_9_025 LITERAL1 173 | KNX_DPT_9_026 LITERAL1 174 | KNX_DPT_9_027 LITERAL1 175 | KNX_DPT_9_028 LITERAL1 176 | KNX_DPT_10_001 LITERAL1 177 | KNX_DPT_11_001 LITERAL1 178 | KNX_DPT_12_001 LITERAL1 179 | KNX_DPT_13_001 LITERAL1 180 | KNX_DPT_13_010 LITERAL1 181 | KNX_DPT_13_011 LITERAL1 182 | KNX_DPT_13_012 LITERAL1 183 | KNX_DPT_13_013 LITERAL1 184 | KNX_DPT_13_014 LITERAL1 185 | KNX_DPT_13_015 LITERAL1 186 | KNX_DPT_13_100 LITERAL1 187 | KNX_DPT_14_000 LITERAL1 188 | KNX_DPT_14_001 LITERAL1 189 | KNX_DPT_14_002 LITERAL1 190 | KNX_DPT_14_003 LITERAL1 191 | KNX_DPT_14_004 LITERAL1 192 | KNX_DPT_14_005 LITERAL1 193 | KNX_DPT_14_006 LITERAL1 194 | KNX_DPT_14_007 LITERAL1 195 | KNX_DPT_16_000 LITERAL1 196 | KNX_DPT_16_001 LITERAL1 197 | KNX_DPT_17_001 LITERAL1 198 | KNX_DPT_19_001 LITERAL1 199 | KNX_DPT_232_600 LITERAL1 200 | KNX_DPT_60000_60000 LITERAL1 201 | ####################################### 202 | # Syntax Coloring Map For KONNEKTING 203 | ####################################### 204 | 205 | ####################################### 206 | # Datatypes (KEYWORD1) 207 | ####################################### 208 | 209 | Konnekting KEYWORD1 210 | Knx KEYWORD1 211 | Debug KEYWORD1 212 | KnxDevice KEYWORD1 213 | KnxComObject KEYWORD1 214 | KonnektingDevice KEYWORD1 215 | 216 | ####################################### 217 | # Methods and Functions (KEYWORD2) 218 | ####################################### 219 | 220 | readMemory KEYWORD2 221 | writeMemory KEYWORD2 222 | updateMemory KEYWORD2 223 | commitMemory KEYWORD2 224 | setPrintStream KEYWORD2 225 | setMemoryReadFunc KEYWORD2 226 | setMemoryWriteFunc KEYWORD2 227 | setMemoryUpdateFunc KEYWORD2 228 | setMemoryCommitFunc KEYWORD2 229 | setProgLedFunc KEYWORD2 230 | init KEYWORD2 231 | kinit KEYWORD2 232 | isActive KEYWORD2 233 | isFactorySetting KEYWORD2 234 | isProgState KEYWORD2 235 | isReadyForApplication KEYWORD2 236 | getFreeEepromOffset KEYWORD2 237 | knxEvents KEYWORD2 238 | task KEYWORD2 239 | getParamValue KEYWORD2 240 | getINT8Param KEYWORD2 241 | getUINT8Param KEYWORD2 242 | getINT16Param KEYWORD2 243 | getUINT16Param KEYWORD2 244 | getINT32Param KEYWORD2 245 | getUINT32Param KEYWORD2 246 | getSTRING11Param KEYWORD2 247 | 248 | ####################################### 249 | # Instances (KEYWORD2) 250 | ####################################### 251 | 252 | 253 | ####################################### 254 | # Constants (LITERAL1) 255 | ####################################### 256 | KDEBUG LITERAL1 257 | DEBUGSERIAL LITERAL1 258 | KNX_SERIAL LITERAL1 259 | PROG_BUTTON_PIN LITERAL1 260 | PROG_LED_PIN LITERAL1 261 | MANUFACTURER_ID LITERAL1 262 | DEVICE_ID LITERAL1 263 | REVISION LITERAL1 264 | _comObjectsList LITERAL1 265 | _numberOfComObjects LITERAL1 266 | _paramSizeList LITERAL1 267 | _numberOfParams LITERAL1 268 | PARAM_INT8 LITERAL1 269 | PARAM_UINT8 LITERAL1 270 | PARAM_INT16 LITERAL1 271 | PARAM_UINT16 LITERAL1 272 | PARAM_INT32 LITERAL1 273 | PARAM_UINT32 LITERAL1 274 | PARAM_RAW1 LITERAL1 275 | PARAM_RAW2 LITERAL1 276 | PARAM_RAW3 LITERAL1 277 | PARAM_RAW4 LITERAL1 278 | PARAM_RAW5 LITERAL1 279 | PARAM_RAW6 LITERAL1 280 | PARAM_RAW7 LITERAL1 281 | PARAM_RAW8 LITERAL1 282 | PARAM_RAW9 LITERAL1 283 | PARAM_RAW10 LITERAL1 284 | PARAM_RAW11 LITERAL1 285 | PARAM_STRING11 LITERAL1 286 | KNX_DPT_1_000 LITERAL1 287 | KNX_DPT_1_001 LITERAL1 288 | KNX_DPT_1_002 LITERAL1 289 | KNX_DPT_1_003 LITERAL1 290 | KNX_DPT_1_004 LITERAL1 291 | KNX_DPT_1_005 LITERAL1 292 | KNX_DPT_1_006 LITERAL1 293 | KNX_DPT_1_007 LITERAL1 294 | KNX_DPT_1_008 LITERAL1 295 | KNX_DPT_1_009 LITERAL1 296 | KNX_DPT_1_010 LITERAL1 297 | KNX_DPT_1_011 LITERAL1 298 | KNX_DPT_1_012 LITERAL1 299 | KNX_DPT_1_013 LITERAL1 300 | KNX_DPT_1_014 LITERAL1 301 | KNX_DPT_1_015 LITERAL1 302 | KNX_DPT_1_016 LITERAL1 303 | KNX_DPT_1_017 LITERAL1 304 | KNX_DPT_1_018 LITERAL1 305 | KNX_DPT_1_019 LITERAL1 306 | KNX_DPT_1_021 LITERAL1 307 | KNX_DPT_1_022 LITERAL1 308 | KNX_DPT_1_023 LITERAL1 309 | KNX_DPT_1_100 LITERAL1 310 | KNX_DPT_2_001 LITERAL1 311 | KNX_DPT_2_002 LITERAL1 312 | KNX_DPT_2_003 LITERAL1 313 | KNX_DPT_2_004 LITERAL1 314 | KNX_DPT_2_005 LITERAL1 315 | KNX_DPT_2_006 LITERAL1 316 | KNX_DPT_2_007 LITERAL1 317 | KNX_DPT_2_008 LITERAL1 318 | KNX_DPT_2_009 LITERAL1 319 | KNX_DPT_2_010 LITERAL1 320 | KNX_DPT_2_011 LITERAL1 321 | KNX_DPT_2_012 LITERAL1 322 | KNX_DPT_3_007 LITERAL1 323 | KNX_DPT_3_008 LITERAL1 324 | KNX_DPT_4_001 LITERAL1 325 | KNX_DPT_4_002 LITERAL1 326 | KNX_DPT_5_000 LITERAL1 327 | KNX_DPT_5_001 LITERAL1 328 | KNX_DPT_5_003 LITERAL1 329 | KNX_DPT_5_004 LITERAL1 330 | KNX_DPT_5_005 LITERAL1 331 | KNX_DPT_5_006 LITERAL1 332 | KNX_DPT_5_010 LITERAL1 333 | KNX_DPT_6_001 LITERAL1 334 | KNX_DPT_6_010 LITERAL1 335 | KNX_DPT_6_020 LITERAL1 336 | KNX_DPT_7_000 LITERAL1 337 | KNX_DPT_7_001 LITERAL1 338 | KNX_DPT_7_002 LITERAL1 339 | KNX_DPT_7_003 LITERAL1 340 | KNX_DPT_7_004 LITERAL1 341 | KNX_DPT_7_005 LITERAL1 342 | KNX_DPT_7_006 LITERAL1 343 | KNX_DPT_7_007 LITERAL1 344 | KNX_DPT_7_010 LITERAL1 345 | KNX_DPT_7_011 LITERAL1 346 | KNX_DPT_7_012 LITERAL1 347 | KNX_DPT_7_013 LITERAL1 348 | KNX_DPT_8_000 LITERAL1 349 | KNX_DPT_8_001 LITERAL1 350 | KNX_DPT_8_002 LITERAL1 351 | KNX_DPT_8_003 LITERAL1 352 | KNX_DPT_8_004 LITERAL1 353 | KNX_DPT_8_005 LITERAL1 354 | KNX_DPT_8_006 LITERAL1 355 | KNX_DPT_8_007 LITERAL1 356 | KNX_DPT_8_010 LITERAL1 357 | KNX_DPT_8_011 LITERAL1 358 | KNX_DPT_9_000 LITERAL1 359 | KNX_DPT_9_001 LITERAL1 360 | KNX_DPT_9_002 LITERAL1 361 | KNX_DPT_9_003 LITERAL1 362 | KNX_DPT_9_004 LITERAL1 363 | KNX_DPT_9_005 LITERAL1 364 | KNX_DPT_9_006 LITERAL1 365 | KNX_DPT_9_007 LITERAL1 366 | KNX_DPT_9_008 LITERAL1 367 | KNX_DPT_9_010 LITERAL1 368 | KNX_DPT_9_011 LITERAL1 369 | KNX_DPT_9_020 LITERAL1 370 | KNX_DPT_9_021 LITERAL1 371 | KNX_DPT_9_022 LITERAL1 372 | KNX_DPT_9_023 LITERAL1 373 | KNX_DPT_9_024 LITERAL1 374 | KNX_DPT_9_025 LITERAL1 375 | KNX_DPT_9_026 LITERAL1 376 | KNX_DPT_9_027 LITERAL1 377 | KNX_DPT_9_028 LITERAL1 378 | KNX_DPT_10_001 LITERAL1 379 | KNX_DPT_11_001 LITERAL1 380 | KNX_DPT_12_000 LITERAL1 381 | KNX_DPT_12_001 LITERAL1 382 | KNX_DPT_13_000 LITERAL1 383 | KNX_DPT_13_001 LITERAL1 384 | KNX_DPT_13_010 LITERAL1 385 | KNX_DPT_13_011 LITERAL1 386 | KNX_DPT_13_012 LITERAL1 387 | KNX_DPT_13_013 LITERAL1 388 | KNX_DPT_13_014 LITERAL1 389 | KNX_DPT_13_015 LITERAL1 390 | KNX_DPT_13_100 LITERAL1 391 | KNX_DPT_14_000 LITERAL1 392 | KNX_DPT_14_001 LITERAL1 393 | KNX_DPT_14_002 LITERAL1 394 | KNX_DPT_14_003 LITERAL1 395 | KNX_DPT_14_004 LITERAL1 396 | KNX_DPT_14_005 LITERAL1 397 | KNX_DPT_14_006 LITERAL1 398 | KNX_DPT_14_007 LITERAL1 399 | KNX_DPT_16_000 LITERAL1 400 | KNX_DPT_16_001 LITERAL1 401 | KNX_DPT_17_001 LITERAL1 402 | KNX_DPT_19_001 LITERAL1 403 | KNX_DPT_232_600 LITERAL1 404 | KNX_DPT_60000_60000 LITERAL1 405 | -------------------------------------------------------------------------------- /src/KnxTelegram.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KONNEKTING Device Library. 3 | * 4 | * The KONNEKTING Device Library is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef KNXTELEGRAM_H 19 | #define KNXTELEGRAM_H 20 | 21 | #include "Arduino.h" 22 | 23 | // ---------- Knx Telegram description (visit "www.knx.org" for more info) ----------- 24 | // => Length : 9 bytes min. to 23 bytes max. 25 | // 26 | // => Structure : 27 | // -Header (6 bytes): 28 | // Byte 0 | Control Field 29 | // Byte 1 | Source Address High byte 30 | // Byte 2 | Source Address Low byte 31 | // Byte 3 | Destination Address High byte 32 | // Byte 4 | Destination Address Low byte 33 | // Byte 5 | Routing field 34 | // -Payload (from 2 up to 16 bytes): 35 | // Byte 6 | Commmand field High 36 | // Byte 7 | Command field Low + 1st payload data (6bits) 37 | // Byte 8 up to 21 | payload bytes (optional) 38 | // -Checksum (1 byte) 39 | // 40 | // => Fields details : 41 | // -Control Field : "FFR1 PP00" format with 42 | // FF = Frame Format (10 = Std Length L_DATA service, 00 = extended L_DATA service, 11 = L_POLLDATA service) 43 | // R = Repeatflag (1 = not repeated, 0 = repeated) 44 | // PP = Priority (00 = system, 10 = alarm, 01 = high, 11 = normal) 45 | // -Routing Field : "TCCC LLLL" format with 46 | // T = Target Addr type (1 = group address/muticast, 0 = individual address/unicast) 47 | // CCC = Counter 48 | // LLLL = Payload Length (1-15) 49 | // -Command Field : "00XX XXCC CCDD DDDD" format with 50 | // XX = Not used 51 | // CC = command (0000 = Value Read, 0001 = Value Response, 0010 = Value Write, 1010 = Memory Write) 52 | // DD = Payload Data (1st payload byte) 53 | // 54 | // => Transmit timings : 55 | // -Tbit = 104us, Tbyte=1,35ms (13 bits per character) 56 | // -from 20ms for 1 byte payload telegram (Bus temporisation + Telegram transmit + ACK) 57 | // -up to 40ms for 15 bytes payload (Bus temporisation + Telegram transmit + ACK) 58 | // 59 | 60 | // Define for lengths & offsets 61 | #define KNX_TELEGRAM_HEADER_SIZE 6 62 | #define KNX_TELEGRAM_PAYLOAD_MAX_SIZE 16 63 | #define KNX_TELEGRAM_MIN_SIZE 9 64 | #define KNX_TELEGRAM_MAX_SIZE 23 65 | #define KNX_TELEGRAM_LENGTH_OFFSET 8 // Offset between payload length and telegram length 66 | 67 | enum e_KnxPriority { 68 | KNX_PRIORITY_SYSTEM_VALUE = B00000000, 69 | KNX_PRIORITY_HIGH_VALUE = B00000100, 70 | KNX_PRIORITY_ALARM_VALUE = B00001000, 71 | KNX_PRIORITY_NORMAL_VALUE = B00001100 72 | }; 73 | 74 | enum e_KnxCommand { 75 | KNX_COMMAND_VALUE_READ = B00000000, 76 | KNX_COMMAND_VALUE_RESPONSE = B00000001, 77 | KNX_COMMAND_VALUE_WRITE = B00000010, 78 | KNX_COMMAND_MEMORY_WRITE = B00001010 79 | }; 80 | 81 | //--- CONTROL FIELD values & masks --- 82 | #define CONTROL_FIELD_DEFAULT_VALUE B10111100 // Standard FF; No Repeat; Normal Priority 83 | #define CONTROL_FIELD_FRAME_FORMAT_MASK B11000000 84 | #define CONTROL_FIELD_STANDARD_FRAME_FORMAT B10000000 85 | #define CONTROL_FIELD_REPEATED_MASK B00100000 86 | #define CONTROL_FIELD_SET_REPEATED(x) (x&=B11011111) 87 | #define CONTROL_FIELD_PRIORITY_MASK B00001100 88 | #define CONTROL_FIELD_PATTERN_MASK B00010011 89 | #define CONTROL_FIELD_VALID_PATTERN B00010000 90 | 91 | // --- ROUTING FIELD values & masks --- 92 | #define ROUTING_FIELD_DEFAULT_VALUE B11100001 // Multicast(Target Group @), Routing Counter = 6, Length = 1 93 | #define ROUTING_FIELD_TARGET_ADDRESS_TYPE_MASK B10000000 94 | #define ROUTING_FIELD_COUNTER_MASK B01110000 95 | #define ROUTING_FIELD_PAYLOAD_LENGTH_MASK B00001111 96 | 97 | // --- COMMAND FIELD values & masks --- 98 | #define COMMAND_FIELD_HIGH_COMMAND_MASK 0x03 99 | #define COMMAND_FIELD_LOW_COMMAND_MASK 0xC0 // 2 first bytes on _commandL 100 | #define COMMAND_FIELD_LOW_DATA_MASK 0x3F // 6 last bytes are data 101 | #define COMMAND_FIELD_PATTERN_MASK B11000000 102 | #define COMMAND_FIELD_VALID_PATTERN B00000000 103 | 104 | enum e_KnxTelegramValidity { KNX_TELEGRAM_VALID = 0 , 105 | KNX_TELEGRAM_INVALID_CONTROL_FIELD, 106 | KNX_TELEGRAM_UNSUPPORTED_FRAME_FORMAT, 107 | KNX_TELEGRAM_INCORRECT_PAYLOAD_LENGTH, 108 | KNX_TELEGRAM_INVALID_COMMAND_FIELD, 109 | KNX_TELEGRAM_UNKNOWN_COMMAND, 110 | KNX_TELEGRAM_INCORRECT_CHECKSUM }; 111 | 112 | class KnxTelegram { 113 | union { 114 | byte _telegram[KNX_TELEGRAM_MAX_SIZE]; // byte 0 to 22 115 | struct { 116 | byte _controlField; // byte 0 117 | byte _sourceAddrH; // byte 1 118 | byte _sourceAddrL; // byte 2 119 | byte _targetAddrH; // byte 3 120 | byte _targetAddrL; // byte 4 121 | byte _routing; // byte 5 122 | byte _commandH; // byte 6 123 | byte _commandL; // byte 7 124 | byte _payloadChecksum[KNX_TELEGRAM_PAYLOAD_MAX_SIZE-1]; // byte 8 to 22 125 | }; 126 | }; 127 | 128 | public: 129 | // CONSTRUCTOR 130 | // builds telegram with following default values : 131 | // std FF, no repeat, normal prio, empty payload, multicast, routing counter = 6, payload length = 1 132 | KnxTelegram(); 133 | 134 | // INLINED functions (defined later in this file) 135 | void changePriority(e_KnxPriority priority); 136 | e_KnxPriority getPriority(void) const; 137 | 138 | void setRepeated(void); 139 | boolean isRepeated(void) const; 140 | 141 | void setSourceAddress(word addr); 142 | word getSourceAddress(void) const; 143 | void setTargetAddress(word addr); 144 | word getTargetAddress(void) const; 145 | 146 | void setMulticast(boolean); 147 | boolean isMulticast(void) const; 148 | 149 | void changeRoutingCounter(byte counter); 150 | byte getRoutingCounter(void) const; 151 | 152 | void setPayloadLength(byte length); 153 | byte getPayloadLength(void) const; 154 | 155 | byte getTelegramLength(void) const; 156 | 157 | void setCommand(e_KnxCommand cmd); 158 | e_KnxCommand getCommand(void) const; 159 | 160 | // Handling of the 1st payload byte (the 6 lowest bits in _commandL field) 161 | void setFirstPayloadByte(byte data); 162 | void clearFirstPayloadByte(void); 163 | byte getFirstPayloadByte(void) const; 164 | 165 | // Read of the telegram byte per byte 166 | // NB : do not check that the index is in the range 167 | byte readRawByte(byte byteIndex) const; 168 | 169 | // Write of the telegram byte per byte 170 | // NB : do not check that the index is in the range 171 | void writeRawByte(byte data, byte byteIndex); 172 | 173 | byte getChecksum(void) const; 174 | boolean isChecksumCorrect(void) const; 175 | 176 | // functions NOT INLINED (see definitions in KnxTelegram.cpp) 177 | void clearTelegram(void); // (re)set telegram with default values 178 | 179 | // Set 'nbOfBytes' bytes of the payload starting from the 2nd payload byte 180 | // if 'nbOfBytes' val is out of range, then we use the max allowed value instead 181 | void setLongPayload(const byte origin[], byte nbOfBytes); 182 | // Get 'nbOfBytes' bytes of the payload starting from the 2nd payload byte 183 | // if 'nbOfBytes' val is out of range, then we use the max allowed value instead 184 | void getLongPayload(byte destination[], byte nbOfBytes) const; 185 | 186 | // Clear the whole payload except the 1st payload byte 187 | void clearLongPayload(void); 188 | 189 | byte calculateChecksum(void) const; 190 | // Let the class calculate and update the proper checksum value in the telegram 191 | void updateChecksum(void); 192 | 193 | // Whole telegram copy 194 | void copy(KnxTelegram& dest) const; 195 | // Header Copy (6 1st bytes of the telegram) 196 | void copyHeader(KnxTelegram& dest) const; 197 | 198 | e_KnxTelegramValidity getValidity(void) const; 199 | 200 | // DEBUG functions : 201 | void info(String&) const; // copy telegram info into a string 202 | void infoRaw(String&) const; // copy raw data telegram into a string 203 | void infoVerbose(String&) const; // copy verbose telegram info into a string 204 | }; 205 | 206 | 207 | // --------------- Definition of the INLINED functions : ----------------- 208 | inline void KnxTelegram::changePriority(e_KnxPriority priority) 209 | { _controlField &= ~CONTROL_FIELD_PRIORITY_MASK; _controlField |= priority & CONTROL_FIELD_PRIORITY_MASK;} 210 | 211 | inline e_KnxPriority KnxTelegram::getPriority(void) const 212 | {return (e_KnxPriority)(_controlField & CONTROL_FIELD_PRIORITY_MASK);} 213 | 214 | inline void KnxTelegram::setRepeated(void ) 215 | { CONTROL_FIELD_SET_REPEATED(_controlField);}; 216 | 217 | inline boolean KnxTelegram::isRepeated(void) const 218 | {if (_controlField & CONTROL_FIELD_REPEATED_MASK ) return false; else return true ; } 219 | 220 | inline void KnxTelegram::setSourceAddress(word addr) { 221 | // WARNING : works with little endianness only 222 | // The adresses within KNX telegram are big endian 223 | _sourceAddrL = (byte) addr; _sourceAddrH = byte(addr>>8);} 224 | 225 | inline word KnxTelegram::getSourceAddress(void) const { 226 | // WARNING : works with little endianness only 227 | // The adresses within KNX telegram are big endian 228 | word addr; addr = _sourceAddrL + (_sourceAddrH<<8); return addr; } 229 | 230 | inline void KnxTelegram::setTargetAddress(word addr) { 231 | // WARNING : works with little endianness only 232 | // The adresses within KNX telegram are big endian 233 | _targetAddrL = (byte) addr; _targetAddrH = byte(addr>>8);} 234 | 235 | inline word KnxTelegram::getTargetAddress(void) const { 236 | // WARNING : endianess sensitive!! Code below is for LITTLE ENDIAN chip 237 | // The KNX telegram uses BIG ENDIANNESS (Hight byte placed before Low Byte) 238 | word addr; addr = _targetAddrL + (_targetAddrH<<8); return addr; } 239 | 240 | inline boolean KnxTelegram::isMulticast(void) const 241 | {return (_routing & ROUTING_FIELD_TARGET_ADDRESS_TYPE_MASK);} 242 | 243 | inline void KnxTelegram::setMulticast(boolean mode) 244 | { if (mode) _routing|= ROUTING_FIELD_TARGET_ADDRESS_TYPE_MASK; 245 | else _routing &= ~ROUTING_FIELD_TARGET_ADDRESS_TYPE_MASK; } 246 | 247 | inline void KnxTelegram::changeRoutingCounter(byte counter) 248 | { counter <<= 4; _routing &= ~ROUTING_FIELD_COUNTER_MASK; _routing |= (counter & ROUTING_FIELD_COUNTER_MASK); } 249 | 250 | inline byte KnxTelegram::getRoutingCounter(void) const 251 | { return ((_routing & ROUTING_FIELD_COUNTER_MASK)>>4); } 252 | 253 | inline void KnxTelegram::setPayloadLength(byte length) 254 | { _routing&= ~ROUTING_FIELD_PAYLOAD_LENGTH_MASK ; _routing |= length & ROUTING_FIELD_PAYLOAD_LENGTH_MASK; } 255 | 256 | inline byte KnxTelegram::getPayloadLength(void) const 257 | {return (_routing & ROUTING_FIELD_PAYLOAD_LENGTH_MASK);} 258 | 259 | inline byte KnxTelegram::getTelegramLength(void) const 260 | { return (KNX_TELEGRAM_LENGTH_OFFSET + getPayloadLength());} 261 | 262 | inline void KnxTelegram::setCommand(e_KnxCommand cmd) { 263 | _commandH &= ~COMMAND_FIELD_HIGH_COMMAND_MASK; _commandH |= (cmd >> 2); 264 | _commandL &= ~COMMAND_FIELD_LOW_COMMAND_MASK; _commandL |= (cmd << 6);} 265 | 266 | inline e_KnxCommand KnxTelegram::getCommand(void) const 267 | {return (e_KnxCommand)(((_commandL & COMMAND_FIELD_LOW_COMMAND_MASK)>>6) + ((_commandH & COMMAND_FIELD_HIGH_COMMAND_MASK)<<2)); }; 268 | 269 | inline void KnxTelegram::setFirstPayloadByte(byte data) 270 | { _commandL &= ~COMMAND_FIELD_LOW_DATA_MASK ; _commandL |= data & COMMAND_FIELD_LOW_DATA_MASK; } 271 | 272 | inline void KnxTelegram::clearFirstPayloadByte(void) 273 | { _commandL &= ~COMMAND_FIELD_LOW_DATA_MASK;} 274 | 275 | inline byte KnxTelegram::getFirstPayloadByte(void) const 276 | { return (_commandL & COMMAND_FIELD_LOW_DATA_MASK);} 277 | 278 | inline byte KnxTelegram::readRawByte(byte byteIndex) const 279 | { return _telegram[byteIndex];} 280 | 281 | inline void KnxTelegram::writeRawByte(byte data, byte byteIndex) 282 | { _telegram[byteIndex] = data;} 283 | 284 | inline byte KnxTelegram::getChecksum(void) const 285 | { return (_payloadChecksum[getPayloadLength() - 1]);} 286 | 287 | inline boolean KnxTelegram::isChecksumCorrect(void) const 288 | { return (getChecksum()==calculateChecksum());} 289 | 290 | #endif // KNXTELEGRAM_H -------------------------------------------------------------------------------- /src/KonnektingDevice.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file KonnektingDevice.h 3 | * 4 | * This is part of KONNEKTING Device Library for the Arduino platform. 5 | * 6 | * Copyright (C) 2016 Alexander Christian . All rights 7 | * reserved. This file is part of KONNEKTING Device Library. 8 | * 9 | * The KONNEKTING Device Library is free software: you can redistribute 10 | * it and/or modify it under the terms of the GNU General Public License as 11 | * published by the Free Software Foundation, either version 3 of the License, 12 | * or (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program. If not, see . 21 | */ 22 | 23 | #ifndef KONNEKTING_h 24 | #define KONNEKTING_h 25 | 26 | #define KONNEKTING_DEVICE_LIBRARY_VERSION 10000 27 | #define KONNEKTING_DEVICE_LIBRARY_SNAPSHOT 28 | #define KONNEKTING_1_0_0_beta5 29 | 30 | #include "System.h" 31 | 32 | #include 33 | 34 | #include "DebugUtil.h" 35 | #include "KnxDevice.h" 36 | #include "KnxDptConstants.h" 37 | // for doing CRC32 checks in data read/write 38 | #include // https://github.com/bakercp/CRC32 39 | 40 | // AVR, ESP8266, ESP32 and STM32 uses EEPROM (SAMD21 not ...) 41 | #if defined(__AVR__) || defined(ESP8266) || defined(ESP32) || defined(ARDUINO_ARCH_STM32) 42 | #include 43 | #ifdef ARDUINO_ARCH_AVR 44 | #include 45 | #endif 46 | #endif 47 | 48 | 49 | // --------------------------------------------------------------------------------------------------- 50 | // System Table Memory Layout, see https://wiki.konnekting.de/index.php/KONNEKTING_Protocol_Specification_0x01#System_Table 51 | 52 | // ReadOnly Section: 53 | // =================== 54 | #define SYSTEMTABLE_VERSION 0 // 2 bytes 55 | #define SYSTEMTABLE_DEVICE_FLAGS 2 ///< EEPROM index for device flags 56 | 57 | // actual addresses are defined by System.h 58 | #define SYSTEMTABLE_ADDRESSTABLE_ADDRESS 3 // 2 bytes 59 | #define SYSTEMTABLE_ASSOCIATIONTABLE_ADDRESS 5 // 2 bytes 60 | #define SYSTEMTABLE_COMMOBJECTTABLE_ADDRESS 7 // 2 bytes 61 | #define SYSTEMTABLE_PARAMETERTABLE_ADDRESS 9 // 2 bytes 62 | 63 | #define SYSTEMTABLE_CRC_SYSTEMTABLE 11 // 4 bytes 64 | #define SYSTEMTABLE_CRC_ADDRESSTABLE 15 // 4 bytes 65 | #define SYSTEMTABLE_CRC_ASSOCIATIONTABLE 19 // 4 bytes 66 | #define SYSTEMTABLE_CRC_COMMOBJECTTABLE 23 // 4 bytes 67 | #define SYSTEMTABLE_CRC_PARAMETERTABLE 27 // 4 bytes 68 | 69 | // Read+Write Section: 70 | // =================== 71 | #define SYSTEMTABLE_INDIVIDUALADDRESS 48 ///< EEPROM index for IA, high byte, +1 = LO byte 72 | // --------------------------------------------------------------------------------------------------- 73 | 74 | 75 | #define KONNEKTING_VERSION 0x0000 76 | #define PROTOCOLVERSION 1 77 | 78 | #define ACK 0x00 79 | #define NACK 0xFF 80 | #define ERR_CODE_OK 0x00 81 | #define ERR_CODE_NOT_SUPPORTED 0x01 82 | #define ERR_CODE_DATA_OPEN_WRITE_FAILED 0x02 83 | #define ERR_CODE_DATA_OPEN_READ_FAILED 0x03 84 | #define ERR_CODE_DATA_WRITE_FAILED 0x04 85 | #define ERR_CODE_DATA_READ_FAILED 0x05 86 | #define ERR_CODE_DATA_CRC_FAILED 0x06 87 | #define ERR_CODE_TIMEOUT 0x07 88 | #define ERR_CODE_ILLEGAL_STATE 0x08 89 | #define ERR_CODE_TABLE_CRC_FAILED 0x09 90 | 91 | #define SYSTEM_TYPE_SIMPLE 0x00 92 | #define SYSTEM_TYPE_DEFAULT 0x01 93 | #define SYSTEM_TYPE_EXTENDED 0x02 // DRAFT! 94 | 95 | #define MSG_LENGTH 14 ///< Message length in bytes 96 | 97 | #define MSGTYPE_ACK 0x00 ///< Message Type: ACK 0x00 98 | #define MSGTYPE_PROPERTY_PAGE_READ 0x01 ///< Message Type: Property Page Read 0x01 99 | #define MSGTYPE_PROPERTY_PAGE_RESPONSE 0x02 ///< Message Type: Property Page Response 0x02 100 | 101 | #define MSGTYPE_CHECKSUM_SET 0x03 ///< Message Type: Checksum Set 0x03 102 | 103 | #define MSGTYPE_UNLOAD 0x08 ///< Message Type: Unload 0x08 104 | #define MSGTYPE_RESTART 0x09 ///< Message Type: Restart 0x09 105 | 106 | #define MSGTYPE_PROGRAMMING_MODE_WRITE 0x0A ///< Message Type: Programming Mode Write 0x0C 107 | #define MSGTYPE_PROGRAMMING_MODE_READ 0x0B ///< Message Type: Programming Mode Read 0x0A 108 | #define MSGTYPE_PROGRAMMING_MODE_RESPONSE 0x0C ///< Message Type: Programming Mode Response 0x0B 109 | 110 | #define MSGTYPE_MEMORY_WRITE 0x1E ///< Message Type: Memory Write 0x1E 111 | #define MSGTYPE_MEMORY_READ 0x1F ///< Message Type: Memory Read 0x1F 112 | #define MSGTYPE_MEMORY_RESPONSE 0x20 ///< Message Type: Memory Response 0x20 113 | 114 | #define MSGTYPE_DATA_WRITE_PREPARE 0x28 ///< Message Type: Data Write Prepare 0x28 115 | #define MSGTYPE_DATA_WRITE 0x29 ///< Message Type: Data Write 0x29 116 | #define MSGTYPE_DATA_WRITE_FINISH 0x2A ///< Message Type: Data Write Finish 0x2A 117 | #define MSGTYPE_DATA_READ 0x2B ///< Message Type: Data Read 0x2B 118 | #define MSGTYPE_DATA_READ_RESPONSE 0x2C ///< Message Type: Data Read Response 0x2C 119 | #define MSGTYPE_DATA_READ_DATA 0x2D ///< Message Type: Data Read Data 0x2D 120 | #define MSGTYPE_DATA_REMOVE 0x2E ///< Message Type: Data Remove 0x2E 121 | 122 | #define DATA_TYPE_ID_UPDATE 0x00 ///< Firmware update for KONNEKTING device 123 | #define DATA_TYPE_ID_DATA 0x01 ///< Data, f.i. additional configuration, images, sounds, ... 124 | 125 | #define DEVICEFLAG_FACTORY_BIT 0x80 126 | #define DEVICEFLAG_IA_BIT 0x40 127 | #define DEVICEFLAG_CO_BIT 0x20 128 | #define DEVICEFLAG_PARAM_BIT 0x10 129 | #define DEVICEFLAG_DATA_BIT 0x08 130 | 131 | #define CHECKSUM_ID_SYSTEM_TABLE 0x00 132 | #define CHECKSUM_ID_ADDRESS_TABLE 0x01 133 | #define CHECKSUM_ID_ASSOCIATION_TABLE 0x02 134 | #define CHECKSUM_ID_COMMOBJECT_TABLE 0x03 135 | #define CHECKSUM_ID_PARAMETER_TABLE 0x04 136 | 137 | #define WAIT_FOR_ACK_TIMEOUT 5000 138 | 139 | #define PARAM_INT8 1 140 | #define PARAM_UINT8 1 141 | #define PARAM_INT16 2 142 | #define PARAM_UINT16 2 143 | #define PARAM_INT32 4 144 | #define PARAM_UINT32 4 145 | #define PARAM_RAW1 1 146 | #define PARAM_RAW2 2 147 | #define PARAM_RAW3 3 148 | #define PARAM_RAW4 4 149 | #define PARAM_RAW5 5 150 | #define PARAM_RAW6 6 151 | #define PARAM_RAW7 7 152 | #define PARAM_RAW8 8 153 | #define PARAM_RAW9 9 154 | #define PARAM_RAW10 10 155 | #define PARAM_RAW11 11 156 | #define PARAM_STRING11 11 157 | 158 | inline byte HI__(word w) { return (byte)((w >> 8) & 0xFF); } 159 | inline byte __LO(word w) { return (byte)((w >> 0) & 0xFF); } 160 | 161 | inline byte BB______(unsigned long dw) { return (byte)((dw >> 24) & 0xFF); } 162 | inline byte __BB____(unsigned long dw) { return (byte)((dw >> 16) & 0xFF); } 163 | inline byte ____BB__(unsigned long dw) { return (byte)((dw >> 8) & 0xFF); } 164 | inline byte ______BB(unsigned long dw) { return (byte)((dw >> 0) & 0xFF); } 165 | 166 | inline word __WORD(byte hi, byte lo) { 167 | return (word)( 168 | ((word)hi << 8) + 169 | ((word)lo << 0) 170 | ); 171 | } 172 | 173 | inline unsigned long __DWORD(byte b0, byte b1, byte b2, byte b3) { 174 | return (unsigned long)( 175 | ((unsigned long)b0 << 24) + 176 | ((unsigned long)b1 << 16) + 177 | ((unsigned long)b2 << 8) + 178 | ((unsigned long)b3 << 0) 179 | ); 180 | } 181 | 182 | // process intercepted knxEvents-calls with this method 183 | extern void konnektingKnxEvents(byte index); 184 | 185 | 186 | typedef struct AssociationTable { 187 | byte size; 188 | byte* gaId; 189 | byte* coId; 190 | }; 191 | 192 | typedef struct AddressTable { 193 | byte size; 194 | word* address; 195 | }; 196 | 197 | /** 198 | * see https://wiki.konnekting.de/index.php?title=KONNEKTING_Protocol_Specification_0x01#0x28_DataWritePrepare 199 | */ 200 | typedef struct DataWrite { 201 | byte count; 202 | byte data[11]; 203 | }; 204 | 205 | 206 | /**************************************************************************/ 207 | /*! 208 | * @brief Main class provides KONNEKTING Device API 209 | */ 210 | /**************************************************************************/ 211 | class KonnektingDevice { 212 | 213 | friend class KnxTpUart; 214 | //friend boolean KnxTpUart:IsAddressAssigned(word addr, ArrayList &indexList) const; 215 | 216 | static byte _paramSizeList[]; 217 | static const int _numberOfParams; 218 | /** 219 | * see https://wiki.konnekting.de/index.php?title=KONNEKTING_Protocol_Specification_0x01#Device_Memory_Layout 220 | */ 221 | static AssociationTable _associationTable; 222 | /** 223 | * see https://wiki.konnekting.de/index.php?title=KONNEKTING_Protocol_Specification_0x01#Device_Memory_Layout 224 | */ 225 | static AddressTable _addressTable; 226 | /** 227 | * maximum number of associations of single group address, depends on the programming via suite and the assiciations a usedr set up 228 | */ 229 | static byte _assocMaxTableEntries; 230 | 231 | byte (*_eepromReadFunc)(int); 232 | void (*_eepromWriteFunc)(int, byte); 233 | void (*_eepromUpdateFunc)(int, byte); 234 | void (*_eepromCommitFunc)(void); 235 | void (*_progIndicatorFunc)(bool); 236 | 237 | bool (*_dataOpenWriteFunc)(byte, byte, unsigned long); 238 | unsigned long (*_dataOpenReadFunc)(byte, byte); 239 | bool (*_dataWriteFunc)(byte*, int); 240 | bool (*_dataReadFunc)(byte*, int); 241 | bool (*_dataRemoveFunc)(byte, byte); 242 | bool (*_dataCloseFunc)(void); 243 | 244 | // Constructor, Destructor 245 | KonnektingDevice(); // private constructor (singleton design pattern) 246 | 247 | ~KonnektingDevice() {} // private destructor (singleton design pattern) 248 | KonnektingDevice(KonnektingDevice &); // private copy constructor (singleton design pattern) 249 | 250 | public: 251 | static KonnektingDevice Konnekting; 252 | 253 | void setMemoryReadFunc(byte (*func)(int)); 254 | void setMemoryWriteFunc(void (*func)(int, byte)); 255 | void setMemoryUpdateFunc(void (*func)(int, byte)); 256 | void setMemoryCommitFunc(void (*func)(void)); 257 | 258 | void setDataOpenWriteFunc(bool (*func)(byte, byte, unsigned long)); 259 | void setDataOpenReadFunc(unsigned long (*func)(byte, byte)); 260 | void setDataWriteFunc(bool (*func)(byte*, int)); 261 | void setDataReadFunc(bool (*func)(byte*, int)); 262 | void setDataRemoveFunc(bool (*func)(byte, byte)); 263 | void setDataCloseFunc(bool (*func)()); 264 | 265 | void init(HardwareSerial &serial, void (*progIndicatorFunc)(bool), 266 | word manufacturerID, byte deviceID, byte revisionID); 267 | 268 | void init(HardwareSerial &serial, int progButtonPin, int progLedPin, 269 | word manufacturerID, byte deviceID, byte revisionID); 270 | 271 | // needs to be public too, due to ISR handler mechanism :-( 272 | bool internalKnxEvents(byte index); 273 | 274 | // must be public to be accessible from KonnektingProgButtonPressed() 275 | void toggleProgState(); 276 | 277 | byte getParamSize(int index); 278 | void getParamValue(int index, byte *value); 279 | 280 | uint8_t getUINT8Param(int index); 281 | int8_t getINT8Param(int index); 282 | 283 | uint16_t getUINT16Param(int index); 284 | int16_t getINT16Param(int index); 285 | 286 | uint32_t getUINT32Param(int index); 287 | int32_t getINT32Param(int index); 288 | 289 | String getSTRING11Param(int index); 290 | 291 | bool isActive(); 292 | 293 | // ----------------------------- 294 | // device flags 295 | bool isFactorySetting(); 296 | bool isIndividualAddressSet(); 297 | bool isComObjSet(); 298 | bool isParamsSet(); 299 | bool isDataSet(); 300 | // ----------------------------- 301 | 302 | bool isProgState(); 303 | 304 | bool isReadyForApplication(); 305 | 306 | void setProgState(bool state); 307 | 308 | int getMemoryUserSpaceStart(); 309 | 310 | private: 311 | CRC32 _crc32; 312 | byte _ackCounter = 0; 313 | bool _rebootRequired = false; 314 | bool _initialized = false; 315 | #ifdef REBOOT_BUTTON 316 | byte _progbtnCount = 0; 317 | long _lastProgbtn = 0; 318 | #endif 319 | word _individualAddress; 320 | 321 | byte _deviceFlags; 322 | word _manufacturerID; 323 | byte _deviceID; 324 | byte _revisionID; 325 | 326 | int _progLED; 327 | int _progButton; // (->interrupt) 328 | void setProgLed(bool state); 329 | 330 | bool _progState; 331 | 332 | bool checkTableCRC(byte crcId); 333 | 334 | KnxComObject createProgComObject(); 335 | 336 | void internalInit(HardwareSerial &serial, word manufacturerID, byte deviceID, byte revisionID); 337 | int calcParamSkipBytes(int index); 338 | 339 | void reboot(); 340 | 341 | // prog methods 342 | void sendMsgAck(byte ackType, byte errorCode); 343 | bool waitForAck(byte ackCountBefore, unsigned long timeout); 344 | 345 | void handleMsgAck(byte *msg); 346 | void handleMsgReadDeviceInfo(byte *msg); 347 | 348 | void handleMsgUnload(byte *msg); 349 | void handleMsgRestart(byte *msg); 350 | 351 | void handleMsgChecksumSet(byte *msg); 352 | 353 | void handleMsgProgrammingModeWrite(byte *msg); 354 | void handleMsgProgrammingModeRead(byte *msg); 355 | void handleMsgPropertyPageRead(byte *msg); 356 | 357 | void handleMsgMemoryWrite(byte *msg); 358 | void handleMsgMemoryRead(byte *msg); 359 | 360 | void handleMsgDataWritePrepare(byte *msg); 361 | void handleMsgDataWrite(byte *msg); 362 | void handleMsgDataWriteFinish(byte *msg); 363 | void handleMsgDataRead(byte *msg); 364 | void handleMsgDataRemove(byte *msg); 365 | 366 | byte memoryRead(int index); 367 | void memoryWrite(int index, byte data); 368 | void memoryUpdate(int index, byte data); 369 | void memoryCommit(); 370 | 371 | void fillEmpty(byte *msg, int startIndex); 372 | }; 373 | 374 | // not part of Konnekting class 375 | void KonnektingProgButtonPressed(); 376 | 377 | // Reference to the KnxDevice unique instance 378 | extern KonnektingDevice &Konnekting; 379 | 380 | #endif // KONNEKTING_h 381 | -------------------------------------------------------------------------------- /doxygen-config: -------------------------------------------------------------------------------- 1 | # Doxyfile 1.8.13 2 | 3 | #--------------------------------------------------------------------------- 4 | # Project related configuration options 5 | #--------------------------------------------------------------------------- 6 | DOXYFILE_ENCODING = UTF-8 7 | PROJECT_NAME = "KONNEKING Device Library" 8 | PROJECT_NUMBER = 9 | PROJECT_BRIEF = 10 | PROJECT_LOGO = 11 | OUTPUT_DIRECTORY = "doc" 12 | CREATE_SUBDIRS = NO 13 | ALLOW_UNICODE_NAMES = NO 14 | OUTPUT_LANGUAGE = English 15 | BRIEF_MEMBER_DESC = YES 16 | REPEAT_BRIEF = YES 17 | ABBREVIATE_BRIEF = "The $name class" \ 18 | "The $name widget" \ 19 | "The $name file" \ 20 | is \ 21 | provides \ 22 | specifies \ 23 | contains \ 24 | represents \ 25 | a \ 26 | an \ 27 | the 28 | ALWAYS_DETAILED_SEC = NO 29 | INLINE_INHERITED_MEMB = NO 30 | FULL_PATH_NAMES = YES 31 | STRIP_FROM_PATH = 32 | STRIP_FROM_INC_PATH = 33 | SHORT_NAMES = NO 34 | JAVADOC_AUTOBRIEF = NO 35 | QT_AUTOBRIEF = NO 36 | MULTILINE_CPP_IS_BRIEF = NO 37 | INHERIT_DOCS = YES 38 | SEPARATE_MEMBER_PAGES = NO 39 | TAB_SIZE = 4 40 | ALIASES = 41 | TCL_SUBST = 42 | OPTIMIZE_OUTPUT_FOR_C = NO 43 | OPTIMIZE_OUTPUT_JAVA = NO 44 | OPTIMIZE_FOR_FORTRAN = NO 45 | OPTIMIZE_OUTPUT_VHDL = NO 46 | EXTENSION_MAPPING = 47 | MARKDOWN_SUPPORT = YES 48 | TOC_INCLUDE_HEADINGS = 0 49 | AUTOLINK_SUPPORT = YES 50 | BUILTIN_STL_SUPPORT = NO 51 | CPP_CLI_SUPPORT = NO 52 | SIP_SUPPORT = NO 53 | IDL_PROPERTY_SUPPORT = YES 54 | DISTRIBUTE_GROUP_DOC = NO 55 | GROUP_NESTED_COMPOUNDS = NO 56 | SUBGROUPING = YES 57 | INLINE_GROUPED_CLASSES = NO 58 | INLINE_SIMPLE_STRUCTS = NO 59 | TYPEDEF_HIDES_STRUCT = NO 60 | LOOKUP_CACHE_SIZE = 0 61 | #--------------------------------------------------------------------------- 62 | # Build related configuration options 63 | #--------------------------------------------------------------------------- 64 | EXTRACT_ALL = NO 65 | EXTRACT_PRIVATE = NO 66 | EXTRACT_PACKAGE = NO 67 | EXTRACT_STATIC = NO 68 | EXTRACT_LOCAL_CLASSES = YES 69 | EXTRACT_LOCAL_METHODS = NO 70 | EXTRACT_ANON_NSPACES = NO 71 | HIDE_UNDOC_MEMBERS = NO 72 | HIDE_UNDOC_CLASSES = NO 73 | HIDE_FRIEND_COMPOUNDS = NO 74 | HIDE_IN_BODY_DOCS = NO 75 | INTERNAL_DOCS = NO 76 | CASE_SENSE_NAMES = YES 77 | HIDE_SCOPE_NAMES = NO 78 | HIDE_COMPOUND_REFERENCE= NO 79 | SHOW_INCLUDE_FILES = YES 80 | SHOW_GROUPED_MEMB_INC = NO 81 | FORCE_LOCAL_INCLUDES = NO 82 | INLINE_INFO = YES 83 | SORT_MEMBER_DOCS = YES 84 | SORT_BRIEF_DOCS = NO 85 | SORT_MEMBERS_CTORS_1ST = NO 86 | SORT_GROUP_NAMES = NO 87 | SORT_BY_SCOPE_NAME = NO 88 | STRICT_PROTO_MATCHING = NO 89 | GENERATE_TODOLIST = YES 90 | GENERATE_TESTLIST = YES 91 | GENERATE_BUGLIST = YES 92 | GENERATE_DEPRECATEDLIST= YES 93 | ENABLED_SECTIONS = 94 | MAX_INITIALIZER_LINES = 30 95 | SHOW_USED_FILES = YES 96 | SHOW_FILES = YES 97 | SHOW_NAMESPACES = YES 98 | FILE_VERSION_FILTER = 99 | LAYOUT_FILE = 100 | CITE_BIB_FILES = 101 | #--------------------------------------------------------------------------- 102 | # Configuration options related to warning and progress messages 103 | #--------------------------------------------------------------------------- 104 | QUIET = NO 105 | WARNINGS = YES 106 | WARN_IF_UNDOCUMENTED = YES 107 | WARN_IF_DOC_ERROR = YES 108 | WARN_NO_PARAMDOC = NO 109 | WARN_AS_ERROR = NO 110 | WARN_FORMAT = "$file:$line: $text" 111 | WARN_LOGFILE = 112 | #--------------------------------------------------------------------------- 113 | # Configuration options related to the input files 114 | #--------------------------------------------------------------------------- 115 | INPUT = 116 | INPUT_ENCODING = UTF-8 117 | FILE_PATTERNS = *.ino \ 118 | *.c \ 119 | *.cc \ 120 | *.cxx \ 121 | *.cpp \ 122 | *.c++ \ 123 | *.java \ 124 | *.ii \ 125 | *.ixx \ 126 | *.ipp \ 127 | *.i++ \ 128 | *.inl \ 129 | *.idl \ 130 | *.ddl \ 131 | *.odl \ 132 | *.h \ 133 | *.hh \ 134 | *.hxx \ 135 | *.hpp \ 136 | *.h++ \ 137 | *.cs \ 138 | *.d \ 139 | *.php \ 140 | *.php4 \ 141 | *.php5 \ 142 | *.phtml \ 143 | *.inc \ 144 | *.m \ 145 | *.markdown \ 146 | *.md \ 147 | *.mm \ 148 | *.dox \ 149 | *.py \ 150 | *.pyw \ 151 | *.f90 \ 152 | *.f95 \ 153 | *.f03 \ 154 | *.f08 \ 155 | *.f \ 156 | *.for \ 157 | *.tcl \ 158 | *.vhd \ 159 | *.vhdl \ 160 | *.ucf \ 161 | *.qsf 162 | RECURSIVE = NO 163 | EXCLUDE = 164 | EXCLUDE_SYMLINKS = NO 165 | EXCLUDE_PATTERNS = 166 | EXCLUDE_SYMBOLS = 167 | EXAMPLE_PATH = 168 | EXAMPLE_PATTERNS = * 169 | EXAMPLE_RECURSIVE = NO 170 | IMAGE_PATH = 171 | INPUT_FILTER = 172 | FILTER_PATTERNS = 173 | FILTER_SOURCE_FILES = NO 174 | FILTER_SOURCE_PATTERNS = 175 | USE_MDFILE_AS_MAINPAGE = 176 | #--------------------------------------------------------------------------- 177 | # Configuration options related to source browsing 178 | #--------------------------------------------------------------------------- 179 | SOURCE_BROWSER = NO 180 | INLINE_SOURCES = NO 181 | STRIP_CODE_COMMENTS = YES 182 | REFERENCED_BY_RELATION = NO 183 | REFERENCES_RELATION = NO 184 | REFERENCES_LINK_SOURCE = YES 185 | SOURCE_TOOLTIPS = YES 186 | USE_HTAGS = NO 187 | VERBATIM_HEADERS = YES 188 | CLANG_ASSISTED_PARSING = NO 189 | CLANG_OPTIONS = 190 | #--------------------------------------------------------------------------- 191 | # Configuration options related to the alphabetical class index 192 | #--------------------------------------------------------------------------- 193 | ALPHABETICAL_INDEX = YES 194 | COLS_IN_ALPHA_INDEX = 5 195 | IGNORE_PREFIX = 196 | #--------------------------------------------------------------------------- 197 | # Configuration options related to the HTML output 198 | #--------------------------------------------------------------------------- 199 | GENERATE_HTML = YES 200 | HTML_OUTPUT = html 201 | HTML_FILE_EXTENSION = .html 202 | HTML_HEADER = 203 | HTML_FOOTER = 204 | HTML_STYLESHEET = 205 | HTML_EXTRA_STYLESHEET = 206 | HTML_EXTRA_FILES = 207 | HTML_COLORSTYLE_HUE = 220 208 | HTML_COLORSTYLE_SAT = 100 209 | HTML_COLORSTYLE_GAMMA = 80 210 | HTML_TIMESTAMP = NO 211 | HTML_DYNAMIC_SECTIONS = NO 212 | HTML_INDEX_NUM_ENTRIES = 100 213 | GENERATE_DOCSET = NO 214 | DOCSET_FEEDNAME = "Doxygen generated docs" 215 | DOCSET_BUNDLE_ID = org.doxygen.Project 216 | DOCSET_PUBLISHER_ID = org.doxygen.Publisher 217 | DOCSET_PUBLISHER_NAME = Publisher 218 | GENERATE_HTMLHELP = NO 219 | CHM_FILE = 220 | HHC_LOCATION = 221 | GENERATE_CHI = NO 222 | CHM_INDEX_ENCODING = 223 | BINARY_TOC = NO 224 | TOC_EXPAND = NO 225 | GENERATE_QHP = NO 226 | QCH_FILE = 227 | QHP_NAMESPACE = org.doxygen.Project 228 | QHP_VIRTUAL_FOLDER = doc 229 | QHP_CUST_FILTER_NAME = 230 | QHP_CUST_FILTER_ATTRS = 231 | QHP_SECT_FILTER_ATTRS = 232 | QHG_LOCATION = 233 | GENERATE_ECLIPSEHELP = NO 234 | ECLIPSE_DOC_ID = org.doxygen.Project 235 | DISABLE_INDEX = NO 236 | GENERATE_TREEVIEW = NO 237 | ENUM_VALUES_PER_LINE = 4 238 | TREEVIEW_WIDTH = 250 239 | EXT_LINKS_IN_WINDOW = NO 240 | FORMULA_FONTSIZE = 10 241 | FORMULA_TRANSPARENT = YES 242 | USE_MATHJAX = NO 243 | MATHJAX_FORMAT = HTML-CSS 244 | MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest 245 | MATHJAX_EXTENSIONS = 246 | MATHJAX_CODEFILE = 247 | SEARCHENGINE = YES 248 | SERVER_BASED_SEARCH = NO 249 | EXTERNAL_SEARCH = NO 250 | SEARCHENGINE_URL = 251 | SEARCHDATA_FILE = searchdata.xml 252 | EXTERNAL_SEARCH_ID = 253 | EXTRA_SEARCH_MAPPINGS = 254 | #--------------------------------------------------------------------------- 255 | # Configuration options related to the LaTeX output 256 | #--------------------------------------------------------------------------- 257 | GENERATE_LATEX = YES 258 | LATEX_OUTPUT = latex 259 | LATEX_CMD_NAME = latex 260 | MAKEINDEX_CMD_NAME = makeindex 261 | COMPACT_LATEX = NO 262 | PAPER_TYPE = a4 263 | EXTRA_PACKAGES = 264 | LATEX_HEADER = 265 | LATEX_FOOTER = 266 | LATEX_EXTRA_STYLESHEET = 267 | LATEX_EXTRA_FILES = 268 | PDF_HYPERLINKS = YES 269 | USE_PDFLATEX = YES 270 | LATEX_BATCHMODE = NO 271 | LATEX_HIDE_INDICES = NO 272 | LATEX_SOURCE_CODE = NO 273 | LATEX_BIB_STYLE = plain 274 | LATEX_TIMESTAMP = NO 275 | #--------------------------------------------------------------------------- 276 | # Configuration options related to the RTF output 277 | #--------------------------------------------------------------------------- 278 | GENERATE_RTF = NO 279 | RTF_OUTPUT = rtf 280 | COMPACT_RTF = NO 281 | RTF_HYPERLINKS = NO 282 | RTF_STYLESHEET_FILE = 283 | RTF_EXTENSIONS_FILE = 284 | RTF_SOURCE_CODE = NO 285 | #--------------------------------------------------------------------------- 286 | # Configuration options related to the man page output 287 | #--------------------------------------------------------------------------- 288 | GENERATE_MAN = NO 289 | MAN_OUTPUT = man 290 | MAN_EXTENSION = .3 291 | MAN_SUBDIR = 292 | MAN_LINKS = NO 293 | #--------------------------------------------------------------------------- 294 | # Configuration options related to the XML output 295 | #--------------------------------------------------------------------------- 296 | GENERATE_XML = NO 297 | XML_OUTPUT = xml 298 | XML_PROGRAMLISTING = YES 299 | #--------------------------------------------------------------------------- 300 | # Configuration options related to the DOCBOOK output 301 | #--------------------------------------------------------------------------- 302 | GENERATE_DOCBOOK = NO 303 | DOCBOOK_OUTPUT = docbook 304 | DOCBOOK_PROGRAMLISTING = NO 305 | #--------------------------------------------------------------------------- 306 | # Configuration options for the AutoGen Definitions output 307 | #--------------------------------------------------------------------------- 308 | GENERATE_AUTOGEN_DEF = NO 309 | #--------------------------------------------------------------------------- 310 | # Configuration options related to the Perl module output 311 | #--------------------------------------------------------------------------- 312 | GENERATE_PERLMOD = NO 313 | PERLMOD_LATEX = NO 314 | PERLMOD_PRETTY = YES 315 | PERLMOD_MAKEVAR_PREFIX = 316 | #--------------------------------------------------------------------------- 317 | # Configuration options related to the preprocessor 318 | #--------------------------------------------------------------------------- 319 | ENABLE_PREPROCESSING = YES 320 | MACRO_EXPANSION = NO 321 | EXPAND_ONLY_PREDEF = NO 322 | SEARCH_INCLUDES = YES 323 | INCLUDE_PATH = 324 | INCLUDE_FILE_PATTERNS = 325 | PREDEFINED = 326 | EXPAND_AS_DEFINED = 327 | SKIP_FUNCTION_MACROS = YES 328 | #--------------------------------------------------------------------------- 329 | # Configuration options related to external references 330 | #--------------------------------------------------------------------------- 331 | TAGFILES = 332 | GENERATE_TAGFILE = 333 | ALLEXTERNALS = NO 334 | EXTERNAL_GROUPS = YES 335 | EXTERNAL_PAGES = YES 336 | PERL_PATH = /usr/bin/perl 337 | #--------------------------------------------------------------------------- 338 | # Configuration options related to the dot tool 339 | #--------------------------------------------------------------------------- 340 | CLASS_DIAGRAMS = YES 341 | MSCGEN_PATH = 342 | DIA_PATH = 343 | HIDE_UNDOC_RELATIONS = YES 344 | HAVE_DOT = YES 345 | DOT_NUM_THREADS = 0 346 | DOT_FONTNAME = Helvetica 347 | DOT_FONTSIZE = 10 348 | DOT_FONTPATH = 349 | CLASS_GRAPH = YES 350 | COLLABORATION_GRAPH = YES 351 | GROUP_GRAPHS = YES 352 | UML_LOOK = NO 353 | UML_LIMIT_NUM_FIELDS = 10 354 | TEMPLATE_RELATIONS = NO 355 | INCLUDE_GRAPH = YES 356 | INCLUDED_BY_GRAPH = YES 357 | CALL_GRAPH = NO 358 | CALLER_GRAPH = NO 359 | GRAPHICAL_HIERARCHY = YES 360 | DIRECTORY_GRAPH = YES 361 | DOT_IMAGE_FORMAT = png 362 | INTERACTIVE_SVG = NO 363 | DOT_PATH = 364 | DOTFILE_DIRS = 365 | MSCFILE_DIRS = 366 | DIAFILE_DIRS = 367 | PLANTUML_JAR_PATH = 368 | PLANTUML_CFG_FILE = 369 | PLANTUML_INCLUDE_PATH = 370 | DOT_GRAPH_MAX_NODES = 50 371 | MAX_DOT_GRAPH_DEPTH = 0 372 | DOT_TRANSPARENT = NO 373 | DOT_MULTI_TARGETS = NO 374 | GENERATE_LEGEND = YES 375 | DOT_CLEANUP = YES 376 | -------------------------------------------------------------------------------- /src/KnxTpUart.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KONNEKTING Device Library. 3 | * 4 | * The KONNEKTING Device Library is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef KNXTPUART_H 19 | #define KNXTPUART_H 20 | 21 | #include "Arduino.h" 22 | #include "DebugUtil.h" 23 | #include "HardwareSerial.h" 24 | #include "KnxTelegram.h" 25 | #include "KnxComObject.h" 26 | #include "System.h" 27 | 28 | 29 | // !!!!!!!!!!!!!!! FLAG OPTIONS !!!!!!!!!!!!!!!!! 30 | // DEBUG : 31 | // #define KNXTPUART_DEBUG_INFO // Uncomment to activate info traces 32 | // #define KNXTPUART_DEBUG_ERROR // Uncomment to activate error traces 33 | 34 | 35 | // Values returned by the KnxTpUart member functions : 36 | #define KNX_TPUART_OK 0 37 | #define KNX_TPUART_ERROR 255 38 | #define KNX_TPUART_ERROR_NOT_INIT_STATE 254 39 | #define KNX_TPUART_ERROR_NULL_EVT_CALLBACK_FCT 253 40 | #define KNX_TPUART_ERROR_NULL_ACK_CALLBACK_FCT 252 41 | #define KNX_TPUART_ERROR_RESET 251 42 | 43 | 44 | // Services to TPUART (hostcontroller -> TPUART) : 45 | #define TPUART_RESET_REQ 0x01 46 | #define TPUART_STATE_REQ 0x02 47 | #define TPUART_SET_ADDR_REQ 0x28 48 | #define TPUART_DATA_START_CONTINUE_REQ 0x80 49 | #define TPUART_DATA_END_REQ 0x40 50 | #define TPUART_ACTIVATEBUSMON_REQ 0x05 51 | #define TPUART_RX_ACK_SERVICE_ADDRESSED 0x11 52 | #define TPUART_RX_ACK_SERVICE_NOT_ADDRESSED 0x10 53 | 54 | 55 | // Services from TPUART (TPUART -> hostcontroller) : 56 | // 3 types of data are transmitted from TPUART to the host : 57 | // 1) KNX bus data (transparently transmitted). Format = KNX control field byte + rest of the telegram 58 | // 2) Additional information from the TP-UART. Format = 1 data byte 59 | // 3) Immediate acknowledge services (BUS MONITOR mode only) 60 | #define TPUART_RESET_INDICATION 0x03 61 | #define TPUART_DATA_CONFIRM_SUCCESS 0x8B 62 | #define TPUART_DATA_CONFIRM_FAILED 0x0B 63 | #define TPUART_STATE_INDICATION 0x07 64 | #define TPUART_STATE_INDICATION_MASK 0x07 65 | #define KNX_CONTROL_FIELD_PATTERN_MASK B11010011 // 0xD3 66 | #define KNX_CONTROL_FIELD_VALID_PATTERN B10010000 // 0x90, Only Standard Frame Format "10" is handled 67 | #define KNX_PAYLOAD_LENGTH_MASK B00001111 // 0x0F, last 4 bits, only Standard Frame is supported 68 | 69 | 70 | // Mask for STATE INDICATION service 71 | #define TPUART_STATE_INDICATION_SLAVE_COLLISION_MASK 0x80 72 | #define TPUART_STATE_INDICATION_RECEIVE_ERROR_MASK 0x40 73 | #define TPUART_STATE_INDICATION_TRANSMIT_ERROR_MASK 0x20 74 | #define TPUART_STATE_INDICATION_PROTOCOL_ERROR_MASK 0x10 75 | #define TPUART_STATE_INDICATION_TEMP_WARNING_MASK 0x08 76 | 77 | // Time out/EOP by telegram recption (us) 78 | #ifdef ESP32 79 | // ESP32 more time, maybe will be fixed in future 80 | #define KNX_RECEPTION_TIMEOUT 30000 81 | #else 82 | // all other MCU are fine with 2000us 83 | #define KNX_RECEPTION_TIMEOUT 2000 84 | #endif 85 | 86 | // Definition of the TP-UART working modes 87 | enum KnxTpUartMode { NORMAL, 88 | BUS_MONITOR }; 89 | 90 | // Definition of the TP-UART events sent to the application layer 91 | enum KnxTpUartEvent { 92 | TPUART_EVENT_RESET = 0, // 0: reset received from the TPUART device 93 | TPUART_EVENT_RECEIVED_KNX_TELEGRAM = 1, // 1: a new addressed KNX Telegram has been received 94 | TPUART_EVENT_KNX_TELEGRAM_RECEPTION_ERROR = 2, // 2: a new addressed KNX telegram reception failed 95 | TPUART_EVENT_STATE_INDICATION = 3 // 3: new TPUART state indication received 96 | }; 97 | 98 | // Typedef for events callback function 99 | typedef void (*EventCallbackFctPtr) (KnxTpUartEvent); 100 | 101 | // --- Definitions for the RECEPTION part ---- 102 | // RX states 103 | enum TpUartRxState { 104 | RX_RESET = 0, // The RX part is awaiting reset execution 105 | RX_STOPPED = 1, // TPUART reset event received, RX activity is stopped 106 | RX_INIT = 2, // The RX part is awaiting init execution 107 | RX_IDLE_WAITING_FOR_CTRL_FIELD = 3, // Idle, no reception ongoing 108 | RX_KNX_TELEGRAM_RECEPTION_STARTED = 4, // Telegram reception started (address evaluation not done yet) 109 | RX_KNX_TELEGRAM_RECEPTION_ADDRESSED = 5, // Addressed telegram reception ongoing 110 | RX_KNX_TELEGRAM_RECEPTION_LENGTH_INVALID = 6, // The telegram being received is too long 111 | RX_KNX_TELEGRAM_RECEPTION_NOT_ADDRESSED = 7 // Tegram reception ongoing but not addressed 112 | }; 113 | 114 | typedef struct AddressedComObjects { 115 | byte size; // total size of list, incl. empty cells 116 | byte items; // size if items in list 117 | byte* list; // the list/array if indizes of addressed comcobjects 118 | } AddressedComObjects; 119 | 120 | typedef struct TpUartRx { 121 | TpUartRxState state; // Current TPUART RX state 122 | KnxTelegram receivedTelegram; // Where each received telegram is stored (the content is overwritten on each telegram reception) 123 | // A TPUART_EVENT_RECEIVED_KNX_TELEGRAM event notifies each content change 124 | } TpUartRx; 125 | 126 | // --- Definitions for the TRANSMISSION part ---- 127 | // Transmission states 128 | enum TpUartTxState { 129 | TX_RESET = 0, // The TX part is awaiting reset execution 130 | TX_STOPPED, // TPUART reset event received, TX activity is stopped 131 | TX_INIT, // The TX part is awaiting init execution 132 | TX_IDLE, // Idle, no transmission ongoing 133 | TX_TELEGRAM_SENDING_ONGOING, // KNX telegram transmission ongoing 134 | TX_WAITING_ACK // Telegram transmitted, waiting for ACK/NACK 135 | }; 136 | 137 | // Acknowledge values following a telegram sending 138 | enum TpUartTxAck { 139 | ACK_RESPONSE = 0, // TPUART received an ACK following telegram sending 140 | NACK_RESPONSE, // TPUART received a NACK following telegram sending (1+3 attempts by default) 141 | NO_ANSWER_TIMEOUT, // No answer (Data_Confirm) received from the TPUART 142 | TPUART_RESET_RESPONSE // TPUART RESET before we get any ACK 143 | }; 144 | 145 | // Typedef for TX acknowledge callback function 146 | typedef void (*AckCallbackFctPtr) (TpUartTxAck); 147 | 148 | typedef struct TpUartTx { 149 | TpUartTxState state; // Current TPUART TX state 150 | KnxTelegram *sentTelegram; // Telegram being sent 151 | AckCallbackFctPtr ackFctPtr; // Pointer to callback function for TX ack 152 | byte nbRemainingBytes; // Nb of bytes remaining to be transmitted 153 | byte txByteIndex; // Index of the byte to be sent 154 | } TpUartTx; 155 | 156 | 157 | // --- Typdef for BUS MONITORING mode data ---- 158 | typedef struct MonitorData { 159 | boolean isEOP; // True if the data is an End Of Packet 160 | byte dataByte; // Last data retrieved on the bus (valid when isEOP is false) 161 | } MonitorData; 162 | 163 | class KnxTpUart { 164 | HardwareSerial& _serial; // Arduino HW serial port connected to the TPUART 165 | const word _physicalAddr; // Physical address set in the TP-UART 166 | const KnxTpUartMode _mode; // TpUart working Mode (Normal/Bus Monitor) 167 | TpUartRx _rx; // Reception structure 168 | TpUartTx _tx; // Transmission structure 169 | EventCallbackFctPtr _evtCallbackFct; // Pointer to the EVENTS callback function 170 | KnxComObject *_comObjectsList; // Attached list of com objects 171 | byte _assignedComObjectsNb; // Nb of assigned com objects 172 | byte _stateIndication; // Value of the last received state indication 173 | 174 | public: 175 | 176 | // Constructor / Destructor 177 | KnxTpUart(HardwareSerial& serial, word physicalAddr, KnxTpUartMode _mode); 178 | ~KnxTpUart(); 179 | 180 | // INLINED functions (see definitions later in this file) 181 | 182 | // Set EVENTs callback function 183 | // return KNX_TPUART_ERROR (255) if the parameter is NULL 184 | // return KNX_TPUART_ERROR_NOT_INIT_STATE (254) if the TPUART is not in Init state 185 | // else return OK 186 | // The function must be called prior to Init() execution 187 | byte setEvtCallback(EventCallbackFctPtr); 188 | 189 | // Set ACK callback function 190 | // return KNX_TPUART_ERROR (255) if the parameter is NULL 191 | // return KNX_TPUART_ERROR_NOT_INIT_STATE (254) if the TPUART is not in Init state 192 | // else return OK 193 | // The function must be called prior to Init() execution 194 | byte setAckCallback(AckCallbackFctPtr); 195 | 196 | // Get the value of the last received State Indication 197 | // NB : every state indication value change is notified by a "TPUART_EVENT_STATE_INDICATION" event 198 | byte getStateIndication(void) const; 199 | 200 | // Get the reference to the telegram received by the TPUART 201 | // NB : every received telegram content change is notified by a "TPUART_EVENT_RECEIVED_KNX_TELEGRAM" event 202 | KnxTelegram& getReceivedTelegram(void); 203 | 204 | // Get the index of the com object targeted by the last received telegram 205 | //byte GetTargetedComObjectIndex(void) const; 206 | AddressedComObjects getAddressedComObjects(void) const; 207 | 208 | // returns true if there is an activity ongoing (RX/TX) on the TPUART 209 | // false when there's no activity or when the tpuart is not initialized 210 | boolean isActive(void) const; 211 | 212 | // Functions NOT INLINED 213 | // Reset the Arduino UART port and the TPUART device 214 | // Return KNX_TPUART_ERROR in case of TPUART reset failure 215 | byte reset(void); 216 | 217 | // Attach a list of com objects 218 | // NB1 : only the objects with "communication" attribute are considered by the TPUART 219 | // NB2 : In case of objects with identical address, the object with highest index only is considered 220 | // return KNX_TPUART_ERROR_NOT_INIT_STATE (254) if the TPUART is not in Init state 221 | // The function must be called prior to Init() execution 222 | byte attachComObjectsList(KnxComObject KnxComObjectsList[], byte listSize); 223 | 224 | // Init 225 | // returns ERROR (255) if the TP-UART is not in INIT state, else returns OK (0) 226 | // Init must be called after every reset() execution 227 | byte init(void); 228 | 229 | // Send a KNX telegram 230 | // returns ERROR (255) if TX is not available or if the telegram is not valid, else returns OK (0) 231 | // NB : the source address is forced to TPUART physical address value 232 | byte sendTelegram(KnxTelegram& sentTelegram); 233 | 234 | // Reception task 235 | // This function shall be called periodically in order to allow a correct reception of the KNX bus data 236 | // Assuming the TPUART speed is configured to 19200 baud, a character (8 data + 1 start + 1 parity + 1 stop) 237 | // is transmitted in 0,58ms. 238 | // In order not to miss any End Of Packets (i.e. a gap from 2 to 2,5ms), the function shall be called at a max period of 0,5ms. 239 | // Typical calling period is 400 usec. 240 | void rxTask(void); 241 | 242 | // Transmission task 243 | // This function shall be called periodically in order to allow a correct transmission of the KNX bus data 244 | // Assuming the TP-Uart speed is configured to 19200 baud, a character (8 data + 1 start + 1 parity + 1 stop) 245 | // is transmitted in 0,58ms. 246 | // Sending one byte of a telegram consists in transmitting 2 characters (1,16ms) 247 | // Let's wait around 800us between each telegram piece sending so that the 64byte TX buffer remains almost empty. 248 | // Typical calling period is 800 usec. 249 | void txTask(void); 250 | 251 | // Get Bus monitoring data (BUS MONITORING mode) 252 | // The function returns true if a new data has been retrieved (data pointer in argument), else false 253 | // It shall be called periodically (max period of 0,5ms) in order to allow correct data reception 254 | // Typical calling period is 400 usec. 255 | boolean getMonitoringData(MonitorData&); 256 | 257 | private: 258 | 259 | AddressedComObjects _addressedComObjects; 260 | 261 | // Private NOT INLINED functions 262 | // Check if the target address points to an assigned com object (i.e. the target address equals a com object address) 263 | // if yes, then update index parameter with the index (in the list) of the targeted com object and return true 264 | // else return false 265 | boolean isAddressAssigned(word addr); 266 | }; 267 | 268 | 269 | // ----- Definition of the INLINED functions : ------------ 270 | 271 | inline byte KnxTpUart::setEvtCallback(EventCallbackFctPtr evtCallbackFct) 272 | { 273 | if (evtCallbackFct == NULL) return KNX_TPUART_ERROR; 274 | if ((_rx.state!=RX_INIT) || (_tx.state!=TX_INIT)) return KNX_TPUART_ERROR_NOT_INIT_STATE; 275 | _evtCallbackFct = evtCallbackFct; 276 | return KNX_TPUART_OK; 277 | } 278 | 279 | inline byte KnxTpUart::setAckCallback(AckCallbackFctPtr ackFctPtr) 280 | { 281 | if (ackFctPtr == NULL) return KNX_TPUART_ERROR; 282 | if ((_rx.state!=RX_INIT) || (_tx.state!=TX_INIT)) return KNX_TPUART_ERROR_NOT_INIT_STATE; 283 | _tx.ackFctPtr = ackFctPtr; 284 | return KNX_TPUART_OK; 285 | } 286 | 287 | inline byte KnxTpUart::getStateIndication(void) const { return _stateIndication; } 288 | 289 | inline KnxTelegram& KnxTpUart::getReceivedTelegram(void) 290 | { return _rx.receivedTelegram; } 291 | 292 | 293 | inline AddressedComObjects KnxTpUart::getAddressedComObjects(void) const 294 | { return _addressedComObjects; } 295 | 296 | 297 | inline boolean KnxTpUart::isActive(void) const 298 | { 299 | if ( _rx.state > RX_IDLE_WAITING_FOR_CTRL_FIELD) return true; // Rx activity 300 | if ( _tx.state > TX_IDLE) return true; // Tx activity 301 | return false; 302 | } 303 | 304 | 305 | 306 | 307 | 308 | 309 | #endif // KNXTPUART_H 310 | -------------------------------------------------------------------------------- /src/KnxDataPointTypes.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file KnxDataPointTypes.h 3 | * 4 | * @section author Author 5 | * 6 | * Written by Alexander Christian. 7 | * 8 | * @section license License 9 | * 10 | * Copyright (C) 2016 Alexander Christian . All rights 11 | * reserved. This file is part of KONNEKTING Device Library. 12 | * 13 | * The KONNEKTING Device Library is free software: you can redistribute 14 | * it and/or modify it under the terms of the GNU General Public License as 15 | * published by the Free Software Foundation, either version 3 of the License, 16 | * or (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program. If not, see . 25 | * 26 | */ 27 | 28 | /** 29 | * Definition of KNX Datapoints types 30 | * 31 | * @author Alexander Christian 32 | * @author Eugen Burkowski 33 | */ 34 | 35 | #ifndef KNXDATAPOINTTYPES_H 36 | #define KNXDATAPOINTTYPES_H 37 | 38 | // DPT arrays are stored in flash using PROG MEMORY 39 | #ifndef ESP8266 //ESP8266 does't need pgmspace.h 40 | #ifdef ESP32 41 | #include //ESP32 42 | #else 43 | #include //rest of the world 44 | #endif 45 | #endif 46 | 47 | 48 | /** 49 | * List of the DPT formats 50 | * A Character 51 | * A[n] String of n characters 52 | * B Boolean / Bit set 53 | * C Control 54 | * E Exponent 55 | * F Floating point value 56 | * M Mantissa 57 | * N eNumeration 58 | * r Reserved bit or field 59 | * S Sign 60 | * U Unsigned value 61 | * V 2's Complement signed value 62 | * Z8 Standardised Status/Command B8. Encoding as in DPT_StatusGen 63 | */ 64 | enum KnxDPTFormat { 65 | KNX_DPT_FORMAT_B1 = 0, 66 | KNX_DPT_FORMAT_B2, 67 | KNX_DPT_FORMAT_B1U3, 68 | KNX_DPT_FORMAT_A8, 69 | KNX_DPT_FORMAT_U8, 70 | KNX_DPT_FORMAT_V8, 71 | KNX_DPT_FORMAT_B5N3, 72 | KNX_DPT_FORMAT_U16, 73 | KNX_DPT_FORMAT_V16, 74 | KNX_DPT_FORMAT_F16, 75 | KNX_DPT_FORMAT_N3N5R2N6R2N6, 76 | KNX_DPT_FORMAT_R3N5R4N4R1U7, 77 | KNX_DPT_FORMAT_U32, 78 | KNX_DPT_FORMAT_V32, 79 | KNX_DPT_FORMAT_F32, 80 | KNX_DPT_FORMAT_U4U4U4U4U4U4B4N4, 81 | KNX_DPT_FORMAT_A112, 82 | KNX_DPT_FORMAT_R2U6, 83 | KNX_DPT_FORMAT_B1R1U6, 84 | KNX_DPT_FORMAT_U8R4U4R3U5U3U5R2U6B16, 85 | KNX_DPT_FORMAT_U8R4U4R3U5U3U5R2U6R2U6B16, 86 | KNX_DPT_FORMAT_N8, 87 | KNX_DPT_FORMAT_B8, 88 | KNX_DPT_FORMAT_B16, 89 | KNX_DPT_FORMAT_N2, 90 | KNX_DPT_FORMAT_AN, 91 | KNX_DPT_FORMAT_U4U4, 92 | KNX_DPT_FORMAT_R1B1U6, 93 | KNX_DPT_FORMAT_B32, 94 | KNX_DPT_FORMAT_V64, 95 | KNX_DPT_FORMAT_B24, 96 | KNX_DPT_FORMAT_N3, 97 | KNX_DPT_FORMAT_B1Z8, 98 | KNX_DPT_FORMAT_N8Z8, 99 | KNX_DPT_FORMAT_U8Z8, 100 | KNX_DPT_FORMAT_U16Z8, 101 | KNX_DPT_FORMAT_V8Z8, 102 | KNX_DPT_FORMAT_V16Z8, 103 | KNX_DPT_FORMAT_U16N8, 104 | KNX_DPT_FORMAT_U8B8, 105 | KNX_DPT_FORMAT_V16B8, 106 | KNX_DPT_FORMAT_V16B16, 107 | KNX_DPT_FORMAT_U8N8, 108 | KNX_DPT_FORMAT_V16V16V16, 109 | KNX_DPT_FORMAT_V16V16V16V16, 110 | KNX_DPT_FORMAT_V16U8B8, 111 | KNX_DPT_FORMAT_V16U8B16, 112 | KNX_DPT_FORMAT_U16U8N8N8P8, 113 | KNX_DPT_FORMAT_U5U5U16, 114 | KNX_DPT_FORMAT_V32Z8, 115 | KNX_DPT_FORMAT_U8N8N8N8B8B8, 116 | KNX_DPT_FORMAT_U16V16, 117 | KNX_DPT_FORMAT_N16U32, 118 | KNX_DPT_FORMAT_F16F16F16, 119 | KNX_DPT_FORMAT_V8N8N8, 120 | KNX_DPT_FORMAT_V16V16N8N8, 121 | KNX_DPT_FORMAT_U16U8, 122 | KNX_DPT_FORMAT_V32N8Z8, 123 | KNX_DPT_FORMAT_U16U32U8N8, 124 | KNX_DPT_FORMAT_A8A8A8A8, 125 | KNX_DPT_FORMAT_U8U8U8, 126 | KNX_DPT_FORMAT_B4U16U16U8, 127 | KNX_DPT_FORMAT_r12B4U8U8U8, 128 | KNX_DPT_FORMAT_A8A8 129 | }; 130 | 131 | /** 132 | * Definition of all available DPTs 133 | */ 134 | enum KnxDpt { 135 | KNX_DPT_1_000 = 0, // 1.000 B1 general bool 136 | KNX_DPT_1_001, // 1.001 B1 DPT_Switch 137 | KNX_DPT_1_002, // 1.002 B1 DPT_Bool 138 | KNX_DPT_1_003, // 1.003 B1 DPT_Enable 139 | KNX_DPT_1_004, // 1.004 B1 DPT_Ramp 140 | KNX_DPT_1_005, // 1.005 B1 DPT_Alarm 141 | KNX_DPT_1_006, // 1.006 B1 DPT_BinaryValue 142 | KNX_DPT_1_007, // 1.007 B1 DPT_Step 143 | KNX_DPT_1_008, // 1.008 B1 DPT_UpDown 144 | KNX_DPT_1_009, // 1.009 B1 DPT_OpenClose 145 | KNX_DPT_1_010, // 1.010 B1 DPT_Start 146 | KNX_DPT_1_011, // 1.011 B1 DPT_State 147 | KNX_DPT_1_012, // 1.012 B1 DPT_Invert 148 | KNX_DPT_1_013, // 1.013 B1 DPT_DimSendStyle 149 | KNX_DPT_1_014, // 1.014 B1 DPT_InputSource 150 | KNX_DPT_1_015, // 1.015 B1 DPT_Reset 151 | KNX_DPT_1_016, // 1.016 B1 DPT_Ack 152 | KNX_DPT_1_017, // 1.017 B1 DPT_Trigger 153 | KNX_DPT_1_018, // 1.018 B1 DPT_Occupancy 154 | KNX_DPT_1_019, // 1.019 B1 DPT_Window_Door 155 | KNX_DPT_1_021, // 1.021 B1 DPT_LogicalFunction 156 | KNX_DPT_1_022, // 1.022 B1 DPT_Scene_AB 157 | KNX_DPT_1_023, // 1.023 B1 DPT_ShutterBlinds_Mode 158 | KNX_DPT_1_100, // 1.100 B1 DPT_Heat/Cool 159 | KNX_DPT_2_001, // 2.001 B2 DPT_Switch_Control 160 | KNX_DPT_2_002, // 2.002 B2 DPT_Bool_Control 161 | KNX_DPT_2_003, // 2.003 B2 DPT_Enable_Control 162 | KNX_DPT_2_004, // 2.004 B2 DPT_Ramp_Control 163 | KNX_DPT_2_005, // 2.005 B2 DPT_Alarm_Control 164 | KNX_DPT_2_006, // 2.006 B2 DPT_BinaryValue_Control 165 | KNX_DPT_2_007, // 2.007 B2 DPT_Step_Control 166 | KNX_DPT_2_008, // 2.008 B2 DPT_Direction1_Control 167 | KNX_DPT_2_009, // 2.009 B2 DPT_Direction2_Control 168 | KNX_DPT_2_010, // 2.010 B2 DPT_Start_Control 169 | KNX_DPT_2_011, // 2.011 B2 DPT_State_Control 170 | KNX_DPT_2_012, // 2.012 B2 DPT_Invert_Control 171 | KNX_DPT_3_007, // 3.007 B1U3 DPT_Control_Dimming 172 | KNX_DPT_3_008, // 3.008 B1U3 DPT_Control_Blinds 173 | KNX_DPT_4_001, // 4.001 A8 DPT_Char_ASCII 174 | KNX_DPT_4_002, // 4.002 A8 DPT_Char_8859_1 175 | KNX_DPT_5_000, // 5.000 U8 general byte 176 | KNX_DPT_5_001, // 5.001 U8 DPT_Scaling 177 | KNX_DPT_5_003, // 5.003 U8 DPT_Angle 178 | KNX_DPT_5_004, // 5.004 U8 DPT_Percent_U8 179 | KNX_DPT_5_005, // 5.005 U8 DPT_DecimalFactor 180 | KNX_DPT_5_006, // 5.006 U8 DPT_Tariff 181 | KNX_DPT_5_010, // 5.010 U8 DPT_Value_1_Ucount 182 | KNX_DPT_6_001, // 6.001 V8 DPT_Percent_V8 183 | KNX_DPT_6_010, // 6.010 V8 DPT_Value_1_Count 184 | KNX_DPT_6_020, // 6.020 B5N3 DPT_Status_Mode3 185 | KNX_DPT_7_000, // 7.001 U16 general unsigned integer 186 | KNX_DPT_7_001, // 7.001 U16 DPT_Value_2_Ucount 187 | KNX_DPT_7_002, // 7.002 U16 DPT_TimePeriodMsec 188 | KNX_DPT_7_003, // 7.003 U16 DPT_TimePeriod10MSec 189 | KNX_DPT_7_004, // 7.004 U16 DPT_TimePeriod100MSec 190 | KNX_DPT_7_005, // 7.005 U16 DPT_TimePeriodSec 191 | KNX_DPT_7_006, // 7.006 U16 DPT_TimePeriodMin 192 | KNX_DPT_7_007, // 7.007 U16 DPT_TimePeriodHrs 193 | KNX_DPT_7_010, // 7.010 U16 DPT_PropDataType 194 | KNX_DPT_7_011, // 7.011 U16 DPT_Length_mm 195 | KNX_DPT_7_012, // 7.012 U16 DPT_UElCurrentmA 196 | KNX_DPT_7_013, // 7.013 U16 DPT_Brightness 197 | KNX_DPT_7_600, // 7.600 U16 DPT_Colour_Temperature 198 | KNX_DPT_8_000, // 8.000 V16 general integer 199 | KNX_DPT_8_001, // 8.001 V16 DPT_Value_2_Count 200 | KNX_DPT_8_002, // 8.002 V16 DPT_DeltaTimeMsec 201 | KNX_DPT_8_003, // 8.003 V16 DPT_DeltaTime10MSec 202 | KNX_DPT_8_004, // 8.004 V16 DPT_DeltaTime100MSec 203 | KNX_DPT_8_005, // 8.005 V16 DPT_DeltaTimeSec 204 | KNX_DPT_8_006, // 8.006 V16 DPT_DeltaTimeMin 205 | KNX_DPT_8_007, // 8.007 V16 DPT_DeltaTimeHrs 206 | KNX_DPT_8_010, // 8.010 V16 DPT_Percent_V16 207 | KNX_DPT_8_011, // 8.011 V16 DPT_Rotation_Angle 208 | KNX_DPT_9_000, // 9.000 F16 general float 209 | KNX_DPT_9_001, // 9.001 F16 DPT_Value_Temp 210 | KNX_DPT_9_002, // 9.002 F16 DPT_Value_Tempd 211 | KNX_DPT_9_003, // 9.003 F16 DPT_Value_Tempa 212 | KNX_DPT_9_004, // 9.004 F16 DPT_Value_Lux 213 | KNX_DPT_9_005, // 9.005 F16 DPT_Value_Wsp 214 | KNX_DPT_9_006, // 9.006 F16 DPT_Value_Pres 215 | KNX_DPT_9_007, // 9.007 F16 DPT_Value_Humidity 216 | KNX_DPT_9_008, // 9.008 F16 DPT_Value_AirQuality 217 | KNX_DPT_9_010, // 9.010 F16 DPT_Value_Time1 218 | KNX_DPT_9_011, // 9.011 F16 DPT_Value_Time2 219 | KNX_DPT_9_020, // 9.020 F16 DPT_Value_Volt 220 | KNX_DPT_9_021, // 9.021 F16 DPT_Value_Curr 221 | KNX_DPT_9_022, // 9.022 F16 DPT_PowerDensity 222 | KNX_DPT_9_023, // 9.023 F16 DPT_KelvinPerPercent 223 | KNX_DPT_9_024, // 9.024 F16 DPT_Power 224 | KNX_DPT_9_025, // 9.025 F16 DPT_Value_Volume_Flow 225 | KNX_DPT_9_026, // 9.026 F16 DPT_Rain_Amount 226 | KNX_DPT_9_027, // 9.027 F16 DPT_Value_Temp_F 227 | KNX_DPT_9_028, // 9.028 F16 DPT_Value_Wsp_kmh 228 | KNX_DPT_9_029, // 9.029 F16 DPT_Value_Abs_Humidity 229 | KNX_DPT_10_001, // 10.001 N3N5r2N6r2N6 DPT_TimeOfDay 230 | KNX_DPT_11_001, // 11.001 r3N5r4N4r1U7 DPT_Date 231 | KNX_DPT_12_000, // 12.000 U32 general unsigned long 232 | KNX_DPT_12_001, // 12.001 U32 DPT_Value_4_Ucount 233 | KNX_DPT_13_000, // 13.000 V32 general long 234 | KNX_DPT_13_001, // 13.001 V32 DPT_Value_4_Count 235 | KNX_DPT_13_010, // 13.010 V32 DPT_ActiveEnergy 236 | KNX_DPT_13_011, // 13.011 V32 DPT_ApparantEnergy 237 | KNX_DPT_13_012, // 13.012 V32 DPT_ReactiveEnergy 238 | KNX_DPT_13_013, // 13.013 V32 DPT_ActiveEnergy_kWh 239 | KNX_DPT_13_014, // 13.014 V32 DPT_ApparantEnergy_kVAh 240 | KNX_DPT_13_015, // 13.015 V32 DPT_ReactiveEnergy_kVARh 241 | KNX_DPT_13_100, // 13.100 V32 DPT_LongDeltaTimeSec 242 | KNX_DPT_14_000, // 14.000 F32 DPT_Value_Acceleration 243 | KNX_DPT_14_001, // 14.001 F32 DPT_Value_Acceleration_Angular 244 | KNX_DPT_14_002, // 14.002 F32 DPT_Value_Activation_Energy 245 | KNX_DPT_14_003, // 14.003 F32 DPT_Value_Activity 246 | KNX_DPT_14_004, // 14.004 F32 DPT_Value_Mol 247 | KNX_DPT_14_005, // 14.005 F32 DPT_Value_Amplitude 248 | KNX_DPT_14_006, // 14.006 F32 DPT_Value_AngleRad 249 | KNX_DPT_14_007, // 14.007 F32 DPT_Value_AngleDeg 250 | KNX_DPT_16_000, // 16.000 A112 DPT_String_ASCII 251 | KNX_DPT_16_001, // 16.001 A112 DPT_String_8859_1 252 | KNX_DPT_17_001, // 17.001 r2U6 DPT_SceneNumber 253 | KNX_DPT_18_001, // 18.001 B1r1U6 DPT_SceneControl 254 | KNX_DPT_19_001, // 19.001 U8R4U4R3U5U3U5R2U6R2U6B16 DPT_DateTime 255 | KNX_DPT_232_600,// 232.600 U8U8U8 DPT_Colour_RGB 256 | KNX_DPT_242_600,// 242.600 B4U16U16U8 DPT_Colour_xyY 257 | KNX_DPT_251_600,// 251.600 r12B4U8U8U8 DPT_Colour_RGBW 258 | KNX_DPT_60000_60000// 60000.60000 A112 DPT_KONNEKTING_PROGRAM 259 | }; 260 | 261 | /** 262 | * Mapping-Table: 263 | * KnxDptFormat -> it's length in bits 264 | */ 265 | const byte KnxDptFormatToLength[] PROGMEM = { 266 | 1 , // KNX_DPT_FORMAT_B1 = 0, 267 | 2 , // KNX_DPT_FORMAT_B2, 268 | 4 , // KNX_DPT_FORMAT_B1U3 269 | 8 , // KNX_DPT_FORMAT_A8, 270 | 8 , // KNX_DPT_FORMAT_U8, 271 | 8 , // KNX_DPT_FORMAT_V8, 272 | 8 , // KNX_DPT_FORMAT_B5N3, 273 | 16, // KNX_DPT_FORMAT_U16, 274 | 16, // KNX_DPT_FORMAT_V16, 275 | 16, // KNX_DPT_FORMAT_F16, 276 | 24, // KNX_DPT_FORMAT_N3N5R2N6R2N6, 277 | 24, // KNX_DPT_FORMAT_R3N5R4N4R1U7, 278 | 32, // KNX_DPT_FORMAT_U32, 279 | 32, // KNX_DPT_FORMAT_V32, 280 | 32, // KNX_DPT_FORMAT_F32, 281 | 32, // KNX_DPT_FORMAT_U4U4U4U4U4U4B4N4, 282 | 112, // KNX_DPT_FORMAT_A112, 283 | 8 , // KNX_DPT_FORMAT_R2U6, 284 | 8 , // KNX_DPT_FORMAT_B1R1U6, 285 | 56, // KNX_DPT_FORMAT_U8R4U4R3U5U3U5R2U6B16, 286 | 64, // KNX_DPT_FORMAT_U8R4U4R3U5U3U5R2U6R2U6B16, 287 | 8 , // KNX_DPT_FORMAT_N8, 288 | 8 , // KNX_DPT_FORMAT_B8, 289 | 16, // KNX_DPT_FORMAT_B16, 290 | 2 , // KNX_DPT_FORMAT_N2, 291 | 112, // KNX_DPT_FORMAT_AN, 292 | 8 , // KNX_DPT_FORMAT_U4U4, 293 | 8 , // KNX_DPT_FORMAT_R1B1U6, 294 | 32, // KNX_DPT_FORMAT_B32, 295 | 64, // KNX_DPT_FORMAT_V64, 296 | 24, // KNX_DPT_FORMAT_B24, 297 | 3 , // KNX_DPT_FORMAT_N3, 298 | 2 , // KNX_DPT_FORMAT_B1Z8, 299 | 16, // KNX_DPT_FORMAT_N8Z8, 300 | 16, // KNX_DPT_FORMAT_U8Z8, 301 | 24, // KNX_DPT_FORMAT_U16Z8, 302 | 16, // KNX_DPT_FORMAT_V8Z8, 303 | 24, // KNX_DPT_FORMAT_V16Z8, 304 | 24, // KNX_DPT_FORMAT_U16N8, 305 | 16, // KNX_DPT_FORMAT_U8B8, 306 | 24, // KNX_DPT_FORMAT_V16B8, 307 | 32, // KNX_DPT_FORMAT_V16B16, 308 | 16, // KNX_DPT_FORMAT_U8N8, 309 | 48, // KNX_DPT_FORMAT_V16V16V16, 310 | 64, // KNX_DPT_FORMAT_V16V16V16V16, 311 | 32, // KNX_DPT_FORMAT_V16U8B8, 312 | 40, // KNX_DPT_FORMAT_V16U8B16, 313 | 48, // KNX_DPT_FORMAT_U16U8N8N8P8, 314 | 16, // KNX_DPT_FORMAT_U5U5U6, 315 | 40, // KNX_DPT_FORMAT_V32Z8, 316 | 48, // KNX_DPT_FORMAT_U8N8N8N8B8B8, 317 | 32, // KNX_DPT_FORMAT_U16V16, 318 | 48, // KNX_DPT_FORMAT_N16U32, 319 | 48, // KNX_DPT_FORMAT_F16F16F16, 320 | 24, // KNX_DPT_FORMAT_V8N8N8, 321 | 48, // KNX_DPT_FORMAT_V16V16N8N8, 322 | 24, // KNX_DPT_FORMAT_U16U8, 323 | 48, // KNX_DPT_FORMAT_V32N8Z8, 324 | 64, // KNX_DPT_FORMAT_U16U32U8N8, 325 | 24, // KNX_DPT_FORMAT_A8A8A8A8, 326 | 24, // KNX_DPT_FORMAT_U8U8U8, 327 | 48, // KNX_DPT_FORMAT_B4U16U16U8, 328 | 48, // KNX_DPT_FORMAT_r12B4U8U8U8, 329 | 16 // KNX_DPT_FORMAT_A8A8 330 | }; 331 | 332 | 333 | /** 334 | * Mapping-Table: 335 | * KnxDpt -> KNX DPT Format 336 | */ 337 | const byte KnxDptToFormat[] PROGMEM = { 338 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_000, // 1.000 B1 general bool 339 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_001, // 1.001 B1 DPT_Switch 340 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_002, // 1.002 B1 DPT_Bool 341 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_003, // 1.003 B1 DPT_Enable 342 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_004, // 1.004 B1 DPT_Ramp 343 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_005, // 1.005 B1 DPT_Alarm 344 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_006, // 1.006 B1 DPT_BinaryValue 345 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_007, // 1.007 B1 DPT_Step 346 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_008, // 1.008 B1 DPT_UpDown 347 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_009, // 1.009 B1 DPT_OpenClose 348 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_010, // 1.010 B1 DPT_Start 349 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_011, // 1.011 B1 DPT_State 350 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_012, // 1.012 B1 DPT_Invert 351 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_013, // 1.013 B1 DPT_DimSendStyle 352 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_014, // 1.014 B1 DPT_InputSource 353 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_015, // 1.015 B1 DPT_Reset 354 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_016, // 1.016 B1 DPT_Ack 355 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_017, // 1.017 B1 DPT_Trigger 356 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_018, // 1.018 B1 DPT_Occupancy 357 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_019, // 1.019 B1 DPT_Window_Door 358 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_021, // 1.021 B1 DPT_LogicalFunction 359 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_022, // 1.022 B1 DPT_Scene_AB 360 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_023, // 1.023 B1 DPT_ShutterBlinds_Mode 361 | KNX_DPT_FORMAT_B1, // KNX_DPT_1_100, // 1.100 B1 DPT_Heat/Cool 362 | KNX_DPT_FORMAT_B2, // KNX_DPT_2_001, // 2.001 B2 DPT_Switch_Control 363 | KNX_DPT_FORMAT_B2, // KNX_DPT_2_002, // 2.002 B2 DPT_Bool_Control 364 | KNX_DPT_FORMAT_B2, // KNX_DPT_2_003, // 2.003 B2 DPT_Enable_Control 365 | KNX_DPT_FORMAT_B2, // KNX_DPT_2_004, // 2.004 B2 DPT_Ramp_Control 366 | KNX_DPT_FORMAT_B2, // KNX_DPT_2_005, // 2.005 B2 DPT_Alarm_Control 367 | KNX_DPT_FORMAT_B2, // KNX_DPT_2_006, // 2.006 B2 DPT_BinaryValue_Control 368 | KNX_DPT_FORMAT_B2, // KNX_DPT_2_007, // 2.007 B2 DPT_Step_Control 369 | KNX_DPT_FORMAT_B2, // KNX_DPT_2_008, // 2.008 B2 DPT_Direction1_Control 370 | KNX_DPT_FORMAT_B2, // KNX_DPT_2_009, // 2.009 B2 DPT_Direction2_Control 371 | KNX_DPT_FORMAT_B2, // KNX_DPT_2_010, // 2.010 B2 DPT_Start_Control 372 | KNX_DPT_FORMAT_B2, // KNX_DPT_2_011, // 2.011 B2 DPT_State_Control 373 | KNX_DPT_FORMAT_B2, // KNX_DPT_2_012, // 2.012 B2 DPT_Invert_Control 374 | KNX_DPT_FORMAT_B1U3, // KNX_DPT_3_007, // 3.007 B1U3 DPT_Control_Dimming 375 | KNX_DPT_FORMAT_B1U3, // KNX_DPT_3_008, // 3.008 B1U3 DPT_Control_Blinds 376 | KNX_DPT_FORMAT_A8, // KNX_DPT_4_001, // 4.001 A8 DPT_Char_ASCII 377 | KNX_DPT_FORMAT_A8, // KNX_DPT_4_002, // 4.002 A8 DPT_Char_8859_1 378 | KNX_DPT_FORMAT_U8, // KNX_DPT_5_000, // 5.000 U8 general byte 379 | KNX_DPT_FORMAT_U8, // KNX_DPT_5_001, // 5.001 U8 DPT_Scaling 380 | KNX_DPT_FORMAT_U8, // KNX_DPT_5_003, // 5.003 U8 DPT_Angle 381 | KNX_DPT_FORMAT_U8, // KNX_DPT_5_004, // 5.004 U8 DPT_Percent_U8 382 | KNX_DPT_FORMAT_U8, // KNX_DPT_5_005, // 5.005 U8 DPT_DecimalFactor 383 | KNX_DPT_FORMAT_U8, // KNX_DPT_5_006, // 5.006 U8 DPT_Tariff 384 | KNX_DPT_FORMAT_U8, // KNX_DPT_5_010, // 5.010 U8 DPT_Value_1_Ucount 385 | KNX_DPT_FORMAT_V8, // KNX_DPT_6_001, // 6.001 V8 DPT_Percent_V8 386 | KNX_DPT_FORMAT_V8, // KNX_DPT_6_010, // 6.010 V8 DPT_Value_1_Count 387 | KNX_DPT_FORMAT_B5N3, // KNX_DPT_6_020, // 6.020 B5N3 DPT_Status_Mode3 388 | KNX_DPT_FORMAT_U16, // KNX_DPT_7_000, // 7.000 U16 general unsigned integer 389 | KNX_DPT_FORMAT_U16, // KNX_DPT_7_001, // 7.001 U16 DPT_Value_2_Ucount 390 | KNX_DPT_FORMAT_U16, // KNX_DPT_7_002, // 7.002 U16 DPT_TimePeriodMsec 391 | KNX_DPT_FORMAT_U16, // KNX_DPT_7_003, // 7.003 U16 DPT_TimePeriod10MSec 392 | KNX_DPT_FORMAT_U16, // KNX_DPT_7_004, // 7.004 U16 DPT_TimePeriod100MSec 393 | KNX_DPT_FORMAT_U16, // KNX_DPT_7_005, // 7.005 U16 DPT_TimePeriodSec 394 | KNX_DPT_FORMAT_U16, // KNX_DPT_7_006, // 7.006 U16 DPT_TimePeriodMin 395 | KNX_DPT_FORMAT_U16, // KNX_DPT_7_007, // 7.007 U16 DPT_TimePeriodHrs 396 | KNX_DPT_FORMAT_U16, // KNX_DPT_7_010, // 7.010 U16 DPT_PropDataType 397 | KNX_DPT_FORMAT_U16, // KNX_DPT_7_011, // 7.011 U16 DPT_Length_mm 398 | KNX_DPT_FORMAT_U16, // KNX_DPT_7_012, // 7.012 U16 DPT_UElCurrentmA 399 | KNX_DPT_FORMAT_U16, // KNX_DPT_7_013, // 7.013 U16 DPT_Brightness 400 | KNX_DPT_FORMAT_U16, // KNX_DPT_7_600, // 7.600 U16 DPT_Colour_Temperature 401 | KNX_DPT_FORMAT_V16, // KNX_DPT_8_000, // 8.000 V16 general integer 402 | KNX_DPT_FORMAT_V16, // KNX_DPT_8_001, // 8.001 V16 DPT_Value_2_Count 403 | KNX_DPT_FORMAT_V16, // KNX_DPT_8_002, // 8.002 V16 DPT_DeltaTimeMsec 404 | KNX_DPT_FORMAT_V16, // KNX_DPT_8_003, // 8.003 V16 DPT_DeltaTime10MSec 405 | KNX_DPT_FORMAT_V16, // KNX_DPT_8_004, // 8.004 V16 DPT_DeltaTime100MSec 406 | KNX_DPT_FORMAT_V16, // KNX_DPT_8_005, // 8.005 V16 DPT_DeltaTimeSec 407 | KNX_DPT_FORMAT_V16, // KNX_DPT_8_006, // 8.006 V16 DPT_DeltaTimeMin 408 | KNX_DPT_FORMAT_V16, // KNX_DPT_8_007, // 8.007 V16 DPT_DeltaTimeHrs 409 | KNX_DPT_FORMAT_V16, // KNX_DPT_8_010, // 8.010 V16 DPT_Percent_V16 410 | KNX_DPT_FORMAT_V16, // KNX_DPT_8_011, // 8.011 V16 DPT_Rotation_Angle 411 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_000, // 9.000 F16 general float 412 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_001, // 9.001 F16 DPT_Value_Temp 413 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_002, // 9.002 F16 DPT_Value_Tempd 414 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_003, // 9.003 F16 DPT_Value_Tempa 415 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_004, // 9.004 F16 DPT_Value_Lux 416 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_005, // 9.005 F16 DPT_Value_Wsp 417 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_006, // 9.006 F16 DPT_Value_Pres 418 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_007, // 9.007 F16 DPT_Value_Humidity 419 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_008, // 9.008 F16 DPT_Value_AirQuality 420 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_010, // 9.010 F16 DPT_Value_Time1 421 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_011, // 9.011 F16 DPT_Value_Time2 422 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_020, // 9.020 F16 DPT_Value_Volt 423 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_021, // 9.021 F16 DPT_Value_Curr 424 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_022, // 9.022 F16 DPT_PowerDensity 425 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_023, // 9.023 F16 DPT_KelvinPerPercent 426 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_024, // 9.024 F16 DPT_Power 427 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_025, // 9.025 F16 DPT_Value_Volume_Flow 428 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_026, // 9.026 F16 DPT_Rain_Amount 429 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_027, // 9.027 F16 DPT_Value_Temp_F 430 | KNX_DPT_FORMAT_F16, // KNX_DPT_9_028, // 9.028 F16 DPT_Value_Wsp_kmh 431 | KNX_DPT_FORMAT_F16, // KNX_DPT_9.029, // 9.029 F16 DPT_Value_Abs_Humidity 432 | KNX_DPT_FORMAT_N3N5R2N6R2N6, // KNX_DPT_10_001, // 10.001 N3N5r2N6r2N6 DPT_TimeOfDay 433 | KNX_DPT_FORMAT_R3N5R4N4R1U7, // KNX_DPT_11_001, // 11.001 r3N5r4N4r1U7 DPT_Date 434 | KNX_DPT_FORMAT_U32, // KNX_DPT_12_000, // 12.000 U32 general unsigned long 435 | KNX_DPT_FORMAT_U32, // KNX_DPT_12_001, // 12.001 U32 DPT_Value_4_Ucount 436 | KNX_DPT_FORMAT_V32, // KNX_DPT_13_000, // 13.000 V32 general long 437 | KNX_DPT_FORMAT_V32, // KNX_DPT_13_001, // 13.001 V32 DPT_Value_4_Count 438 | KNX_DPT_FORMAT_V32, // KNX_DPT_13_010, // 13.010 V32 DPT_ActiveEnergy 439 | KNX_DPT_FORMAT_V32, // KNX_DPT_13_011, // 13.011 V32 DPT_ApparantEnergy 440 | KNX_DPT_FORMAT_V32, // KNX_DPT_13_012, // 13.012 V32 DPT_ReactiveEnergy 441 | KNX_DPT_FORMAT_V32, // KNX_DPT_13_013, // 13.013 V32 DPT_ActiveEnergy_kWh 442 | KNX_DPT_FORMAT_V32, // KNX_DPT_13_014, // 13.014 V32 DPT_ApparantEnergy_kVAh 443 | KNX_DPT_FORMAT_V32, // KNX_DPT_13_015, // 13.015 V32 DPT_ReactiveEnergy_kVARh 444 | KNX_DPT_FORMAT_V32, // KNX_DPT_13_100, // 13.100 V32 DPT_LongDeltaTimeSec 445 | KNX_DPT_FORMAT_F32, // KNX_DPT_14_000, // 14.000 F32 DPT_Value_Acceleration 446 | KNX_DPT_FORMAT_F32, // KNX_DPT_14_001, // 14.001 F32 DPT_Value_Acceleration_Angular 447 | KNX_DPT_FORMAT_F32, // KNX_DPT_14_002, // 14.002 F32 DPT_Value_Activation_Energy 448 | KNX_DPT_FORMAT_F32, // KNX_DPT_14_003, // 14.003 F32 DPT_Value_Activity 449 | KNX_DPT_FORMAT_F32, // KNX_DPT_14_004, // 14.004 F32 DPT_Value_Mol 450 | KNX_DPT_FORMAT_F32, // KNX_DPT_14_005, // 14.005 F32 DPT_Value_Amplitude 451 | KNX_DPT_FORMAT_F32, // KNX_DPT_14_006, // 14.006 F32 DPT_Value_AngleRad 452 | KNX_DPT_FORMAT_F32, // KNX_DPT_14_007, // 14.007 F32 DPT_Value_AngleDeg 453 | KNX_DPT_FORMAT_A112,// KNX_DPT_16_000, // 16.000 A112 DPT_String_ASCII 454 | KNX_DPT_FORMAT_A112,// KNX_DPT_16_001, // 16.001 A112 DPT_String_8859_1 455 | KNX_DPT_FORMAT_R2U6,// KNX_DPT_17_001, // 17.001 r2U6 DPT_SceneNumber 456 | KNX_DPT_FORMAT_B1R1U6,// KNX_DPT_18_001, // 18.001 B1r1U6 DPT_SceneControl 457 | KNX_DPT_FORMAT_U8R4U4R3U5U3U5R2U6R2U6B16, //KNX_DPT_19_001, // 19.001 U8R4U4R3U5U3U5R2U6R2U6B16 DPT_DateTime 458 | KNX_DPT_FORMAT_U8U8U8, //KNX_DPT_232_600,// 232.600 U8U8U8 DPT_Colour_RGB 459 | KNX_DPT_FORMAT_B4U16U16U8, //KNX_DPT_242_600,// 242.600 B4U16U16U8 DPT_Colour_xyY 460 | KNX_DPT_FORMAT_r12B4U8U8U8, //KNX_DPT_251_600,// 251.600 r12B4U8U8U8 DPT_Colour_RGBW 461 | KNX_DPT_FORMAT_A112 // KNX_DPT_60000_60000// 60000.60000 A112 DPT_KONNEKTING_PROGRAM 462 | }; 463 | 464 | #endif // KNXDATAPOINTTYPES_H 465 | -------------------------------------------------------------------------------- /src/KnxDevice.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file KnxDevice.cpp 3 | * 4 | * @section author Author 5 | * 6 | * Written by Alexander Christian. 7 | * 8 | * @section license License 9 | * 10 | * Copyright (C) 2016 Alexander Christian . All rights 11 | * reserved. This file is part of KONNEKTING Device Library. 12 | * 13 | * The KONNEKTING Device Library is free software: you can redistribute 14 | * it and/or modify it under the terms of the GNU General Public License as 15 | * published by the Free Software Foundation, either version 3 of the License, 16 | * or (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program. If not, see . 25 | * 26 | */ 27 | 28 | #include "KnxDevice.h" 29 | #include "KonnektingDevice.h" 30 | 31 | static inline word TimeDeltaWord(word now, word before) { 32 | return (word)(now - before); 33 | } 34 | 35 | // KnxDevice unique instance creation 36 | KnxDevice KnxDevice::Knx; 37 | KnxDevice& Knx = KnxDevice::Knx; 38 | 39 | // Constructor 40 | 41 | KnxDevice::KnxDevice() { 42 | _state = INIT; 43 | _tpuart = NULL; 44 | _txActionList = RingBuff(); 45 | _initCompleted = false; 46 | _initIndex = 0; 47 | _rxTelegram = NULL; 48 | 49 | _progComObj.setAddr(G_ADDR(15, 7, 255)); 50 | } 51 | 52 | int KnxDevice::getNumberOfComObjects() { 53 | return _numberOfComObjects; 54 | } 55 | 56 | /** 57 | * Start the KNX Device 58 | * return KNX_DEVICE_ERROR (255) if begin() failed 59 | * else return KNX_DEVICE_OK 60 | */ 61 | KnxDeviceStatus KnxDevice::begin(HardwareSerial& serial, word physicalAddr) { 62 | delete _tpuart; // always safe to delete null ptr 63 | _tpuart = new KnxTpUart(serial, physicalAddr, NORMAL); 64 | _rxTelegram = &_tpuart->getReceivedTelegram(); 65 | //delay(10000); // Workaround for init issue with bus-powered arduino 66 | // the issue is reproduced on one (faulty?) TPUART device only, so remove it for the moment. 67 | if (_tpuart->reset() != KNX_TPUART_OK) { 68 | delete (_tpuart); 69 | _tpuart = NULL; 70 | _rxTelegram = NULL; 71 | DEBUG_PRINTLN(F("Init Error!")); 72 | return KNX_DEVICE_INIT_ERROR; 73 | } 74 | _tpuart->attachComObjectsList(_comObjectsList, _numberOfComObjects); 75 | _tpuart->setEvtCallback(&KnxDevice::getTpUartEvents); 76 | _tpuart->setAckCallback(&KnxDevice::txTelegramAck); 77 | _tpuart->init(); 78 | _state = IDLE; 79 | DEBUG_PRINTLN(F("Init successful")); 80 | _lastInitTimeMillis = millis(); 81 | _lastRXTimeMicros = micros(); 82 | _lastTXTimeMicros = _lastRXTimeMicros; 83 | #if defined(KNXDEVICE_DEBUG_INFO) 84 | _nbOfInits = 0; 85 | #endif 86 | return KNX_DEVICE_OK; 87 | } 88 | 89 | // Stop the KNX Device 90 | void KnxDevice::end() { 91 | //TxAction action; 92 | DEBUG_PRINTLN(F("KnxDevice::end begin ...")); 93 | //while (_txActionList.pop(action)) 94 | //; // empty ring buffer 95 | // 96 | // ensure all telegrams are sent 97 | while (_txActionList.getItemCount()>0) { 98 | DEBUG_PRINTLN(F("KnxDevice::end working on open tasks: %d"), _txActionList.getItemCount()); 99 | task(); 100 | } 101 | _state = INIT; 102 | _initCompleted = false; 103 | _initIndex = 0; 104 | _rxTelegram = NULL; 105 | delete (_tpuart); 106 | _tpuart = NULL; 107 | DEBUG_PRINTLN(F("KnxDevice::end *done*")); 108 | } 109 | 110 | /** 111 | * KNX device execution task 112 | * This function call shall be placed in the "loop()" Arduino function 113 | */ 114 | void KnxDevice::task(void) { 115 | TxAction action; 116 | word nowTimeMillis, nowTimeMicros; 117 | 118 | //stay in task() if _tpuart.isActive() 119 | do { 120 | 121 | // STEP 1 : Initialize Com Objects having Init Read attribute 122 | if (!_initCompleted) { 123 | nowTimeMillis = millis(); 124 | // To avoid KNX bus overloading, we wait for 500 ms between each Init read request 125 | if (TimeDeltaWord(nowTimeMillis, _lastInitTimeMillis) > 500) { 126 | while ( 127 | (_initIndex < _numberOfComObjects) && 128 | (_comObjectsList[_initIndex].getValidity() || !_comObjectsList[_initIndex].isActive()) /* either valid (=init done or not required) or not-active required to jump to next index */ 129 | ) _initIndex++; 130 | 131 | if (_initIndex == _numberOfComObjects) { 132 | _initCompleted = true; // All the Com Object initialization have been performed 133 | } else { // Com Object to be initialised has been found 134 | // Add a READ request in the TX action list 135 | action.command = KNX_READ_REQUEST; 136 | action.index = _initIndex; 137 | _txActionList.append(action); 138 | _lastInitTimeMillis = millis(); // Update the timer 139 | } 140 | } 141 | } 142 | 143 | // STEP 2 : Get new received KNX messages from the TPUART 144 | // The TPUART RX task is executed every 400 us 145 | nowTimeMicros = micros(); 146 | if (TimeDeltaWord(nowTimeMicros, _lastRXTimeMicros) > 400) { 147 | _lastRXTimeMicros = nowTimeMicros; 148 | _tpuart->rxTask(); 149 | 150 | // TODO: check for rx_state in tpuart and call rxtask repeatedly until telegram is received?! 151 | } 152 | 153 | // STEP 3 : Send KNX messages following TX actions 154 | if (_state == IDLE) { 155 | if (_txActionList.pop(action)) { // Data to be transmitted 156 | 157 | //DEBUG_PRINTLN(F("Data to be transmitted index=%d"), action.index); 158 | KnxComObject* comObj = (action.index == 255 ? &_progComObj : &_comObjectsList[action.index]); 159 | 160 | //} 161 | 162 | switch (action.command) { 163 | 164 | case KNX_READ_REQUEST: // a read operation of a Com Object on the KNX network is required 165 | //_objectsList[action.index].CopyToTelegram(_txTelegram, KNX_COMMAND_VALUE_READ); 166 | comObj->copyAttributes(_txTelegram); 167 | _txTelegram.clearLongPayload(); 168 | _txTelegram.clearFirstPayloadByte(); // Is it required to have a clean payload ?? 169 | _txTelegram.setCommand(KNX_COMMAND_VALUE_READ); 170 | _txTelegram.updateChecksum(); 171 | _tpuart->sendTelegram(_txTelegram); 172 | _state = TX_ONGOING; 173 | break; 174 | 175 | case KNX_RESPONSE_REQUEST: // a response operation of a Com Object on the KNX network is required 176 | comObj->copyAttributes(_txTelegram); 177 | comObj->copyValue(_txTelegram); 178 | _txTelegram.setCommand(KNX_COMMAND_VALUE_RESPONSE); 179 | _txTelegram.updateChecksum(); 180 | _tpuart->sendTelegram(_txTelegram); 181 | _state = TX_ONGOING; 182 | break; 183 | 184 | case KNX_WRITE_REQUEST: // a write operation of a Com Object on the KNX network is required 185 | // update the com obj value 186 | //DEBUG_PRINTLN(F("KNX_WRITE_REQUEST index=%d"), action.index); 187 | 188 | 189 | if ((comObj->getLength()) <= 2) { 190 | //DEBUG_PRINTLN(F("len <= 2")); 191 | comObj->updateValue(action.byteValue); 192 | } else { 193 | //DEBUG_PRINTLN(F("len > 2")); 194 | comObj->updateValue(action.valuePtr); 195 | free(action.valuePtr); 196 | } 197 | // transmit the value through KNX network only if the Com Object has transmit attribute 198 | if ((comObj->getIndicator()) & KNX_COM_OBJ_T_INDICATOR) { 199 | //DEBUG_PRINTLN(F("set tx ongoing")); 200 | comObj->copyAttributes(_txTelegram); 201 | comObj->copyValue(_txTelegram); 202 | _txTelegram.setCommand(KNX_COMMAND_VALUE_WRITE); 203 | _txTelegram.updateChecksum(); 204 | _tpuart->sendTelegram(_txTelegram); 205 | _state = TX_ONGOING; 206 | } 207 | break; 208 | 209 | default: break; 210 | } 211 | } 212 | } 213 | 214 | // STEP 4 : LET THE TP-UART TRANSMIT KNX MESSAGES 215 | // The TPUART TX task is executed every 800 us 216 | nowTimeMicros = micros(); 217 | if (TimeDeltaWord(nowTimeMicros, _lastTXTimeMicros) > 800) { 218 | _lastTXTimeMicros = nowTimeMicros; 219 | _tpuart->txTask(); 220 | } 221 | } while (_tpuart->isActive()); 222 | } 223 | 224 | /** 225 | * Quick method to read a short (<=1 byte) com object 226 | * NB : The returned value will be hazardous in case of use with long objects 227 | * @param objectIndex 228 | * @retreturn 1-byte value of comobj 229 | */ 230 | byte KnxDevice::read(byte objectIndex) { 231 | // return _comObjectsList[objectIndex].getValue(); 232 | return (objectIndex == 255 ? _progComObj.getValue() : _comObjectsList[objectIndex].getValue()); 233 | } 234 | 235 | /** 236 | * Read an usual format com object 237 | * Supported DPT formats are short com object, U16, V16, U32, V32, F16 and F32 (not implemented yet) 238 | */ 239 | template 240 | KnxDeviceStatus KnxDevice::read(byte objectIndex, T& returnedValue) { 241 | KnxComObject* comObj = (objectIndex == 255 ? &_progComObj : &_comObjectsList[objectIndex]); 242 | // Short com object case 243 | if (comObj->getLength() <= 2) { 244 | returnedValue = (T)comObj->getValue(); 245 | return KNX_DEVICE_OK; 246 | } else // long object case, let's see if we are able to translate the DPT value 247 | { 248 | byte dptValue[14]; // define temporary DPT value with max length 249 | comObj->getValue(dptValue); 250 | return ConvertFromDpt(dptValue, returnedValue, pgm_read_byte(&KnxDptToFormat[comObj->getDptId()])); 251 | } 252 | } 253 | 254 | template KnxDeviceStatus KnxDevice::read(byte objectIndex, bool& returnedValue); 255 | template KnxDeviceStatus KnxDevice::read(byte objectIndex, byte& returnedValue); 256 | template KnxDeviceStatus KnxDevice::read(byte objectIndex, short& returnedValue); 257 | template KnxDeviceStatus KnxDevice::read(byte objectIndex, unsigned short& returnedValue); 258 | template KnxDeviceStatus KnxDevice::read(byte objectIndex, int& returnedValue); 259 | template KnxDeviceStatus KnxDevice::read(byte objectIndex, unsigned int& returnedValue); 260 | template KnxDeviceStatus KnxDevice::read(byte objectIndex, long& returnedValue); 261 | template KnxDeviceStatus KnxDevice::read(byte objectIndex, unsigned long& returnedValue); 262 | template KnxDeviceStatus KnxDevice::read(byte objectIndex, float& returnedValue); 263 | template KnxDeviceStatus KnxDevice::read(byte objectIndex, double& returnedValue); 264 | 265 | // Read any type of com object (DPT value provided as is) 266 | 267 | KnxDeviceStatus KnxDevice::read(byte objectIndex, byte returnedValue[]) { 268 | KnxComObject* comObj = (objectIndex == 255 ? &_progComObj : &_comObjectsList[objectIndex]); 269 | comObj->getValue(returnedValue); 270 | return KNX_DEVICE_OK; 271 | } 272 | 273 | /**************************************************************************/ 274 | /*! 275 | * @brief Update an usual format com object 276 | * Supported DPT types are short com object, U16, V16, U32, V32, F16 and F32 277 | * The Com Object value is updated locally 278 | * And a telegram is sent on the KNX bus if the com object has communication & transmit attributes 279 | * @param objectIndex 280 | * Comobject index 281 | * @param value 282 | * the new value 283 | * @return KnxDeviceStatus 284 | */ 285 | /**************************************************************************/ 286 | template 287 | KnxDeviceStatus KnxDevice::write(byte objectIndex, T value) { 288 | TxAction action; 289 | byte* destValue; 290 | //DEBUG_PRINTLN(F("KnxDevice::write 1")); 291 | KnxComObject* comObj = (objectIndex == 255 ? &_progComObj : &_comObjectsList[objectIndex]); 292 | if (!comObj->isActive()) { 293 | return KNX_DEVICE_COMOBJ_INACTIVE; 294 | } 295 | //DEBUG_PRINTLN(F("KnxDevice::write 2")); 296 | byte length = comObj->getLength(); 297 | 298 | //DEBUG_PRINTLN(F("KnxDevice::write 3")); 299 | if (length <= 2) { 300 | //DEBUG_PRINTLN(F("KnxDevice::write 4")); 301 | action.byteValue = (byte)value; // short object case 302 | } else { // long object case, let's try to translate value to the com object DPT 303 | //DEBUG_PRINTLN(F("KnxDevice::write 5")); 304 | destValue = (byte*)malloc(length - 1); // allocate the memory for DPT 305 | //DEBUG_PRINTLN(F("KnxDevice::write 6")); 306 | KnxDeviceStatus status = ConvertToDpt(value, destValue, pgm_read_byte(&KnxDptToFormat[comObj->getDptId()])); 307 | //DEBUG_PRINTLN(F("KnxDevice::write 7")); 308 | if (status) // translation error 309 | { 310 | free(destValue); 311 | //DEBUG_PRINTLN(F("KnxDevice::write 8")); 312 | return status; // we cannot convert, we stop here 313 | } else { 314 | action.valuePtr = destValue; 315 | //DEBUG_PRINTLN(F("KnxDevice::write 9")); 316 | } 317 | } 318 | // add WRITE action in the TX action queue 319 | action.command = KNX_WRITE_REQUEST; 320 | action.index = objectIndex; 321 | _txActionList.append(action); 322 | //DEBUG_PRINTLN(F("KnxDevice::write 10")); 323 | return KNX_DEVICE_OK; 324 | } 325 | 326 | template KnxDeviceStatus KnxDevice::write(byte objectIndex, bool value); 327 | template KnxDeviceStatus KnxDevice::write(byte objectIndex, byte value); 328 | template KnxDeviceStatus KnxDevice::write(byte objectIndex, short value); 329 | template KnxDeviceStatus KnxDevice::write(byte objectIndex, unsigned short value); 330 | template KnxDeviceStatus KnxDevice::write(byte objectIndex, int value); 331 | template KnxDeviceStatus KnxDevice::write(byte objectIndex, unsigned int value); 332 | template KnxDeviceStatus KnxDevice::write(byte objectIndex, long value); 333 | template KnxDeviceStatus KnxDevice::write(byte objectIndex, unsigned long value); 334 | template KnxDeviceStatus KnxDevice::write(byte objectIndex, float value); 335 | template KnxDeviceStatus KnxDevice::write(byte objectIndex, double value); 336 | 337 | /** 338 | * Update any type of com object (rough DPT value shall be provided) 339 | * The Com Object value is updated locally 340 | * And a telegram is sent on the KNX bus if the com object has communication & transmit attributes 341 | */ 342 | KnxDeviceStatus KnxDevice::write(byte objectIndex, byte valuePtr[]) { 343 | TxAction action; 344 | 345 | // get length of comobj for copying value into tx-action struct 346 | KnxComObject* comObj = (objectIndex == 255 ? &_progComObj : &_comObjectsList[objectIndex]); 347 | byte length = comObj->getLength(); 348 | 349 | // check we are in long object case 350 | if (length > 2) { 351 | // add WRITE action in the TX action queue 352 | action.command = KNX_WRITE_REQUEST; 353 | action.index = objectIndex; 354 | 355 | // allocate the memory for long value 356 | byte* dptValue = (byte*)malloc(length - 1); 357 | 358 | for (byte i = 0; i < length - 1; i++) { 359 | dptValue[i] = valuePtr[i]; // copy value 360 | } 361 | action.valuePtr = (byte*)dptValue; 362 | 363 | _txActionList.append(action); 364 | 365 | return KNX_DEVICE_OK; 366 | } 367 | return KNX_DEVICE_ERROR; 368 | } 369 | 370 | /** 371 | * Com Object KNX Bus Update request 372 | * Request the local object to be updated with the value from the bus 373 | * NB : the function is asynchroneous, the update completion is notified by the knxEvents() callback 374 | */ 375 | void KnxDevice::update(byte objectIndex) { 376 | TxAction action; 377 | action.command = KNX_READ_REQUEST; 378 | action.index = objectIndex; 379 | _txActionList.append(action); 380 | } 381 | 382 | /** 383 | * The function returns true if there is rx/tx activity ongoing, else false 384 | */ 385 | bool KnxDevice::isActive() const { 386 | if (_tpuart->isActive()) return true; // TPUART is active 387 | if (_state == TX_ONGOING) return true; // the Device is sending a request 388 | if (_txActionList.getItemCount()) return true; // there is at least one tx action in the queue 389 | return false; 390 | } 391 | 392 | KnxDeviceStatus KnxDevice::setComObjectAddress(byte index, word addr) { 393 | if (_state != INIT) return KNX_DEVICE_INIT_ERROR; 394 | if (index >= _numberOfComObjects) return KNX_DEVICE_INVALID_INDEX; 395 | _comObjectsList[index].setAddr(addr); 396 | return KNX_DEVICE_OK; 397 | } 398 | KnxDeviceStatus KnxDevice::setComObjectIndicator(byte index, byte indicator) { 399 | if (_state != INIT) return KNX_DEVICE_INIT_ERROR; 400 | if (index >= _numberOfComObjects) return KNX_DEVICE_INVALID_INDEX; 401 | _comObjectsList[index].setIndicator(indicator); 402 | return KNX_DEVICE_OK; 403 | } 404 | 405 | word KnxDevice::getComObjectAddress(byte index) { 406 | return _comObjectsList[index].getAddr(); 407 | } 408 | 409 | /** 410 | * Static getTpUartEvents() function called by the KnxTpUart layer (callback) 411 | */ 412 | void KnxDevice::getTpUartEvents(KnxTpUartEvent event) { 413 | TxAction action; 414 | byte targetedComObjIndex; // index of the Com Object targeted by the event 415 | //DEBUG_PRINTLN(F("KnxDevice::getTpUartEvents")); 416 | 417 | switch (event) { 418 | // Manage RECEIVED MESSAGES 419 | case TPUART_EVENT_RECEIVED_KNX_TELEGRAM: { 420 | Knx._state = IDLE; 421 | 422 | AddressedComObjects addressedComObjects = Knx._tpuart->getAddressedComObjects(); //.get(0, targetedComObjIndex); 423 | 424 | //DEBUG_PRINTLN(F(" KnxDevice::getTpUartEvents need to process %d comobjs."), addressedComObjects.items); 425 | 426 | // handle all addressed comobjs 427 | for (int i = 0; i < addressedComObjects.items; i++) { 428 | targetedComObjIndex = addressedComObjects.list[i]; 429 | 430 | KnxComObject* comObj = (targetedComObjIndex == 255 ? &Knx._progComObj : &_comObjectsList[targetedComObjIndex]); 431 | 432 | //DEBUG_PRINTLN(F(" KnxDevice::getTpUartEvents targetedComObjIndex=%d command=%d"), targetedComObjIndex, Knx._rxTelegram->getCommand()); 433 | 434 | byte indicator = comObj->getIndicator(); 435 | 436 | switch (Knx._rxTelegram->getCommand()) { 437 | case KNX_COMMAND_VALUE_READ: 438 | // READ command coming from the bus 439 | // if the Com Object has read attribute, then add RESPONSE action in the TX action list 440 | if ((indicator) & KNX_COM_OBJ_R_INDICATOR) { // The targeted Com Object can indeed be read 441 | action.command = KNX_RESPONSE_REQUEST; 442 | action.index = targetedComObjIndex; 443 | Knx._txActionList.append(action); 444 | } 445 | break; 446 | 447 | case KNX_COMMAND_VALUE_RESPONSE: 448 | // RESPONSE command coming from KNX network, we update the value of the corresponding Com Object. 449 | // We 1st check that the corresponding Com Object has UPDATE attribute 450 | if ((indicator) & KNX_COM_OBJ_U_INDICATOR) { 451 | comObj->updateValue(*(Knx._rxTelegram)); 452 | //We notify the upper layer of the update 453 | knxEvents(targetedComObjIndex); 454 | } 455 | break; 456 | 457 | case KNX_COMMAND_VALUE_WRITE: 458 | // WRITE command coming from KNX network, we update the value of the corresponding Com Object. 459 | // We 1st check that the corresponding Com Object has WRITE attribute 460 | 461 | //DEBUG_PRINTLN(F(" KNX_COMMAND_VALUE_WRITE: ComObj Indicator=0x%02X"), indicator); 462 | if ((indicator) & KNX_COM_OBJ_W_INDICATOR) { 463 | comObj->updateValue(*(Knx._rxTelegram)); 464 | //We notify the upper layer of the update 465 | if (Konnekting.isActive()) { 466 | //DEBUG_PRINTLN(F(" Routing event to konnektingKnxEvents: #%d"), targetedComObjIndex); 467 | konnektingKnxEvents(targetedComObjIndex); 468 | } else { 469 | //DEBUG_PRINTLN(F(" No event routing, because not active: #%d"), targetedComObjIndex); 470 | // knxEvents(targetedComObjIndex); 471 | } 472 | } else { 473 | //DEBUG_PRINTLN(F( "Wrong config byte on comobj #%d: 0x%02X"), targetedComObjIndex, indicator); 474 | } 475 | break; 476 | 477 | // case KNX_COMMAND_MEMORY_WRITE : break; // Memory Write not handled 478 | 479 | default: 480 | break; // not supposed to happen 481 | } 482 | } 483 | 484 | } break; 485 | // Manage RESET events 486 | case TPUART_EVENT_RESET: { 487 | while (Knx._tpuart->reset() == KNX_TPUART_ERROR){ 488 | // wait for successfull reset 489 | //DEBUG_PRINTLN(F(" waiting for reset")); 490 | } 491 | 492 | Knx._tpuart->init(); 493 | Knx._state = IDLE; 494 | } break; 495 | // just log unhandled event id 496 | default: 497 | DEBUG_PRINTLN(F(" getTpUartEvents unhandled event=%d"), event); 498 | } 499 | } 500 | 501 | /* 502 | * Static txTelegramAck() function called by the KnxTpUart layer (callback) 503 | */ 504 | void KnxDevice::txTelegramAck(TpUartTxAck) { 505 | Knx._state = IDLE; 506 | } 507 | 508 | template 509 | KnxDeviceStatus ConvertFromDpt(const byte dptOriginValue[], T& resultValue, byte dptFormat) { 510 | switch (dptFormat) { 511 | case KNX_DPT_FORMAT_U16: 512 | case KNX_DPT_FORMAT_V16: 513 | resultValue = (T)((unsigned int)dptOriginValue[0] << 8); 514 | resultValue += (T)(dptOriginValue[1]); 515 | return KNX_DEVICE_OK; 516 | break; 517 | 518 | case KNX_DPT_FORMAT_U32: 519 | case KNX_DPT_FORMAT_V32: 520 | resultValue = (T)((unsigned long)dptOriginValue[0] << 24); 521 | resultValue += (T)((unsigned long)dptOriginValue[1] << 16); 522 | resultValue += (T)((unsigned long)dptOriginValue[2] << 8); 523 | resultValue += (T)(dptOriginValue[3]); 524 | return KNX_DEVICE_OK; 525 | break; 526 | 527 | case KNX_DPT_FORMAT_F16: { 528 | // Get the DPT sign, mantissa and exponent 529 | int signMultiplier = (dptOriginValue[0] & 0x80) ? -1 : 1; 530 | word absoluteMantissa = dptOriginValue[1] + ((dptOriginValue[0] & 0x07) << 8); 531 | if (signMultiplier == -1) { // Calculate absolute mantissa value in case of negative mantissa 532 | // Abs = 2's complement + 1 533 | absoluteMantissa = ((~absoluteMantissa) & 0x07FF) + 1; 534 | } 535 | byte exponent = (dptOriginValue[0] & 0x78) >> 3; 536 | resultValue = (T)(0.01 * ((long)absoluteMantissa << exponent) * signMultiplier); 537 | return KNX_DEVICE_OK; 538 | } break; 539 | 540 | case KNX_DPT_FORMAT_F32: 541 | return KNX_DEVICE_NOT_IMPLEMENTED; 542 | break; 543 | 544 | default: 545 | return KNX_DEVICE_ERROR; 546 | } 547 | } 548 | 549 | template KnxDeviceStatus ConvertFromDpt(const byte dptOriginValue[], unsigned char&, byte dptFormat); 550 | template KnxDeviceStatus ConvertFromDpt(const byte dptOriginValue[], char&, byte dptFormat); 551 | template KnxDeviceStatus ConvertFromDpt(const byte dptOriginValue[], unsigned int&, byte dptFormat); 552 | template KnxDeviceStatus ConvertFromDpt(const byte dptOriginValue[], int&, byte dptFormat); 553 | template KnxDeviceStatus ConvertFromDpt(const byte dptOriginValue[], unsigned long&, byte dptFormat); 554 | template KnxDeviceStatus ConvertFromDpt(const byte dptOriginValue[], long&, byte dptFormat); 555 | template KnxDeviceStatus ConvertFromDpt(const byte dptOriginValue[], float&, byte dptFormat); 556 | template KnxDeviceStatus ConvertFromDpt(const byte dptOriginValue[], double&, byte dptFormat); 557 | 558 | template 559 | KnxDeviceStatus ConvertToDpt(T originValue, byte dptDestValue[], byte dptFormat) { 560 | switch (dptFormat) { 561 | case KNX_DPT_FORMAT_U16: 562 | case KNX_DPT_FORMAT_V16: 563 | dptDestValue[0] = (byte)((unsigned int)originValue >> 8); 564 | dptDestValue[1] = (byte)(originValue); 565 | return KNX_DEVICE_OK; 566 | break; 567 | 568 | case KNX_DPT_FORMAT_U32: 569 | case KNX_DPT_FORMAT_V32: 570 | dptDestValue[0] = (byte)((unsigned long)originValue >> 24); 571 | dptDestValue[1] = (byte)((unsigned long)originValue >> 16); 572 | dptDestValue[2] = (byte)((unsigned long)originValue >> 8); 573 | dptDestValue[3] = (byte)(originValue); 574 | return KNX_DEVICE_OK; 575 | break; 576 | 577 | case KNX_DPT_FORMAT_F16: { 578 | long longValuex100 = (long)(100.0 * originValue); 579 | bool negativeSign = (longValuex100 & 0x80000000) ? true : false; 580 | byte exponent = 0; 581 | byte round = 0; 582 | 583 | if (negativeSign) { 584 | while (longValuex100 < (long)(-2048)) { 585 | exponent++; 586 | round = (byte)(longValuex100)&1; 587 | longValuex100 >>= 1; 588 | longValuex100 |= 0x80000000; 589 | } 590 | } else { 591 | while (longValuex100 > (long)(2047)) { 592 | exponent++; 593 | round = (byte)(longValuex100)&1; 594 | longValuex100 >>= 1; 595 | } 596 | } 597 | if (round) longValuex100++; 598 | dptDestValue[1] = (byte)longValuex100; 599 | dptDestValue[0] = (byte)(longValuex100 >> 8) & 0x7; 600 | dptDestValue[0] += exponent << 3; 601 | if (negativeSign) dptDestValue[0] += 0x80; 602 | return KNX_DEVICE_OK; 603 | } break; 604 | 605 | case KNX_DPT_FORMAT_F32: 606 | return KNX_DEVICE_NOT_IMPLEMENTED; 607 | break; 608 | 609 | default: 610 | return KNX_DEVICE_ERROR; 611 | } 612 | } 613 | 614 | template KnxDeviceStatus ConvertToDpt(unsigned char, byte dptDestValue[], byte dptFormat); 615 | template KnxDeviceStatus ConvertToDpt(char, byte dptDestValue[], byte dptFormat); 616 | template KnxDeviceStatus ConvertToDpt(unsigned int, byte dptDestValue[], byte dptFormat); 617 | template KnxDeviceStatus ConvertToDpt(int, byte dptDestValue[], byte dptFormat); 618 | template KnxDeviceStatus ConvertToDpt(unsigned long, byte dptDestValue[], byte dptFormat); 619 | template KnxDeviceStatus ConvertToDpt(long, byte dptDestValue[], byte dptFormat); 620 | template KnxDeviceStatus ConvertToDpt(float, byte dptDestValue[], byte dptFormat); 621 | template KnxDeviceStatus ConvertToDpt(double, byte dptDestValue[], byte dptFormat); 622 | 623 | // EOF 624 | --------------------------------------------------------------------------------