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/application_layer.cpp b/src/knx/application_layer.cpp
index 579c17d..74f2944 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 b364458..21e1d90 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
protected:
diff --git a/src/knx/bau_systemB.cpp b/src/knx/bau_systemB.cpp
index 6c04edb..c5631cb 100644
--- a/src/knx/bau_systemB.cpp
+++ b/src/knx/bau_systemB.cpp
@@ -56,6 +56,9 @@ void BauSystemB::enabled(bool value)
void BauSystemB::sendNextGroupTelegram()
{
+ if(!configured())
+ return;
+
static uint16_t startIdx = 1;
GroupObjectTableObject& table = _groupObjTable;
diff --git a/src/knx/bits.h b/src/knx/bits.h
index 0308ffe..565d24c 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 getbyte(x,n) (*(((uint8_t*)&(x))+n))
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 5da8fde..84c4f94 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:
@@ -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;
}
@@ -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)
{
@@ -1837,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
+}
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 9e8abac..5fb7f32 100644
--- a/src/knx/interface_object.h
+++ b/src/knx/interface_object.h
@@ -147,9 +147,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.
@@ -184,15 +182,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,};
};
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/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
{
diff --git a/src/knx_facade.cpp b/src/knx_facade.cpp
index 45cdbcc..a26089c 100644
--- a/src/knx_facade.cpp
+++ b/src/knx_facade.cpp
@@ -15,24 +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;
#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 c59b600..44afb4a 100644
--- a/src/knx_facade.h
+++ b/src/knx_facade.h
@@ -17,7 +17,11 @@
#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"
+ #include "knx/bau07B0.h"
#else
#define LED_BUILTIN 0
#include "linux_platform.h"
@@ -331,8 +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
diff --git a/src/stm32_platform.cpp b/src/stm32_platform.cpp
new file mode 100644
index 0000000..4d2d92c
--- /dev/null
+++ b/src/stm32_platform.cpp
@@ -0,0 +1,42 @@
+#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()
+{
+ 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..d8c6faa
--- /dev/null
+++ b/src/stm32_platform.h
@@ -0,0 +1,22 @@
+#ifdef ARDUINO_ARCH_STM32
+#include "arduino_platform.h"
+
+class Stm32Platform : public ArduinoPlatform
+{
+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