From 147a3942ad36ec1e1f5409782ecc08ba38ac1a70 Mon Sep 17 00:00:00 2001 From: etrinh Date: Thu, 2 Apr 2020 18:09:53 +0200 Subject: [PATCH 01/10] Add priliminar Arduino STM32 port --- src/knx/bits.h | 2 +- src/knx/group_object.h | 2 +- src/knx_facade.cpp | 2 ++ src/knx_facade.h | 9 +++++++++ src/stm32_platform.cpp | 43 ++++++++++++++++++++++++++++++++++++++++++ src/stm32_platform.h | 25 ++++++++++++++++++++++++ 6 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 src/stm32_platform.cpp create mode 100644 src/stm32_platform.h diff --git a/src/knx/bits.h b/src/knx/bits.h index ec12e9a..6a2b771 100644 --- a/src/knx/bits.h +++ b/src/knx/bits.h @@ -34,7 +34,7 @@ uint32_t digitalRead(uint32_t dwPin); typedef void (*voidFuncPtr)(void); void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode); -#elif ARDUINO_ARCH_SAMD +#elif ARDUINO_ARCH_SAMD || ARDUINO_ARCH_STM32 #include #define htons(x) ( (((x)<<8)&0xFF00) | (((x)>>8)&0xFF) ) #define ntohs(x) htons(x) diff --git a/src/knx/group_object.h b/src/knx/group_object.h index 0e71b96..96499e9 100644 --- a/src/knx/group_object.h +++ b/src/knx/group_object.h @@ -19,7 +19,7 @@ enum ComFlag class GroupObject; -#ifdef __linux__ +#if __has_include() #include typedef std::function GroupObjectUpdatedHandler; #else diff --git a/src/knx_facade.cpp b/src/knx_facade.cpp index 45cdbcc..e79ccec 100644 --- a/src/knx_facade.cpp +++ b/src/knx_facade.cpp @@ -22,6 +22,8 @@ #elif ARDUINO_ARCH_ESP32 // predefined global instance for IP only KnxFacade knx; +#elif ARDUINO_ARCH_STM32 + KnxFacade knx; #elif __linux__ // no predefined global instance #define ICACHE_RAM_ATTR diff --git a/src/knx_facade.h b/src/knx_facade.h index c59b600..8611c02 100644 --- a/src/knx_facade.h +++ b/src/knx_facade.h @@ -18,6 +18,9 @@ #define LED_BUILTIN 13 #include "esp32_platform.h" #include "knx/bau57B0.h" +#elif ARDUINO_ARCH_STM32 + #include "stm32_platform.h" + #include "knx/bau57B0.h" #else #define LED_BUILTIN 0 #include "linux_platform.h" @@ -331,8 +334,14 @@ template class KnxFacade : private SaveRestore // predefined global instance for IP only extern KnxFacade knx; #elif ARDUINO_ARCH_ESP32 +<<<<<<< Updated upstream // predefined global instance for IP only extern KnxFacade knx; +======= +extern KnxFacade knx; +#elif ARDUINO_ARCH_STM32 +extern KnxFacade knx; +>>>>>>> Stashed changes #elif __linux__ // no predefined global instance #endif diff --git a/src/stm32_platform.cpp b/src/stm32_platform.cpp new file mode 100644 index 0000000..b9db3c7 --- /dev/null +++ b/src/stm32_platform.cpp @@ -0,0 +1,43 @@ +#include "stm32_platform.h" + +#ifdef ARDUINO_ARCH_STM32 +#include +#include "knx/bits.h" + +Stm32Platform::Stm32Platform() : ArduinoPlatform(&Serial2), eepromPtr(nullptr), eepromSize(0) +{ +} + +Stm32Platform::Stm32Platform( HardwareSerial* s) : ArduinoPlatform(s), eepromPtr(nullptr), eepromSize(0) +{ +} + +Stm32Platform::~Stm32Platform() +{ + delete [] eepromPtr; +} + +void Stm32Platform::restart() +{ + println("restart"); + NVIC_SystemReset(); +} + +uint8_t * Stm32Platform::getEepromBuffer(uint16_t size) +{ + delete [] eepromPtr; + eepromPtr = new uint8_t[size]; + for (uint16_t i = 0; i < size; ++i) + eepromPtr[i] = EEPROM[i]; + return eepromPtr; +} + +void Stm32Platform::commitToEeprom() +{ + if(eepromPtr == nullptr) + return; + for (uint16_t i = 0; i < eepromSize; ++i) + EEPROM.update(i, eepromPtr[i]); +} + +#endif diff --git a/src/stm32_platform.h b/src/stm32_platform.h new file mode 100644 index 0000000..17062f3 --- /dev/null +++ b/src/stm32_platform.h @@ -0,0 +1,25 @@ +#ifdef ARDUINO_ARCH_STM32 +#include "arduino_platform.h" + + +class Stm32Platform : public ArduinoPlatform +{ + using ArduinoPlatform::_mulitcastAddr; + using ArduinoPlatform::_mulitcastPort; +public: + Stm32Platform(); + Stm32Platform( HardwareSerial* s); + ~Stm32Platform(); + + // basic stuff + void restart(); + + //memory + uint8_t* getEepromBuffer(uint16_t size); + void commitToEeprom(); +private: + uint8_t *eepromPtr; + uint16_t eepromSize; +}; + +#endif From 34df27ee8729a9cd562b62898d4dc265c34eda69 Mon Sep 17 00:00:00 2001 From: etrinh Date: Thu, 2 Apr 2020 18:16:15 +0200 Subject: [PATCH 02/10] fix bad commit --- src/knx_facade.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/knx_facade.h b/src/knx_facade.h index 8611c02..108b7be 100644 --- a/src/knx_facade.h +++ b/src/knx_facade.h @@ -334,14 +334,11 @@ template class KnxFacade : private SaveRestore // predefined global instance for IP only extern KnxFacade knx; #elif ARDUINO_ARCH_ESP32 -<<<<<<< Updated upstream // predefined global instance for IP only extern KnxFacade knx; -======= -extern KnxFacade knx; #elif ARDUINO_ARCH_STM32 -extern KnxFacade knx; ->>>>>>> Stashed changes + // predefined global instance for TP only + extern KnxFacade knx; #elif __linux__ // no predefined global instance #endif From ced8aa0a31224368c93e850173608dfc974a2350 Mon Sep 17 00:00:00 2001 From: etrinh Date: Thu, 2 Apr 2020 18:25:52 +0200 Subject: [PATCH 03/10] Fix conflicts with STM32 DADDR, knx DADDR rename DEVADDR --- src/knx/rf_physical_layer.h | 2 +- src/knx_facade.cpp | 2 ++ src/stm32_platform.cpp | 1 - src/stm32_platform.h | 3 --- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/knx/rf_physical_layer.h b/src/knx/rf_physical_layer.h index 19392e8..01a3c44 100644 --- a/src/knx/rf_physical_layer.h +++ b/src/knx/rf_physical_layer.h @@ -59,7 +59,7 @@ extern void delayMicroseconds (unsigned int howLong); #define PKTLEN 0x06 // Packet length #define PKTCTRL1 0x07 // Packet automation control #define PKTCTRL0 0x08 // Packet automation control -#define DADDR 0x09 // Device address +#define DEVADDR 0x09 // Device address #define CHANNR 0x0A // Channel number #define FSCTRL1 0x0B // Frequency synthesizer control #define FSCTRL0 0x0C // Frequency synthesizer control diff --git a/src/knx_facade.cpp b/src/knx_facade.cpp index e79ccec..ba5e766 100644 --- a/src/knx_facade.cpp +++ b/src/knx_facade.cpp @@ -24,6 +24,8 @@ KnxFacade knx; #elif ARDUINO_ARCH_STM32 KnxFacade knx; + // no predefined global instance + #define ICACHE_RAM_ATTR #elif __linux__ // no predefined global instance #define ICACHE_RAM_ATTR diff --git a/src/stm32_platform.cpp b/src/stm32_platform.cpp index b9db3c7..4d2d92c 100644 --- a/src/stm32_platform.cpp +++ b/src/stm32_platform.cpp @@ -19,7 +19,6 @@ Stm32Platform::~Stm32Platform() void Stm32Platform::restart() { - println("restart"); NVIC_SystemReset(); } diff --git a/src/stm32_platform.h b/src/stm32_platform.h index 17062f3..d8c6faa 100644 --- a/src/stm32_platform.h +++ b/src/stm32_platform.h @@ -1,11 +1,8 @@ #ifdef ARDUINO_ARCH_STM32 #include "arduino_platform.h" - class Stm32Platform : public ArduinoPlatform { - using ArduinoPlatform::_mulitcastAddr; - using ArduinoPlatform::_mulitcastPort; public: Stm32Platform(); Stm32Platform( HardwareSerial* s); From 0f99a4c969c4c7dbbbec336b48e4df8553301976 Mon Sep 17 00:00:00 2001 From: etrinh Date: Thu, 2 Apr 2020 22:10:50 +0200 Subject: [PATCH 04/10] Fix compilation warning STM32 uses TP --- src/knx/dptconvert.cpp | 10 ++++++---- src/knx/knx_value.cpp | 2 +- src/knx_facade.cpp | 2 +- src/knx_facade.h | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/knx/dptconvert.cpp b/src/knx/dptconvert.cpp index 5da8fde..1c5a734 100644 --- a/src/knx/dptconvert.cpp +++ b/src/knx/dptconvert.cpp @@ -1723,8 +1723,9 @@ double float16FromPayload(const uint8_t* payload, int index) } float float32FromPayload(const uint8_t* payload, int index) { - uint32_t area = unsigned32FromPayload(payload, index); - return *((float*)&area); + union { float f; uint32_t i; } area; + area.i = unsigned32FromPayload(payload, index); + return area.f; } int64_t signed64FromPayload(const uint8_t* payload, int index) { @@ -1815,8 +1816,9 @@ void float16ToPayload(uint8_t* payload, size_t payload_length, int index, double } void float32ToPayload(uint8_t* payload, size_t payload_length, int index, double value, uint32_t mask) { - float num = value; - unsigned32ToPayload(payload, payload_length, index, *((uint32_t*)&num), mask); + union { float f; uint32_t i; } num; + num.f = value; + unsigned32ToPayload(payload, payload_length, index, num.i, mask); } void signed64ToPayload(uint8_t* payload, size_t payload_length, int index, int64_t value, uint64_t mask) { diff --git a/src/knx/knx_value.cpp b/src/knx/knx_value.cpp index 7b6f93a..22d3e85 100644 --- a/src/knx/knx_value.cpp +++ b/src/knx/knx_value.cpp @@ -526,7 +526,7 @@ struct tm KNXValue::timeValue() const return *timePtr; } } - struct tm tmp; + struct tm tmp = {0}; return tmp; } diff --git a/src/knx_facade.cpp b/src/knx_facade.cpp index ba5e766..7219cb0 100644 --- a/src/knx_facade.cpp +++ b/src/knx_facade.cpp @@ -23,7 +23,7 @@ // predefined global instance for IP only KnxFacade knx; #elif ARDUINO_ARCH_STM32 - KnxFacade knx; + KnxFacade knx; // no predefined global instance #define ICACHE_RAM_ATTR #elif __linux__ diff --git a/src/knx_facade.h b/src/knx_facade.h index 108b7be..7aa862c 100644 --- a/src/knx_facade.h +++ b/src/knx_facade.h @@ -20,7 +20,7 @@ #include "knx/bau57B0.h" #elif ARDUINO_ARCH_STM32 #include "stm32_platform.h" - #include "knx/bau57B0.h" + #include "knx/bau07B0.h" #else #define LED_BUILTIN 0 #include "linux_platform.h" @@ -338,7 +338,7 @@ template class KnxFacade : private SaveRestore extern KnxFacade knx; #elif ARDUINO_ARCH_STM32 // predefined global instance for TP only - extern KnxFacade knx; + extern KnxFacade knx; #elif __linux__ // no predefined global instance #endif From d789fb14592bfb94918019b1e82c6e6b77640c99 Mon Sep 17 00:00:00 2001 From: etrinh Date: Tue, 7 Apr 2020 18:24:28 +0200 Subject: [PATCH 05/10] Enable TP medium for ESP32 --- src/knx_facade.cpp | 25 +++++++++++++++++-------- src/knx_facade.h | 17 ++++++++++++++--- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/knx_facade.cpp b/src/knx_facade.cpp index 7219cb0..a26089c 100644 --- a/src/knx_facade.cpp +++ b/src/knx_facade.cpp @@ -15,28 +15,37 @@ #else #error "No medium type specified for platform Arduino_SAMD! Please set MEDIUM_TYPE! (TP:0, RF:2, IP:5)" #endif - #define ICACHE_RAM_ATTR #elif ARDUINO_ARCH_ESP8266 // predefined global instance for IP only KnxFacade knx; #elif ARDUINO_ARCH_ESP32 - // predefined global instance for IP only - KnxFacade knx; + // predefined global instance for TP or IP + #ifdef MEDIUM_TYPE + #if MEDIUM_TYPE == 0 + KnxFacade knx; + #elif MEDIUM_TYPE == 5 + KnxFacade knx; + #else + #error "Only TP and IP supported for Arduino ESP32 platform!" + #endif + #else + // Compatibility + KnxFacade knx; + //#error "No medium type specified for platform Arduino ESP32! Please set MEDIUM_TYPE! (TP:0, RF:2, IP:5)" + #endif #elif ARDUINO_ARCH_STM32 KnxFacade knx; - // no predefined global instance - #define ICACHE_RAM_ATTR #elif __linux__ // no predefined global instance - #define ICACHE_RAM_ATTR #endif -#ifndef __linux__ -uint32_t lastpressed=0; +#ifndef ICACHE_RAM_ATTR + #define ICACHE_RAM_ATTR #endif ICACHE_RAM_ATTR void buttonUp() { #ifndef __linux__ + static uint32_t lastpressed=0; if (millis() - lastpressed > 200){ knx._toogleProgMode = true; lastpressed = millis(); diff --git a/src/knx_facade.h b/src/knx_facade.h index 7aa862c..44afb4a 100644 --- a/src/knx_facade.h +++ b/src/knx_facade.h @@ -17,6 +17,7 @@ #elif ARDUINO_ARCH_ESP32 #define LED_BUILTIN 13 #include "esp32_platform.h" + #include "knx/bau07B0.h" #include "knx/bau57B0.h" #elif ARDUINO_ARCH_STM32 #include "stm32_platform.h" @@ -334,11 +335,21 @@ template class KnxFacade : private SaveRestore // predefined global instance for IP only extern KnxFacade knx; #elif ARDUINO_ARCH_ESP32 - // predefined global instance for IP only - extern KnxFacade knx; + // predefined global instance for TP or IP + #ifdef MEDIUM_TYPE + #if MEDIUM_TYPE == 0 + extern KnxFacade knx; + #elif MEDIUM_TYPE == 5 + extern KnxFacade knx; + #else + #error "Only TP and IP supported for Arduino ESP32 platform!" + #endif + #else + #error "No medium type specified for Arduino ESP32 platform! Please set MEDIUM_TYPE! (TP:0, RF:2, IP:5)" + #endif #elif ARDUINO_ARCH_STM32 // predefined global instance for TP only extern KnxFacade knx; #elif __linux__ // no predefined global instance -#endif +#endif \ No newline at end of file From 5855f35eef51b4c41d7655e5b9aae7dfb85f182b Mon Sep 17 00:00:00 2001 From: thelsing Date: Tue, 23 Jun 2020 00:21:00 +0200 Subject: [PATCH 06/10] fix #50 --- src/knx/dptconvert.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/knx/dptconvert.cpp b/src/knx/dptconvert.cpp index 1c5a734..9ed1154 100644 --- a/src/knx/dptconvert.cpp +++ b/src/knx/dptconvert.cpp @@ -416,11 +416,11 @@ int busValueToUnsigned8(const uint8_t* payload, size_t payload_length, const Dpt switch (datatype.subGroup) { case 1: - value = (uint8_t)(unsigned8FromPayload(payload, 0) * 100.0 / 255.0); + value = (uint8_t)round(unsigned8FromPayload(payload, 0) * 100.0 / 255.0); return true; case 3: - value = (uint8_t)unsigned8FromPayload(payload, 0) * 360.0 / 255.0; + value = (uint8_t)round(unsigned8FromPayload(payload, 0) * 360.0 / 255.0); return true; case 6: @@ -1839,4 +1839,4 @@ void bcdToPayload(uint8_t* payload, size_t payload_length, int index, uint8_t va payload[index / 2] = (payload[index / 2] & 0xF0) | (value & 0x0F); else payload[index / 2] = (payload[index / 2] & 0x0F) | ((value << 4) & 0xF0); -} \ No newline at end of file +} From 084657cb7a27804e84d810a392bd5e7503ea2b62 Mon Sep 17 00:00:00 2001 From: thelsing Date: Wed, 24 Jun 2020 18:48:55 +0200 Subject: [PATCH 07/10] fix #46 --- src/knx/bau_systemB.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/knx/bau_systemB.cpp b/src/knx/bau_systemB.cpp index 1a80920..3340fc5 100644 --- a/src/knx/bau_systemB.cpp +++ b/src/knx/bau_systemB.cpp @@ -45,6 +45,9 @@ void BauSystemB::enabled(bool value) void BauSystemB::sendNextGroupTelegram() { + if(!configured()) + return; + static uint16_t startIdx = 1; GroupObjectTableObject& table = _groupObjTable; From eacc944e7ce397e2ffe0b2a041d8c80ab62e5c86 Mon Sep 17 00:00:00 2001 From: thelsing Date: Wed, 24 Jun 2020 22:14:45 +0200 Subject: [PATCH 08/10] remove __has_include because of build failure --- src/knx/group_object.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/knx/group_object.h b/src/knx/group_object.h index 96499e9..0e71b96 100644 --- a/src/knx/group_object.h +++ b/src/knx/group_object.h @@ -19,7 +19,7 @@ enum ComFlag class GroupObject; -#if __has_include() +#ifdef __linux__ #include typedef std::function GroupObjectUpdatedHandler; #else From f450d87d05f2ad497d7cda863259cfcdd1af60ee Mon Sep 17 00:00:00 2001 From: Thomas Kunze Date: Wed, 24 Jun 2020 23:03:12 +0200 Subject: [PATCH 09/10] refactor RfMediumObject to use properties --- examples/knx-linux/knx-linux.vcxproj | 1 + examples/knx-linux/knx-linux.vcxproj.filters | 3 + src/knx/function_property.h | 6 +- src/knx/interface_object.cpp | 59 ------- src/knx/interface_object.h | 11 -- src/knx/rf_medium_object.cpp | 165 +++++-------------- src/knx/rf_medium_object.h | 14 +- 7 files changed, 51 insertions(+), 208 deletions(-) diff --git a/examples/knx-linux/knx-linux.vcxproj b/examples/knx-linux/knx-linux.vcxproj index ed5230c..cdc925d 100644 --- a/examples/knx-linux/knx-linux.vcxproj +++ b/examples/knx-linux/knx-linux.vcxproj @@ -93,6 +93,7 @@ + diff --git a/examples/knx-linux/knx-linux.vcxproj.filters b/examples/knx-linux/knx-linux.vcxproj.filters index 3f4a28a..6b44be3 100644 --- a/examples/knx-linux/knx-linux.vcxproj.filters +++ b/examples/knx-linux/knx-linux.vcxproj.filters @@ -194,6 +194,9 @@ Header files\knx + + Header files\knx + diff --git a/src/knx/function_property.h b/src/knx/function_property.h index b43df9f..78e6464 100644 --- a/src/knx/function_property.h +++ b/src/knx/function_property.h @@ -7,11 +7,11 @@ class InterfaceObject; template class FunctionProperty : public Property { public: - FunctionProperty(T* io, PropertyID id, uint8_t access, + FunctionProperty(T* io, PropertyID id, void (*commandCallback)(T*, uint8_t*, uint8_t, uint8_t*, uint8_t&), void (*stateCallback)(T*, uint8_t*, uint8_t, uint8_t*, uint8_t&)) - : Property(id, false, PDT_FUNCTION, 1, access), _interfaceObject(io), _commandCallback(commandCallback), _stateCallback(stateCallback) - /* max_elements is set to 1, see 3.3.7 Application Layer p.68 */ + : Property(id, false, PDT_FUNCTION, 1, ReadLv0|WriteLv0), _interfaceObject(io), _commandCallback(commandCallback), _stateCallback(stateCallback) + /* max_elements is set to 1, read and write level any value so we use Lv0, see 3.3.7 Application Layer p.68 */ {} virtual uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const override diff --git a/src/knx/interface_object.cpp b/src/knx/interface_object.cpp index 19396ac..3949409 100644 --- a/src/knx/interface_object.cpp +++ b/src/knx/interface_object.cpp @@ -10,54 +10,6 @@ InterfaceObject::~InterfaceObject() } void InterfaceObject::readPropertyDescription(uint8_t& propertyId, uint8_t& propertyIndex, bool& writeEnable, uint8_t& type, uint16_t& numberOfElements, uint8_t& access) -{ - PropertyDescription* descriptions = propertyDescriptions(); - uint8_t count = propertyDescriptionCount(); - - numberOfElements = 0; - if (descriptions == nullptr || count == 0) - return readPropertyDescription2(propertyId, propertyIndex, writeEnable, type, numberOfElements, access); - - PropertyDescription* desc = nullptr; - - // from KNX spec. 03.03.07 Application Layer (page 56) - 3.4.3.3 A_PropertyDescription_Read-service - // Summary: either propertyId OR propertyIndex, but not both at the same time - if (propertyId != 0) - { - for (uint8_t i = 0; i < count; i++) - { - PropertyDescription d = descriptions[i]; - if (d.Id != propertyId) - continue; - - desc = &d; - propertyIndex = i; - break; - } - } - else - { - // If propertyId is zero, propertyIndex shall be used. - // Response: propertyIndex of received A_PropertyDescription_Read - if (propertyIndex < count) - { - desc = &descriptions[propertyIndex]; - } - } - - if (desc != nullptr) - { - propertyId = desc->Id; - writeEnable = desc->WriteEnable; - type = desc->Type; - numberOfElements = desc->MaxElements; - access = desc->Access; - } - else - return readPropertyDescription2(propertyId, propertyIndex, writeEnable, type, numberOfElements, access); -} - -void InterfaceObject::readPropertyDescription2(uint8_t& propertyId, uint8_t& propertyIndex, bool& writeEnable, uint8_t& type, uint16_t& numberOfElements, uint8_t& access) { uint8_t count = _propertyCount; @@ -161,17 +113,6 @@ void InterfaceObject::state(PropertyID id, uint8_t* data, uint8_t length, uint8_ prop->state(data, length, resultData, resultLength); } -uint8_t InterfaceObject::propertyDescriptionCount() -{ - return 0; -} - -PropertyDescription* InterfaceObject::propertyDescriptions() -{ - return nullptr; -} - - void InterfaceObject::initializeProperties(size_t propertiesSize, Property** properties) { _propertyCount = propertiesSize / sizeof(Property*); diff --git a/src/knx/interface_object.h b/src/knx/interface_object.h index 0b92633..63e6797 100644 --- a/src/knx/interface_object.h +++ b/src/knx/interface_object.h @@ -144,9 +144,7 @@ class InterfaceObject : public SaveRestore * * @param[out] access the ::AccessLevel necessary to read/write the property. */ - // TODO: remove first version after complete property refactoring void readPropertyDescription(uint8_t& propertyId, uint8_t& propertyIndex, bool& writeEnable, uint8_t& type, uint16_t& numberOfElements, uint8_t& access); - void readPropertyDescription2(uint8_t& propertyId, uint8_t& propertyIndex, bool& writeEnable, uint8_t& type, uint16_t& numberOfElements, uint8_t& access); /** * Gets property with PropertyID id if it exists and nullptr otherwise. @@ -181,15 +179,6 @@ class InterfaceObject : public SaveRestore virtual uint16_t saveSize() override; protected: - /** - * Returns the number of properties the interface object has. - */ - virtual uint8_t propertyDescriptionCount(); - /** - * Returns a pointer to the first PropertyDescription of the interface object. - * This is used by readPropertyDescription() together with propertyCount(). - */ - virtual PropertyDescription* propertyDescriptions(); /** * Intializes the Property-array the the supplied values. diff --git a/src/knx/rf_medium_object.cpp b/src/knx/rf_medium_object.cpp index d731975..be4d511 100644 --- a/src/knx/rf_medium_object.cpp +++ b/src/knx/rf_medium_object.cpp @@ -1,141 +1,60 @@ #include #include "rf_medium_object.h" #include "bits.h" +#include "data_property.h" +#include "function_property.h" #include "config.h" #ifdef USE_RF -void RfMediumObject::readProperty(PropertyID propertyId, uint16_t start, uint8_t& count, uint8_t* data) +RfMediumObject::RfMediumObject() { - switch (propertyId) + uint8_t rfDomainAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // see KNX RF S-Mode AN160 p.11 + Property* properties[] = { - case PID_OBJECT_TYPE: - pushWord(OT_RF_MEDIUM, data); - break; - case PID_RF_MULTI_TYPE: - data[0] = 0x00; // KNX RF ready only - break; - case PID_RF_DOMAIN_ADDRESS: - pushByteArray((uint8_t*)_rfDomainAddress, 6, data); - break; - case PID_RF_RETRANSMITTER: - data[0] = 0x00; // No KNX RF retransmitter - break; - case PID_RF_BIDIR_TIMEOUT: // PDT_FUNCTION - data[0] = 0x00; // success - data[1] = 0xFF; // permanent bidirectional device - data[2] = 0xFF; // permanent bidirectional device - break; - case PID_RF_DIAG_SA_FILTER_TABLE: // PDT_GENERIC_03[] - pushByteArray((uint8_t*)_rfDiagSourceAddressFilterTable, 24, data); - break; - case PID_RF_DIAG_BUDGET_TABLE: - pushByteArray((uint8_t*)_rfDiagLinkBudgetTable, 24, data); - break; - case PID_RF_DIAG_PROBE: // PDT_FUNCTION - // Not supported yet - break; - default: - count = 0; - } + new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_RF_MEDIUM), + new DataProperty(PID_RF_MULTI_TYPE, true, PDT_GENERIC_01, 1, ReadLv3 | WriteLv2, (uint8_t)0x00), + new DataProperty(PID_RF_RETRANSMITTER, false, PDT_GENERIC_01, 1, ReadLv3 | WriteLv0, (uint8_t)0x00), + new DataProperty(PID_RF_DOMAIN_ADDRESS, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv2, rfDomainAddress), + new FunctionProperty(this, PID_RF_BIDIR_TIMEOUT, + [](RfMediumObject* io, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) + { + resultData[0] = 0x00; // success + resultData[1] = 0xFF; // permanent bidirectional device + resultData[2] = 0xFF; // permanent bidirectional device + resultLength = 3; + }, + [](RfMediumObject* io, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) + { + resultData[0] = 0x00; // success + resultData[1] = 0xFF; // permanent bidirectional device + resultData[2] = 0xFF; // permanent bidirectional device + resultLength = 3; + }), +/* This properties are used in NMP_LinkBudget_Measure to diagnose the Link Budget of the communication. + This in not implemented yet. + new DataProperty(PID_RF_DIAG_SA_FILTER_TABLE, true, PDT_GENERIC_03, 8, ReadLv3 | WriteLv3), + new DataProperty(PID_RF_DIAG_BUDGET_TABLE, false, PDT_GENERIC_03, 8, ReadLv3 | WriteLv0), + new FunctionProperty(this, PID_RF_DIAG_PROBE, + [](RfMediumObject* io, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) + { + }, + [](RfMediumObject* io, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) + { + }), */ + }; + initializeProperties(sizeof(properties), properties); } -void RfMediumObject::writeProperty(PropertyID id, uint16_t start, uint8_t* data, uint8_t& count) +const uint8_t* RfMediumObject::rfDomainAddress() { - switch (id) - { - case PID_RF_MULTI_TYPE: - // We only support RF ready and not RF multi, ignore write request - break; - case PID_RF_DOMAIN_ADDRESS: - for (uint8_t i = start; i < start + count; i++) - _rfDomainAddress[i-1] = data[i - start]; - break; - case PID_RF_BIDIR_TIMEOUT: // PDT_FUNCTION - // Not supported yet (permanent bidir device) - break; - case PID_RF_DIAG_SA_FILTER_TABLE: - for (uint8_t i = start; i < start + count; i++) - _rfDiagSourceAddressFilterTable[i-1] = data[i - start]; - break; - case PID_RF_DIAG_BUDGET_TABLE: - for (uint8_t i = start; i < start + count; i++) - _rfDiagLinkBudgetTable[i-1] = data[i - start]; - break; - case PID_RF_DIAG_PROBE: - // Not supported yet - break; - default: - count = 0; - break; - } -} - -uint8_t RfMediumObject::propertySize(PropertyID id) -{ - switch (id) - { - case PID_RF_MULTI_TYPE: - case PID_RF_RETRANSMITTER: - return 1; - case PID_OBJECT_TYPE: - return 2; - case PID_RF_DOMAIN_ADDRESS: - return 6; - case PID_RF_DIAG_SA_FILTER_TABLE: - case PID_RF_DIAG_BUDGET_TABLE: - return 24; - // case PID_RF_BIDIR_TIMEOUT: ? - // case PID_RF_DIAG_PROBE: ? - default: - break; - } - return 0; -} - -uint8_t* RfMediumObject::save(uint8_t* buffer) -{ - buffer = pushByteArray((uint8_t*)_rfDomainAddress, 6, buffer); - return buffer; -} - -const uint8_t* RfMediumObject::restore(const uint8_t* buffer) -{ - buffer = popByteArray((uint8_t*)_rfDomainAddress, 6, buffer); - return buffer; -} - -uint16_t RfMediumObject::saveSize() -{ - return 6; -} - -uint8_t* RfMediumObject::rfDomainAddress() -{ - return _rfDomainAddress; + DataProperty* prop = (DataProperty*)property(PID_RF_DOMAIN_ADDRESS); + return prop->data(); } void RfMediumObject::rfDomainAddress(const uint8_t* value) { - pushByteArray(value, 6, _rfDomainAddress); -} - -static PropertyDescription _propertyDescriptions[] = -{ - { PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0 }, - { PID_RF_MULTI_TYPE, false, PDT_GENERIC_01, 1, ReadLv3 | WriteLv0 }, - { PID_RF_RETRANSMITTER, false, PDT_GENERIC_01, 1, ReadLv3 | WriteLv0 }, - { PID_RF_DOMAIN_ADDRESS, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv0 } -}; -static uint8_t _propertyDescriptionCount = sizeof(_propertyDescriptions) / sizeof(PropertyDescription); - -uint8_t RfMediumObject::propertyDescriptionCount() -{ - return _propertyDescriptionCount; -} - -PropertyDescription* RfMediumObject::propertyDescriptions() -{ - return _propertyDescriptions; + Property* prop = property(PID_RF_DOMAIN_ADDRESS); + prop->write(value); } #endif \ No newline at end of file diff --git a/src/knx/rf_medium_object.h b/src/knx/rf_medium_object.h index 6742a85..a07e03b 100644 --- a/src/knx/rf_medium_object.h +++ b/src/knx/rf_medium_object.h @@ -7,21 +7,11 @@ class RfMediumObject: public InterfaceObject { public: - void readProperty(PropertyID id, uint16_t start, uint8_t& count, uint8_t* data) override; - void writeProperty(PropertyID id, uint16_t start, uint8_t* data, uint8_t& count) override; - uint8_t propertySize(PropertyID id) override; - uint8_t* save(uint8_t* buffer) override; - const uint8_t* restore(const uint8_t* buffer) override; - uint16_t saveSize() override; - - uint8_t* rfDomainAddress(); + RfMediumObject(); + const uint8_t* rfDomainAddress(); void rfDomainAddress(const uint8_t* value); -protected: - uint8_t propertyDescriptionCount() override; - PropertyDescription* propertyDescriptions() override; private: - uint8_t _rfDomainAddress[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // see KNX RF S-Mode AN160 p.11 uint8_t _rfDiagSourceAddressFilterTable[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; uint8_t _rfDiagLinkBudgetTable[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; }; From 4677044f46c0e637fb669d93e62fd5c1f4cecb43 Mon Sep 17 00:00:00 2001 From: Thomas Kunze Date: Thu, 25 Jun 2020 20:36:02 +0200 Subject: [PATCH 10/10] add some fixes and enhancements by leoujz fix build --- src/knx/application_layer.cpp | 6 +- src/knx/application_layer.h | 6 +- src/knx/cemi_frame.cpp | 4 +- src/knx/cemi_frame.h | 2 +- src/knx/dptconvert.cpp | 2 +- src/knx/tpuart_data_link_layer.cpp | 1090 ++++++++++++++-------------- src/knx/tpuart_data_link_layer.h | 1 + 7 files changed, 562 insertions(+), 549 deletions(-) diff --git a/src/knx/application_layer.cpp b/src/knx/application_layer.cpp index 421a8f2..297eb65 100644 --- a/src/knx/application_layer.cpp +++ b/src/knx/application_layer.cpp @@ -487,7 +487,7 @@ void ApplicationLayer::systemNetworkParameterReadResponse(Priority priority, Hop //TODO: ApplicationLayer::domainAddressSerialNumberWriteRequest() //TODO: ApplicationLayer::domainAddressSerialNumberReadRequest() -void ApplicationLayer::domainAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, uint8_t* rfDoA, +void ApplicationLayer::domainAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const uint8_t* rfDoA, const uint8_t* knxSerialNumber) { CemiFrame frame(13); @@ -506,8 +506,8 @@ void ApplicationLayer::domainAddressSerialNumberReadResponse(Priority priority, //TODO: ApplicationLayer::IndividualAddressSerialNumberWriteRequest() //TODO: ApplicationLayer::IndividualAddressSerialNumberReadRequest() -void ApplicationLayer::IndividualAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, uint8_t* rfDoA, - uint8_t* knxSerialNumber) +void ApplicationLayer::IndividualAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const uint8_t* rfDoA, + const uint8_t* knxSerialNumber) { CemiFrame frame(13); APDU& apdu = frame.apdu(); diff --git a/src/knx/application_layer.h b/src/knx/application_layer.h index c2de79c..e05e3c9 100644 --- a/src/knx/application_layer.h +++ b/src/knx/application_layer.h @@ -135,10 +135,10 @@ class ApplicationLayer void systemNetworkParameterReadResponse(Priority priority, HopCountType hopType, uint16_t objectType, uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength, uint8_t* testResult, uint16_t testResultLength); - void domainAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, uint8_t* rfDoA, + void domainAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const uint8_t* rfDoA, + const uint8_t* knxSerialNumber); + void IndividualAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const uint8_t* rfDoA, const uint8_t* knxSerialNumber); - void IndividualAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, uint8_t* rfDoA, - uint8_t* knxSerialNumber); #pragma endregion private: diff --git a/src/knx/cemi_frame.cpp b/src/knx/cemi_frame.cpp index c4d6ff1..13e7c79 100644 --- a/src/knx/cemi_frame.cpp +++ b/src/knx/cemi_frame.cpp @@ -323,9 +323,9 @@ uint8_t* CemiFrame::rfSerialOrDoA() const return _rfSerialOrDoA; } -void CemiFrame::rfSerialOrDoA(uint8_t* rfSerialOrDoA) +void CemiFrame::rfSerialOrDoA(const uint8_t* rfSerialOrDoA) { - _rfSerialOrDoA = rfSerialOrDoA; + _rfSerialOrDoA = (uint8_t*)rfSerialOrDoA; } uint8_t CemiFrame::rfInfo() const diff --git a/src/knx/cemi_frame.h b/src/knx/cemi_frame.h index ef30165..fc21501 100644 --- a/src/knx/cemi_frame.h +++ b/src/knx/cemi_frame.h @@ -60,7 +60,7 @@ class CemiFrame #ifdef USE_RF // only for RF medium uint8_t* rfSerialOrDoA() const; - void rfSerialOrDoA(uint8_t* rfSerialOrDoA); + void rfSerialOrDoA(const uint8_t* rfSerialOrDoA); uint8_t rfInfo() const; void rfInfo(uint8_t rfInfo); uint8_t rfLfn() const; diff --git a/src/knx/dptconvert.cpp b/src/knx/dptconvert.cpp index 9ed1154..84c4f94 100644 --- a/src/knx/dptconvert.cpp +++ b/src/knx/dptconvert.cpp @@ -1043,7 +1043,7 @@ int valueToBusValueSigned8(const KNXValue& value, uint8_t* payload, size_t paylo if ((int64_t)value < INT64_C(-128) || (int64_t)value > INT64_C(127)) return false; - signed8ToPayload(payload, 0, payload_length, (uint64_t)value, 0xFF); + signed8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF); return true; } diff --git a/src/knx/tpuart_data_link_layer.cpp b/src/knx/tpuart_data_link_layer.cpp index 595800e..c68db25 100644 --- a/src/knx/tpuart_data_link_layer.cpp +++ b/src/knx/tpuart_data_link_layer.cpp @@ -1,539 +1,551 @@ -#include "tpuart_data_link_layer.h" -#ifdef USE_TP -#include "bits.h" -#include "platform.h" -#include "device_object.h" -#include "address_table_object.h" -#include "cemi_frame.h" - -#include -#include - -// NCN5120 -//#define NCN5120 - -// services Host -> Controller : -// internal commands, device specific -#define U_RESET_REQ 0x01 -#define U_STATE_REQ 0x02 -#define U_SET_BUSY_REQ 0x03 -#define U_QUIT_BUSY_REQ 0x04 -#define U_BUSMON_REQ 0x05 -#define U_SET_ADDRESS_REQ 0xF1 // different on TP-UART -#define U_SET_REPETITION_REQ 0xF2 -#define U_L_DATA_OFFSET_REQ 0x08 //-0x0C -#define U_SYSTEM_STATE 0x0D -#define U_STOP_MODE_REQ 0x0E -#define U_EXIT_STOP_MODE_REQ 0x0F -#define U_ACK_REQ 0x10 //-0x17 -#define U_CONFIGURE_REQ 0x18 -#define U_INT_REG_WR_REQ 0x28 -#define U_INT_REG_RD_REQ 0x38 -#define U_POLLING_STATE_REQ 0xE0 - -//knx transmit data commands -#define U_L_DATA_START_CONT_REQ 0x80 //-0xBF -#define U_L_DATA_END_REQ 0x40 //-0x7F - -//serices to host controller - -// DLL services (device is transparent) -#define L_DATA_STANDARD_IND 0x90 -#define L_DATA_EXTENDED_IND 0x10 -#define L_DATA_MASK 0xD3 -#define L_POLL_DATA_IND 0xF0 - -// acknowledge services (device is transparent in bus monitor mode) -#define L_ACKN_IND 0x00 -#define L_ACKN_MASK 0x33 -#define L_DATA_CON 0x0B -#define L_DATA_CON_MASK 0x7F -#define SUCCESS 0x80 - -// control services, device specific -#define U_RESET_IND 0x03 -#define U_STATE_IND 0x07 -#define SLAVE_COLLISION 0x80 -#define RECEIVE_ERROR 0x40 -#define TRANSMIT_ERROR 0x20 -#define PROTOCOL_ERROR 0x10 -#define TEMPERATURE_WARNING 0x08 -#define U_FRAME_STATE_IND 0x13 -#define U_FRAME_STATE_MASK 0x17 -#define PARITY_BIT_ERROR 0x80 -#define CHECKSUM_LENGTH_ERROR 0x40 -#define TIMING_ERROR 0x20 -#define U_CONFIGURE_IND 0x01 -#define U_CONFIGURE_MASK 0x83 -#define AUTO_ACKNOWLEDGE 0x20 -#define AUTO_POLLING 0x10 -#define CRC_CCITT 0x80 -#define FRAME_END_WITH_MARKER 0x40 -#define U_FRAME_END_IND 0xCB -#define U_STOP_MODE_IND 0x2B -#define U_SYSTEM_STAT_IND 0x4B - -//loop states -#define IDLE 0 -#define RX_FIRST_BYTE 1 -#define RX_L_DATA 2 -#define RX_WAIT_DATA_CON 3 -#define TX_FRAME 4 - -#define BYTE_TIMEOUT 10 //milli seconds -#define CONFIRM_TIMEOUT 500 //milli seconds -#define RESET_TIMEOUT 100 //milli seconds - -void TpUartDataLinkLayer::loop() -{ - - _receiveBuffer[0] = 0x29; - _receiveBuffer[1] = 0; - uint8_t* buffer = _receiveBuffer + 2; - uint8_t rxByte; - - if (!_enabled) - return; - - switch (_loopState) - { - case IDLE: - if (_platform.uartAvailable()) - { - _loopState = RX_FIRST_BYTE; - } - else - { - if (!_waitConfirm && !isTxQueueEmpty()) - { - loadNextTxFrame(); - _loopState = TX_FRAME; - } - } - break; - case TX_FRAME: - if (sendSingleFrameByte() == false) - { - _waitConfirm = true; - _waitConfirmStartTime = millis(); - _loopState = IDLE; - } - break; - case RX_FIRST_BYTE: - rxByte = _platform.readUart(); - _lastByteRxTime = millis(); - _RxByteCnt = 0; - _xorSum = 0; - if ((rxByte & L_DATA_MASK) == L_DATA_STANDARD_IND) - { - buffer[_RxByteCnt++] = rxByte; - _xorSum ^= rxByte; - _RxByteCnt++; //convert to L_DATA_EXTENDED - _convert = true; - _loopState = RX_L_DATA; - break; - } - else if ((rxByte & L_DATA_MASK) == L_DATA_EXTENDED_IND) - { - buffer[_RxByteCnt++] = rxByte; - _xorSum ^= rxByte; - _convert = false; - _loopState = RX_L_DATA; - break; - } - else if ((rxByte & L_DATA_CON_MASK) == L_DATA_CON) - { - println("got unexpected L_DATA_CON"); - } - else if (rxByte == L_POLL_DATA_IND) - { - // not sure if this can happen - println("got L_POLL_DATA_IND"); - } - else if ((rxByte & L_ACKN_MASK) == L_ACKN_IND) - { - // this can only happen in bus monitor mode - println("got L_ACKN_IND"); - } - else if (rxByte == U_RESET_IND) - { - println("got U_RESET_IND"); - } - else if ((rxByte & U_STATE_IND) == U_STATE_IND) - { - print("got U_STATE_IND: 0x"); - print(rxByte, HEX); - println(); - } - else if ((rxByte & U_FRAME_STATE_MASK) == U_FRAME_STATE_IND) - { - print("got U_FRAME_STATE_IND: 0x"); - print(rxByte, HEX); - println(); - } - else if ((rxByte & U_CONFIGURE_MASK) == U_CONFIGURE_IND) - { - print("got U_CONFIGURE_IND: 0x"); - print(rxByte, HEX); - println(); - } - else if (rxByte == U_FRAME_END_IND) - { - println("got U_FRAME_END_IND"); - } - else if (rxByte == U_STOP_MODE_IND) - { - println("got U_STOP_MODE_IND"); - } - else if (rxByte == U_SYSTEM_STAT_IND) - { - print("got U_SYSTEM_STAT_IND: 0x"); - while (true) - { - int tmp = _platform.readUart(); - if (tmp < 0) - continue; - - print(tmp, HEX); - break; - } - println(); - } - else - { - print("got UNEXPECTED: 0x"); - print(rxByte, HEX); - println(); - } - _loopState = IDLE; - break; - case RX_L_DATA: - if (millis() - _lastByteRxTime > BYTE_TIMEOUT) - { - _RxByteCnt = 0; - _loopState = IDLE; - println("Timeout during RX_L_DATA"); - break; - } - if (!_platform.uartAvailable()) - break; - _lastByteRxTime = millis(); - rxByte = _platform.readUart(); - - if (_RxByteCnt == MAX_KNX_TELEGRAM_SIZE) - { - _loopState = IDLE; - println("invalid telegram size"); - } - else - { - buffer[_RxByteCnt++] = rxByte; - } - - if (_RxByteCnt == 7) - { - //Destination Address + payload available - _xorSum ^= rxByte; - //check if echo - if (!((buffer[0] ^ _sendBuffer[0]) & ~0x20) && !memcmp(buffer + _convert + 1, _sendBuffer + 1, 5)) - { //ignore repeated bit of control byte - _isEcho = true; - } - else - { - _isEcho = false; - } - - //convert into Extended.ind - if (_convert) - { - uint8_t payloadLength = buffer[6] & 0x0F; - buffer[1] = buffer[6] & 0xF0; - buffer[6] = payloadLength; - } - - if (!_isEcho) - { - uint8_t c = 0x10; - //ceck if individual or group address - if ((buffer[6] & 0x80) == 0) - { - //individual - if (_deviceObject.induvidualAddress() == getWord(buffer + 4)) - { - c |= 0x01; - } - } - else - { - //group - if (_groupAddressTable.contains(getWord(buffer + 4)) || getWord(buffer + 4) == 0) - { - c |= 0x01; - } - } - _platform.writeUart(c); - } - } - else if (_RxByteCnt == buffer[6] + 7 + 2) - { - //complete Frame received, payloadLength+1 for TCPI +1 for CRC - if (rxByte == (uint8_t)(~_xorSum)) - { - //check if crc is correct - if (_isEcho && _sendBuffer != NULL) - { - //check if it is realy an echo, rx_crc = tx_crc - if (rxByte == _sendBuffer[_sendBufferLength - 1]) - _isEcho = true; - else - _isEcho = false; - } - if (_isEcho) - { - _loopState = RX_WAIT_DATA_CON; - } - else - { - frameBytesReceived(_receiveBuffer, _RxByteCnt + 2); - _loopState = IDLE; - } - } - else - { - println("frame with invalid crc ignored"); - _loopState = IDLE; - } - } - else - { - _xorSum ^= rxByte; - } - break; - case RX_WAIT_DATA_CON: - if (!_platform.uartAvailable()) - break; - rxByte = _platform.readUart(); - _lastByteRxTime = millis(); - if ((rxByte & L_DATA_CON_MASK) == L_DATA_CON) - { - //println("L_DATA_CON received"); - dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, ((rxByte & SUCCESS) > 0)); - _waitConfirm = false; - delete[] _sendBuffer; - _sendBuffer = 0; - _sendBufferLength = 0; - _loopState = IDLE; - } - else - { - //should not happen - println("expected L_DATA_CON not received"); - dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, false); - _waitConfirm = false; - delete[] _sendBuffer; - _sendBuffer = 0; - _sendBufferLength = 0; - _loopState = IDLE; - } - break; - default: - break; - } - - if (_waitConfirm) - { - if (millis() - _waitConfirmStartTime > CONFIRM_TIMEOUT) - { - println("L_DATA_CON not received within expected time"); - uint8_t cemiBuffer[MAX_KNX_TELEGRAM_SIZE]; - cemiBuffer[0] = 0x29; - cemiBuffer[1] = 0; - memcpy((cemiBuffer + 2), _sendBuffer, _sendBufferLength); - dataConBytesReceived(cemiBuffer, _sendBufferLength + 2, false); - _waitConfirm = false; - delete[] _sendBuffer; - _sendBuffer = 0; - _sendBufferLength = 0; - if (_loopState == RX_WAIT_DATA_CON) - _loopState = IDLE; - } - } -} - -bool TpUartDataLinkLayer::sendFrame(CemiFrame& frame) -{ - if (!_enabled) - { - dataConReceived(frame, false); - return false; - } - - addFrameTxQueue(frame); - return true; -} - -bool TpUartDataLinkLayer::resetChip() -{ - uint8_t cmd = U_RESET_REQ; - _platform.writeUart(cmd); - _waitConfirmStartTime = millis(); - while (true) - { - int resp = _platform.readUart(); - if (resp == U_RESET_IND) - return true; - else if (millis() - _waitConfirmStartTime > RESET_TIMEOUT) - return false; - } -} - -void TpUartDataLinkLayer::stopChip() -{ -#ifdef NCN5120 - uint8_t cmd = U_STOP_MODE_REQ; - _platform.writeUart(cmd); - while (true) - { - int resp = _platform.readUart(); - if (resp == U_STOP_MODE_IND) - break; - } -#endif -} - -TpUartDataLinkLayer::TpUartDataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, - NetworkLayer& layer, Platform& platform) - : DataLinkLayer(devObj, addrTab, layer, platform) -{ -} - -void TpUartDataLinkLayer::frameBytesReceived(uint8_t* buffer, uint16_t length) -{ - //printHex("=>", buffer, length); - CemiFrame frame(buffer, length); - - frameRecieved(frame); -} - -void TpUartDataLinkLayer::dataConBytesReceived(uint8_t* buffer, uint16_t length, bool success) -{ - //printHex("=>", buffer, length); - CemiFrame frame(buffer, length); - dataConReceived(frame, success); -} - -void TpUartDataLinkLayer::enabled(bool value) -{ - if (value && !_enabled) - { - _platform.setupUart(); - - if (resetChip()){ - _enabled = true; - print("ownaddr "); - println(_deviceObject.induvidualAddress(), HEX); - } - else{ - _enabled = false; - println("ERROR, TPUART not responding"); - } - return; - } - - if (!value && _enabled) - { - _enabled = false; - stopChip(); - _platform.closeUart(); - return; - } -} - -bool TpUartDataLinkLayer::enabled() const -{ - return _enabled; -} - -bool TpUartDataLinkLayer::sendSingleFrameByte() -{ - uint8_t cmd[2]; - uint8_t idx = _TxByteCnt / 64; - - if (_sendBuffer == NULL) - return false; - - if (_TxByteCnt < _sendBufferLength) - { - if (idx != _oldIdx) - { - _oldIdx = idx; - cmd[0] = U_L_DATA_OFFSET_REQ | idx; - _platform.writeUart(cmd, 1); - } - - if (_TxByteCnt != _sendBufferLength - 1) - cmd[0] = U_L_DATA_START_CONT_REQ | _TxByteCnt; - else - cmd[0] = U_L_DATA_END_REQ | _TxByteCnt; - - cmd[1] = _sendBuffer[_TxByteCnt]; - - _platform.writeUart(cmd, 2); - _TxByteCnt++; - return true; - } - else - { - _TxByteCnt = 0; - return false; - } -} - -void TpUartDataLinkLayer::addFrameTxQueue(CemiFrame& frame) -{ - - _tx_queue_frame_t* tx_frame = new _tx_queue_frame_t; - tx_frame->length = frame.telegramLengthtTP(); - tx_frame->data = new uint8_t[tx_frame->length]; - tx_frame->next = NULL; - frame.fillTelegramTP(tx_frame->data); - - if (_tx_queue.back == NULL) - { - _tx_queue.front = _tx_queue.back = tx_frame; - } - else - { - _tx_queue.back->next = tx_frame; - _tx_queue.back = tx_frame; - } -} - -bool TpUartDataLinkLayer::isTxQueueEmpty() -{ - if (_tx_queue.front == NULL) - { - return true; - } - return false; -} - -void TpUartDataLinkLayer::loadNextTxFrame() -{ - if (_tx_queue.front == NULL) - { - return; - } - _tx_queue_frame_t* tx_frame = _tx_queue.front; - _sendBuffer = tx_frame->data; - _sendBufferLength = tx_frame->length; - _tx_queue.front = tx_frame->next; - - if (_tx_queue.front == NULL) - { - _tx_queue.back = NULL; - } - delete tx_frame; -} -#endif \ No newline at end of file +#include "tpuart_data_link_layer.h" +#ifdef USE_TP +#include "bits.h" +#include "platform.h" +#include "device_object.h" +#include "address_table_object.h" +#include "cemi_frame.h" + +#include +#include + +// NCN5120 +//#define NCN5120 + +// services Host -> Controller : +// internal commands, device specific +#define U_RESET_REQ 0x01 +#define U_STATE_REQ 0x02 +#define U_SET_BUSY_REQ 0x03 +#define U_QUIT_BUSY_REQ 0x04 +#define U_BUSMON_REQ 0x05 +#define U_SET_ADDRESS_REQ 0xF1 // different on TP-UART +#define U_SET_REPETITION_REQ 0xF2 +#define U_L_DATA_OFFSET_REQ 0x08 //-0x0C +#define U_SYSTEM_STATE 0x0D +#define U_STOP_MODE_REQ 0x0E +#define U_EXIT_STOP_MODE_REQ 0x0F +#define U_ACK_REQ 0x10 //-0x17 +#define U_CONFIGURE_REQ 0x18 +#define U_INT_REG_WR_REQ 0x28 +#define U_INT_REG_RD_REQ 0x38 +#define U_POLLING_STATE_REQ 0xE0 + +//knx transmit data commands +#define U_L_DATA_START_CONT_REQ 0x80 //-0xBF +#define U_L_DATA_END_REQ 0x40 //-0x7F + +//serices to host controller + +// DLL services (device is transparent) +#define L_DATA_STANDARD_IND 0x90 +#define L_DATA_EXTENDED_IND 0x10 +#define L_DATA_MASK 0xD3 +#define L_POLL_DATA_IND 0xF0 + +// acknowledge services (device is transparent in bus monitor mode) +#define L_ACKN_IND 0x00 +#define L_ACKN_MASK 0x33 +#define L_DATA_CON 0x0B +#define L_DATA_CON_MASK 0x7F +#define SUCCESS 0x80 + +// control services, device specific +#define U_RESET_IND 0x03 +#define U_STATE_IND 0x07 +#define SLAVE_COLLISION 0x80 +#define RECEIVE_ERROR 0x40 +#define TRANSMIT_ERROR 0x20 +#define PROTOCOL_ERROR 0x10 +#define TEMPERATURE_WARNING 0x08 +#define U_FRAME_STATE_IND 0x13 +#define U_FRAME_STATE_MASK 0x17 +#define PARITY_BIT_ERROR 0x80 +#define CHECKSUM_LENGTH_ERROR 0x40 +#define TIMING_ERROR 0x20 +#define U_CONFIGURE_IND 0x01 +#define U_CONFIGURE_MASK 0x83 +#define AUTO_ACKNOWLEDGE 0x20 +#define AUTO_POLLING 0x10 +#define CRC_CCITT 0x80 +#define FRAME_END_WITH_MARKER 0x40 +#define U_FRAME_END_IND 0xCB +#define U_STOP_MODE_IND 0x2B +#define U_SYSTEM_STAT_IND 0x4B + +//loop states +#define IDLE 0 +#define RX_FIRST_BYTE 1 +#define RX_L_DATA 2 +#define RX_WAIT_DATA_CON 3 +#define TX_FRAME 4 + +#define BYTE_TIMEOUT 10 //milli seconds +#define CONFIRM_TIMEOUT 500 //milli seconds +#define RESET_TIMEOUT 100 //milli seconds + +void TpUartDataLinkLayer::loop() +{ + + _receiveBuffer[0] = 0x29; + _receiveBuffer[1] = 0; + uint8_t* buffer = _receiveBuffer + 2; + uint8_t rxByte; + + if (!_enabled) + { + if (millis() - _lastResetChipTime > 1000) + { + //reset chip every 1 seconds + _lastResetChipTime = millis(); + _enabled = resetChip(); + } + } + + if (!_enabled) + return; + + switch (_loopState) + { + case IDLE: + if (_platform.uartAvailable()) + { + _loopState = RX_FIRST_BYTE; + } + else + { + if (!_waitConfirm && !isTxQueueEmpty()) + { + loadNextTxFrame(); + _loopState = TX_FRAME; + } + } + break; + case TX_FRAME: + if (sendSingleFrameByte() == false) + { + _waitConfirm = true; + _waitConfirmStartTime = millis(); + _loopState = IDLE; + } + break; + case RX_FIRST_BYTE: + rxByte = _platform.readUart(); + _lastByteRxTime = millis(); + _RxByteCnt = 0; + _xorSum = 0; + if ((rxByte & L_DATA_MASK) == L_DATA_STANDARD_IND) + { + buffer[_RxByteCnt++] = rxByte; + _xorSum ^= rxByte; + _RxByteCnt++; //convert to L_DATA_EXTENDED + _convert = true; + _loopState = RX_L_DATA; + break; + } + else if ((rxByte & L_DATA_MASK) == L_DATA_EXTENDED_IND) + { + buffer[_RxByteCnt++] = rxByte; + _xorSum ^= rxByte; + _convert = false; + _loopState = RX_L_DATA; + break; + } + else if ((rxByte & L_DATA_CON_MASK) == L_DATA_CON) + { + println("got unexpected L_DATA_CON"); + } + else if (rxByte == L_POLL_DATA_IND) + { + // not sure if this can happen + println("got L_POLL_DATA_IND"); + } + else if ((rxByte & L_ACKN_MASK) == L_ACKN_IND) + { + // this can only happen in bus monitor mode + println("got L_ACKN_IND"); + } + else if (rxByte == U_RESET_IND) + { + println("got U_RESET_IND"); + } + else if ((rxByte & U_STATE_IND) == U_STATE_IND) + { + print("got U_STATE_IND: 0x"); + print(rxByte, HEX); + println(); + } + else if ((rxByte & U_FRAME_STATE_MASK) == U_FRAME_STATE_IND) + { + print("got U_FRAME_STATE_IND: 0x"); + print(rxByte, HEX); + println(); + } + else if ((rxByte & U_CONFIGURE_MASK) == U_CONFIGURE_IND) + { + print("got U_CONFIGURE_IND: 0x"); + print(rxByte, HEX); + println(); + } + else if (rxByte == U_FRAME_END_IND) + { + println("got U_FRAME_END_IND"); + } + else if (rxByte == U_STOP_MODE_IND) + { + println("got U_STOP_MODE_IND"); + } + else if (rxByte == U_SYSTEM_STAT_IND) + { + print("got U_SYSTEM_STAT_IND: 0x"); + while (true) + { + int tmp = _platform.readUart(); + if (tmp < 0) + continue; + + print(tmp, HEX); + break; + } + println(); + } + else + { + print("got UNEXPECTED: 0x"); + print(rxByte, HEX); + println(); + } + _loopState = IDLE; + break; + case RX_L_DATA: + if (millis() - _lastByteRxTime > BYTE_TIMEOUT) + { + _RxByteCnt = 0; + _loopState = IDLE; + println("Timeout during RX_L_DATA"); + break; + } + if (!_platform.uartAvailable()) + break; + _lastByteRxTime = millis(); + rxByte = _platform.readUart(); + + if (_RxByteCnt == MAX_KNX_TELEGRAM_SIZE) + { + _loopState = IDLE; + println("invalid telegram size"); + } + else + { + buffer[_RxByteCnt++] = rxByte; + } + + if (_RxByteCnt == 7) + { + //Destination Address + payload available + _xorSum ^= rxByte; + //check if echo + if (!((buffer[0] ^ _sendBuffer[0]) & ~0x20) && !memcmp(buffer + _convert + 1, _sendBuffer + 1, 5)) + { //ignore repeated bit of control byte + _isEcho = true; + } + else + { + _isEcho = false; + } + + //convert into Extended.ind + if (_convert) + { + uint8_t payloadLength = buffer[6] & 0x0F; + buffer[1] = buffer[6] & 0xF0; + buffer[6] = payloadLength; + } + + if (!_isEcho) + { + uint8_t c = 0x10; + //ceck if individual or group address + if ((buffer[6] & 0x80) == 0) + { + //individual + if (_deviceObject.induvidualAddress() == getWord(buffer + 4)) + { + c |= 0x01; + } + } + else + { + //group + if (_groupAddressTable.contains(getWord(buffer + 4)) || getWord(buffer + 4) == 0) + { + c |= 0x01; + } + } + _platform.writeUart(c); + } + } + else if (_RxByteCnt == buffer[6] + 7 + 2) + { + //complete Frame received, payloadLength+1 for TCPI +1 for CRC + if (rxByte == (uint8_t)(~_xorSum)) + { + //check if crc is correct + if (_isEcho && _sendBuffer != NULL) + { + //check if it is realy an echo, rx_crc = tx_crc + if (rxByte == _sendBuffer[_sendBufferLength - 1]) + _isEcho = true; + else + _isEcho = false; + } + if (_isEcho) + { + _loopState = RX_WAIT_DATA_CON; + } + else + { + frameBytesReceived(_receiveBuffer, _RxByteCnt + 2); + _loopState = IDLE; + } + } + else + { + println("frame with invalid crc ignored"); + _loopState = IDLE; + } + } + else + { + _xorSum ^= rxByte; + } + break; + case RX_WAIT_DATA_CON: + if (!_platform.uartAvailable()) + break; + rxByte = _platform.readUart(); + _lastByteRxTime = millis(); + if ((rxByte & L_DATA_CON_MASK) == L_DATA_CON) + { + //println("L_DATA_CON received"); + dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, ((rxByte & SUCCESS) > 0)); + _waitConfirm = false; + delete[] _sendBuffer; + _sendBuffer = 0; + _sendBufferLength = 0; + _loopState = IDLE; + } + else + { + //should not happen + println("expected L_DATA_CON not received"); + dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, false); + _waitConfirm = false; + delete[] _sendBuffer; + _sendBuffer = 0; + _sendBufferLength = 0; + _loopState = IDLE; + } + break; + default: + break; + } + + if (_waitConfirm) + { + if (millis() - _waitConfirmStartTime > CONFIRM_TIMEOUT) + { + println("L_DATA_CON not received within expected time"); + uint8_t cemiBuffer[MAX_KNX_TELEGRAM_SIZE]; + cemiBuffer[0] = 0x29; + cemiBuffer[1] = 0; + memcpy((cemiBuffer + 2), _sendBuffer, _sendBufferLength); + dataConBytesReceived(cemiBuffer, _sendBufferLength + 2, false); + _waitConfirm = false; + delete[] _sendBuffer; + _sendBuffer = 0; + _sendBufferLength = 0; + if (_loopState == RX_WAIT_DATA_CON) + _loopState = IDLE; + } + } +} + +bool TpUartDataLinkLayer::sendFrame(CemiFrame& frame) +{ + if (!_enabled) + { + dataConReceived(frame, false); + return false; + } + + addFrameTxQueue(frame); + return true; +} + +bool TpUartDataLinkLayer::resetChip() +{ + uint8_t cmd = U_RESET_REQ; + _platform.writeUart(cmd); + _waitConfirmStartTime = millis(); + while (true) + { + int resp = _platform.readUart(); + if (resp == U_RESET_IND) + return true; + else if (millis() - _waitConfirmStartTime > RESET_TIMEOUT) + return false; + } +} + +void TpUartDataLinkLayer::stopChip() +{ +#ifdef NCN5120 + uint8_t cmd = U_STOP_MODE_REQ; + _platform.writeUart(cmd); + while (true) + { + int resp = _platform.readUart(); + if (resp == U_STOP_MODE_IND) + break; + } +#endif +} + +TpUartDataLinkLayer::TpUartDataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, + NetworkLayer& layer, Platform& platform) + : DataLinkLayer(devObj, addrTab, layer, platform) +{ +} + +void TpUartDataLinkLayer::frameBytesReceived(uint8_t* buffer, uint16_t length) +{ + //printHex("=>", buffer, length); + CemiFrame frame(buffer, length); + + frameRecieved(frame); +} + +void TpUartDataLinkLayer::dataConBytesReceived(uint8_t* buffer, uint16_t length, bool success) +{ + //printHex("=>", buffer, length); + CemiFrame frame(buffer, length); + dataConReceived(frame, success); +} + +void TpUartDataLinkLayer::enabled(bool value) +{ + if (value && !_enabled) + { + _platform.setupUart(); + + if (resetChip()) + { + _enabled = true; + print("ownaddr "); + println(_deviceObject.induvidualAddress(), HEX); + } + else + { + _enabled = false; + println("ERROR, TPUART not responding"); + } + return; + } + + if (!value && _enabled) + { + _enabled = false; + stopChip(); + _platform.closeUart(); + return; + } +} + +bool TpUartDataLinkLayer::enabled() const +{ + return _enabled; +} + +bool TpUartDataLinkLayer::sendSingleFrameByte() +{ + uint8_t cmd[2]; + uint8_t idx = _TxByteCnt / 64; + + if (_sendBuffer == NULL) + return false; + + if (_TxByteCnt < _sendBufferLength) + { + if (idx != _oldIdx) + { + _oldIdx = idx; + cmd[0] = U_L_DATA_OFFSET_REQ | idx; + _platform.writeUart(cmd, 1); + } + + if (_TxByteCnt != _sendBufferLength - 1) + cmd[0] = U_L_DATA_START_CONT_REQ | _TxByteCnt; + else + cmd[0] = U_L_DATA_END_REQ | _TxByteCnt; + + cmd[1] = _sendBuffer[_TxByteCnt]; + + _platform.writeUart(cmd, 2); + _TxByteCnt++; + return true; + } + else + { + _TxByteCnt = 0; + return false; + } +} + +void TpUartDataLinkLayer::addFrameTxQueue(CemiFrame& frame) +{ + + _tx_queue_frame_t* tx_frame = new _tx_queue_frame_t; + tx_frame->length = frame.telegramLengthtTP(); + tx_frame->data = new uint8_t[tx_frame->length]; + tx_frame->next = NULL; + frame.fillTelegramTP(tx_frame->data); + + if (_tx_queue.back == NULL) + { + _tx_queue.front = _tx_queue.back = tx_frame; + } + else + { + _tx_queue.back->next = tx_frame; + _tx_queue.back = tx_frame; + } +} + +bool TpUartDataLinkLayer::isTxQueueEmpty() +{ + if (_tx_queue.front == NULL) + { + return true; + } + return false; +} + +void TpUartDataLinkLayer::loadNextTxFrame() +{ + if (_tx_queue.front == NULL) + { + return; + } + _tx_queue_frame_t* tx_frame = _tx_queue.front; + _sendBuffer = tx_frame->data; + _sendBufferLength = tx_frame->length; + _tx_queue.front = tx_frame->next; + + if (_tx_queue.front == NULL) + { + _tx_queue.back = NULL; + } + delete tx_frame; +} +#endif \ No newline at end of file diff --git a/src/knx/tpuart_data_link_layer.h b/src/knx/tpuart_data_link_layer.h index e60c45c..e84bc3e 100644 --- a/src/knx/tpuart_data_link_layer.h +++ b/src/knx/tpuart_data_link_layer.h @@ -38,6 +38,7 @@ class TpUartDataLinkLayer : public DataLinkLayer uint8_t _xorSum = 0; uint32_t _lastByteRxTime; uint32_t _waitConfirmStartTime; + uint32_t _lastResetChipTime = 0; struct _tx_queue_frame_t {