diff --git a/examples/knx-433Dio/KNXto433.xml b/examples/knx-433Dio/KNXto433.xml
new file mode 100644
index 0000000..888c1e9
--- /dev/null
+++ b/examples/knx-433Dio/KNXto433.xml
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/knx-433Dio/README.md b/examples/knx-433Dio/README.md
new file mode 100644
index 0000000..31d7ce1
--- /dev/null
+++ b/examples/knx-433Dio/README.md
@@ -0,0 +1,32 @@
+Control Chacon/DIO 433Mhz plug like that: (not an affiliated link just for info)
+https://www.amazon.fr/DiO-Connected-Home-t%C3%A9l%C3%A9command%C3%A9es-t%C3%A9l%C3%A9commande/dp/B005LKMAW0
+
+
+Hardware:
+- Samd21 (gy-samd21)
+- FS 1000A (cheap 433 transmitter)
+- TpUart KNX
+- logic level converter
+- Chacon/DIO 433Mhz plug (must work with every dumb 433mhz plug/remote that support the HomeEasy protocol)
+
+Software
+- change the rfPin variable, compile and tranfert into the samd21 (or any microcontroller)
+- (maybe) adapt THIGH and TLOW in rfCode class for your case.
+
+Before configuring ETS, you need to receive the 433mhz code for each button of your remote.
+Take an arduino UNO, plug the FS1000a receiver, look on github/google to receive the code rc-switch or https://charleslabs.fr/fr/project-Contr%C3%B4le+de+prises+DiO+avec+Arduino (in french), or https://caron.ws/diy-cartes-microcontroleurs/piloter-vos-prises-chacon-rf433mhz-arduino/ ( in french too)
+
+
+for me it's : 1806947472 and 1806947456 for the channel 1 on/off, etc...
+
+Now in ETS put the received 433Mhz code into parameters.
+-> Full Download in ETS and enjoy.
+
+
+
+Feature:
+This code is delay() free, blocking code free (ie: no long while or for loop), to call the knx.loop() as fast as possible.
+
+
+
+
diff --git a/examples/knx-433Dio/knx-433.knxprod b/examples/knx-433Dio/knx-433.knxprod
new file mode 100644
index 0000000..b3d72fc
Binary files /dev/null and b/examples/knx-433Dio/knx-433.knxprod differ
diff --git a/examples/knx-433Dio/knx-433Dio.ino b/examples/knx-433Dio/knx-433Dio.ino
new file mode 100644
index 0000000..841dd6a
--- /dev/null
+++ b/examples/knx-433Dio/knx-433Dio.ino
@@ -0,0 +1,368 @@
+#include
+//#include
+
+//#define DEBUGSERIAL 1
+#ifdef DEBUGSERIAL
+ #define DPRINT(...) SerialUSB.print(__VA_ARGS__)
+ #define DPRINTLN(...) SerialUSB.println(__VA_ARGS__)
+ #include
+ #include
+#else
+ #define DPRINT(...) //now defines a blank line
+ #define DPRINTLN(...) //now defines a blank line
+#endif
+
+#define goButton1 knx.getGroupObject(1)
+#define goButton2 knx.getGroupObject(2)
+#define goButton3 knx.getGroupObject(3)
+#define goButtonAll knx.getGroupObject(4)
+#define goProgMode knx.getGroupObject(5)
+
+//DiOremote myRemote = DiOremote(6);
+
+//void function2();
+//void function1(void (*)());
+//void loop() {
+// function1(function2);
+//}
+
+//Global Const
+const uint8_t ets_startupTimeout[7] = {0, 1, 2, 3, 4, 5, 6};
+const uint16_t ets_timePeriod[7] = {0, 1, 5, 15, 1 * 60, 5 * 60, 15 * 60};
+const uint8_t ets_progMode[7] = {0, 1, 2 * 60, 3 * 60, 4 * 60, 5 * 60, 10 * 60}; //need knxprod update... ?
+const uint8_t ledPin = LED_BUILTIN;
+const uint8_t rfPin = 6;
+
+// //Protocol timing (in us)
+// #define DiOremote_START_FRAME_1 220
+// #define DiOremote_START_FRAME_0 2675
+// #define DiOremote_THIGH 220
+// #define DiOremote_TLOW_0 350 short
+// #define DiOremote_TLOW_1 1400 long
+// #define DiOremote_END_FRAME_1 220
+// #define DiOremote_END_FRAME_0 10600
+
+// Global Variable
+bool progMode = true;
+// bool codeSendindBlock = false;
+
+uint8_t percentCycle = 0; // better to define a global or read knx.paramByte each time... ?
+uint32_t timePeriod = 0; // same here,
+uint32_t timerProgMode = 0; // same here,
+uint32_t ch1_on, ch1_off, ch2_on, ch2_off, ch3_on, ch3_off, chall_on, chall_off;
+
+class RfCode {
+ private:
+ uint8_t _rfPin;
+ uint32_t _codeValueOn;
+ uint32_t _codeValueOff;
+ uint8_t _GOaddress;
+ const uint16_t THIGH = 220, TSTART = 2675, TSHORT = 220, TLONG = 1400, TEND = 10600;
+ uint8_t _loopCount = 0; // fixed ==5
+ bool lastState = false;
+ uint32_t _codePending = 0;
+ uint32_t _codePendingMemory = _codePending;
+ uint8_t _loopPending = 0; // fixed ==32
+ bool _sendMsgPending= false;
+
+ enum PulseStates {
+ PULSE_INIT,
+ PULSE_KEY1, //32 times loop
+ PULSE_KEY2, //32 times loop
+ PULSE_END
+ };
+ PulseStates pulseStates = PULSE_INIT;
+
+ bool pulseSend(const uint16_t delayHigh, const uint16_t delayLow){ //alike state machine?
+
+ static bool initPulse = false;
+ static bool highDone = false;
+ static uint32_t pulseLastTime = 0;
+
+ uint32_t currentTime = micros();
+
+ if (!initPulse){
+ initPulse = true;
+ digitalWrite(_rfPin, HIGH);
+ pulseLastTime = currentTime;
+ }
+ else if (currentTime - pulseLastTime >= delayHigh && !highDone)
+ {
+ digitalWrite(_rfPin, LOW);
+ pulseLastTime = currentTime;
+ highDone = true;
+ }
+ else if (currentTime - pulseLastTime >= delayLow && highDone)
+ {
+ initPulse = false;
+ highDone = false;
+ }
+ return !initPulse;
+ }
+
+ uint16_t TTime(bool invert){
+ uint16_t TTIME;
+
+ if (_codePending & 0x80000000L)// future bug if uint32_t _codePengin > 2^32 / 2 ?
+ {
+ TTIME = invert ? TSHORT : TLONG;
+ }
+ else
+ {
+ TTIME = invert ? TLONG : TSHORT;
+ }
+ return TTIME;
+ }
+
+ public:
+ RfCode(uint8_t rfPin){
+ _rfPin = rfPin;
+ pinMode(_rfPin, OUTPUT);
+ }
+
+// void init(uint8_t addr, uint32_t codeValueOn, uint32_t codeValueOff){ //GroupObject &device, long timeOn){
+// _codeValueOn = codeValueOn;
+// _codeValueOff = codeValueOff;
+// _GOaddress = addr;
+// }
+
+ void setState(bool modeOnOff, uint32_t codeValueOn, uint32_t codeValueOff){
+ if (!_sendMsgPending)
+ {
+ _sendMsgPending = true;
+ _codeValueOn = codeValueOn;
+ _codeValueOff = codeValueOff;
+// _GOaddress = addr;
+
+ if (modeOnOff){
+ _codePending = _codeValueOn;
+// SerialUSB.println(_codePending);
+ }
+ else
+ {
+ _codePending = _codeValueOff;
+// SerialUSB.println(_codePending);
+ }
+ _codePendingMemory = _codePending;
+ }
+ }
+
+// bool getMsgPendingState(){
+// return _sendMsgPending;
+// }
+
+ void loop(){
+ if (_sendMsgPending)
+ {
+ // needed to block setState of another Class, yes FIFO is better...
+// codeSendindBlock = true;
+ if (_loopCount < 5)
+ {
+ switch (pulseStates){
+ case PULSE_INIT:
+ if (pulseSend(THIGH, TSTART)){
+ pulseStates = PULSE_KEY1;
+ }
+ break;
+ case PULSE_KEY1:
+ if (pulseSend(THIGH, TTime(false)))
+ {
+ pulseStates = PULSE_KEY2;
+ }
+ break;
+ case PULSE_KEY2:
+ if (pulseSend(THIGH, TTime(true)))
+ {
+ if (_loopPending < 32){
+ _codePending <<= 1;
+ _loopPending++;
+ pulseStates = PULSE_KEY1; // next loop !
+ }
+ else{ // finish!
+ pulseStates = PULSE_END;
+ }
+ }
+ break;
+ case PULSE_END:
+ if (pulseSend(THIGH, TEND)){
+ _loopCount++;
+ _codePending = _codePendingMemory;
+ _loopPending = 0;
+ pulseStates = PULSE_INIT;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ _loopCount = 0;
+ _sendMsgPending = false;
+// codeSendindBlock = false;
+ }
+ }
+ }
+};
+
+
+class Blinker
+{
+ private:
+ uint8_t ledPin_; // the number of the LED pin
+ uint32_t OnTime = 1000; // milliseconds of on-time
+ uint32_t OffTime = 1000; // milliseconds of off-time
+ bool ledState = LOW; // ledState used to set the LED
+ uint32_t previousMillis; // will store last time LED was updated
+
+ void setOutput(bool state_, uint32_t currentMillis_){
+ ledState = state_;
+ previousMillis = currentMillis_;
+ digitalWrite(ledPin_, state_);
+ }
+
+ public:
+ Blinker(uint8_t pin)
+ {
+ ledPin_ = pin;
+ pinMode(ledPin_, OUTPUT);
+ previousMillis = 0;
+ }
+
+ void set(uint32_t on, uint32_t off){
+ OnTime = on;
+ OffTime = off;
+ }
+
+ void loop(){
+ uint32_t currentMillis = millis();
+
+ if((ledState == HIGH) && (currentMillis - previousMillis >= OnTime))
+ {
+ setOutput(LOW, currentMillis);
+ }
+ else if ((ledState == LOW) && (currentMillis - previousMillis >= OffTime))
+ {
+ setOutput(HIGH, currentMillis);
+ }
+ }
+};
+
+RfCode button = RfCode(5);
+
+Blinker led = Blinker(ledPin);
+
+
+void callBackButton1(GroupObject& go){
+ button.setState((bool)go.value(), ch1_on, ch1_off);
+}
+void callBackButton2(GroupObject& go){
+ button.setState((bool)go.value(), ch2_on, ch2_off);
+}
+void callBackButton3(GroupObject& go){
+ button.setState((bool)go.value(), ch3_on, ch3_off);
+}
+void callBackButtonAll(GroupObject& go){
+ button.setState((bool)go.value(), chall_on, ch3_off);
+}
+void callBackProgMode(GroupObject& go){
+ progMode = (bool)go.value();
+}
+
+void setup() {
+
+// #ifdef DEBUGSERIAL
+// SerialUSB.begin(9600);
+// while (!SerialUSB) { //wait for DEBUGING
+// ; // wait for serial port to connect. Needed for native USB port only
+// }
+// ArduinoPlatform::SerialDebug = &SerialUSB;
+// #endif
+
+ randomSeed(millis());
+ // knx.bau().deviceObject().individualAddress(1);
+ knx.readMemory();
+
+ if (knx.configured())
+ {
+ DPRINT("Setup: KNX Configuration...");
+
+ progMode = false; // don't need to put device in progMode.
+ int confStartupTime = ets_startupTimeout[knx.paramByte(0)] * 1000;
+ delay(confStartupTime); // the only delay used, why make a withoutDelay function for that?
+
+ timePeriod = ets_timePeriod[knx.paramByte(1)] * 1000;
+// timerProgMode = ets_progMode[knx.paramByte(34)] * 1000;
+
+ ch1_on = knx.paramInt(2);
+ ch1_off = knx.paramInt(6);
+ goButton1.callback(callBackButton1);
+ goButton1.dataPointType(DPT_Switch);
+
+ ch2_on = knx.paramInt(10);
+ ch2_off = knx.paramInt(14);
+ goButton2.callback(callBackButton2);
+ goButton2.dataPointType(DPT_Switch);
+
+ ch3_on = knx.paramInt(18);
+ ch3_off = knx.paramInt(22);
+ goButton3.callback(callBackButton3);
+ goButton3.dataPointType(DPT_Switch);
+
+ chall_on = knx.paramByte(26);
+ chall_off = knx.paramByte(30);
+ goButtonAll.callback(callBackButtonAll);
+ goButtonAll.dataPointType(DPT_Switch);
+
+ goProgMode.callback(callBackProgMode);
+ goProgMode.dataPointType(DPT_Trigger);
+
+ DPRINTLN("Finished");
+ }
+
+ knx.ledPin(5);
+ knx.ledPinActiveOn(HIGH);
+ knx.buttonPin(9);
+
+ knx.start();
+ led.set(2000, 2000);
+}
+
+void loop()
+{
+ knx.loop();
+ led.loop();
+ if (knx.configured() && !progMode)
+ {
+ button.loop();
+ }
+ else if (progMode)
+ {
+ prodModeLoop();
+ }
+
+}
+
+void prodModeLoop(){ // run Only if progMode triggered ( at start or callback)
+
+ const uint32_t timerProgMode = ( 15 * 60 * 1000 ) ; // 15min
+ static uint32_t timerProgPrevMillis = 0;
+
+ if (!knx.progMode())
+ {
+ knx.progMode(true);
+ led.set(500, 500);
+ timerProgPrevMillis = millis();
+ DPRINTLN("progModeLoop Start");
+ }
+ else
+ {
+ if (millis() - timerProgPrevMillis > timerProgMode) {
+ knx.progMode(false);
+ goProgMode.value(false);
+ progMode = 0;
+ led.set(100, 100); // panic!
+ DPRINTLN("progModeLoop Stop");
+ }
+ }
+}
diff --git a/examples/knx-bme680/knx-bme680.ino b/examples/knx-bme680/knx-bme680.ino
index b6deb6d..332bddf 100644
--- a/examples/knx-bme680/knx-bme680.ino
+++ b/examples/knx-bme680/knx-bme680.ino
@@ -25,7 +25,7 @@
void checkIaqSensorStatus(void);
void errLeds(void);
uint8_t* saveBme680State(uint8_t* buffer);
-uint8_t* loadBme680State(uint8_t* buffer);
+const uint8_t* loadBme680State(const uint8_t* buffer);
void triggerCallback(GroupObject& go);
void updateState();
@@ -53,6 +53,10 @@ void setup(void)
wifiManager.autoConnect("knx-bme680");
#endif
+ // set save and restore callbacks
+ knx.setSaveCallback(saveBme680State);
+ knx.setRestoreCallback(loadBme680State);
+
// read adress table, association table, groupobject table and parameters from eeprom
knx.readMemory();
@@ -60,7 +64,6 @@ void setup(void)
if(knx.configured())
goTriggerSample.callback(triggerCallback);
-
// Configure Wire pins before this call if needed.
Wire.begin();
// depends on sensor board. Try BME680_I2C_ADDR_PRIMARY if it doen't work.
@@ -87,9 +90,6 @@ void setup(void)
BSEC_OUTPUT_GAS_PERCENTAGE
};
- knx.setSaveCallback(saveBme680State);
- knx.setRestoreCallback(loadBme680State);
-
if (knx.configured())
{
cyclSend = knx.paramInt(0);
@@ -214,7 +214,7 @@ void errLeds(void)
delay(100);
}
-uint8_t* loadBme680State(uint8_t* buffer)
+const uint8_t* loadBme680State(const uint8_t* buffer)
{
// Existing state in EEPROM
Serial.println("Reading state from EEPROM");
diff --git a/examples/knx-demo-smal-go/knx-demo.ino b/examples/knx-demo-smal-go/knx-demo.ino
new file mode 100644
index 0000000..52fb386
--- /dev/null
+++ b/examples/knx-demo-smal-go/knx-demo.ino
@@ -0,0 +1,129 @@
+#include
+
+#ifdef ARDUINO_ARCH_ESP8266
+#include
+#endif
+
+/*****************************************
+ * changes necessary for SMALL_GROUPOBJECT
+ * are commented with //**
+ * This project can be used with any
+ * of the knxprod files of the original
+ * knx-demo project.
+ *****************************************/
+
+// create named references for easy access to group objects
+#define goCurrent knx.getGroupObject(1)
+#define goMax knx.getGroupObject(2)
+#define goMin knx.getGroupObject(3)
+#define goReset knx.getGroupObject(4)
+
+float currentValue = 0;
+float maxValue = 0;
+float minValue = RAND_MAX;
+long lastsend = 0;
+
+void measureTemp()
+{
+ long now = millis();
+ if ((now - lastsend) < 2000)
+ return;
+
+ lastsend = now;
+ int r = rand();
+ currentValue = (r * 1.0) / (RAND_MAX * 1.0);
+ currentValue *= 100 * 100;
+
+ // write new value to groupobject
+ goCurrent.value(currentValue, DPT_Value_Temp); //** each value access needs to done with according DPT parameter
+
+ if (currentValue > maxValue)
+ {
+ maxValue = currentValue;
+ goMax.value(maxValue, DPT_Value_Temp); //** each value access needs to done with according DPT parameter
+ }
+
+ if (currentValue < minValue)
+ {
+ minValue = currentValue;
+ goMin.value(minValue, DPT_Value_Temp); //** each value access needs to done with according DPT parameter
+ }
+}
+
+// callback from reset-GO
+void resetCallback(GroupObject& go)
+{
+ //** callbacks are now handled in the class, not per instance,
+ //** this means, we have to check, which GroupObject is calling back
+ if (go.asap() == goReset.asap())
+ {
+ if (go.value(DPT_Trigger)) //** each value access needs to done with according DPT parameter
+ {
+ maxValue = 0;
+ minValue = 10000;
+ }
+ }
+}
+
+void setup()
+{
+ Serial.begin(115200);
+ ArduinoPlatform::SerialDebug = &Serial;
+
+ randomSeed(millis());
+
+#ifdef ARDUINO_ARCH_ESP8266
+ WiFiManager wifiManager;
+ wifiManager.autoConnect("knx-demo");
+#endif
+
+ // read adress table, association table, groupobject table and parameters from eeprom
+ knx.readMemory();
+
+ // print values of parameters if device is already configured
+ if (knx.configured())
+ {
+ // register callback for reset GO
+ GroupObject::classCallback(resetCallback); //** callbacks are now handled per class, not per instance
+ //** there is no global assignment of DPT for GroupObjects
+ // goReset.dataPointType(DPT_Trigger);
+ // goCurrent.dataPointType(DPT_Value_Temp);
+ // goMin.dataPointType(DPT_Value_Temp);
+ // goMax.dataPointType(DPT_Value_Temp);
+
+ Serial.print("Timeout: ");
+ Serial.println(knx.paramByte(0));
+ Serial.print("Zykl. senden: ");
+ Serial.println(knx.paramByte(1));
+ Serial.print("Min/Max senden: ");
+ Serial.println(knx.paramByte(2));
+ Serial.print("Aenderung senden: ");
+ Serial.println(knx.paramByte(3));
+ Serial.print("Abgleich: ");
+ Serial.println(knx.paramByte(4));
+ }
+
+ // pin or GPIO the programming led is connected to. Default is LED_BUILTIN
+ // knx.ledPin(LED_BUILTIN);
+ // is the led active on HIGH or low? Default is LOW
+ // knx.ledPinActiveOn(HIGH);
+ // pin or GPIO programming button is connected to. Default is 0
+ // knx.buttonPin(0);
+ // Is the interrup created in RISING or FALLING signal? Default is RISING
+ // knx.buttonPinInterruptOn(FALLING);
+
+ // start the framework.
+ knx.start();
+}
+
+void loop()
+{
+ // don't delay here to much. Otherwise you might lose packages or mess up the timing with ETS
+ knx.loop();
+
+ // only run the application code if the device was configured with ETS
+ if (!knx.configured())
+ return;
+
+ measureTemp();
+}
\ No newline at end of file
diff --git a/examples/knx-demo-smal-go/platformio.ini b/examples/knx-demo-smal-go/platformio.ini
new file mode 100644
index 0000000..a919602
--- /dev/null
+++ b/examples/knx-demo-smal-go/platformio.ini
@@ -0,0 +1,120 @@
+;PlatformIO Project Configuration File
+;
+; Build options: build flags, source filter
+; Upload options: custom upload port, speed and extra flags
+; Library options: dependencies, extra library storages
+; Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+[platformio]
+; We have to keep libdeps dir out the project directory otherwise,
+; library scanner seems to have issues so compilation fails
+libdeps_dir = /tmp/libdeps
+src_dir = .
+
+;--- SAMD --------------------------------------------------
+; SMALL_GROUPOBJECT just tested with TP on SAMD, but should work also in other environments
+[env:zeroUSB]
+platform = atmelsam
+board = zeroUSB
+framework = arduino
+; We consider that the this projects is opened within its project directory
+; while working with VS Code.
+lib_extra_dirs = ../../../
+
+lib_deps =
+ SPI
+ https://github.com/thelsing/FlashStorage.git
+ knx
+
+build_flags =
+ -DMASK_VERSION=0x07B0
+ -DSMALL_GROUPOBJECT
+ -Wno-unknown-pragmas
+
+; [env:adafruit_feather_m0_rf]
+; platform = atmelsam
+; board = adafruit_feather_m0
+; framework = arduino
+; ; We consider that the this projects is opened within its project directory
+; ; while working with VS Code.
+; lib_extra_dirs = ../../../
+
+; lib_deps =
+; SPI
+; https://github.com/thelsing/FlashStorage.git
+; knx
+
+; build_flags =
+; -DMASK_VERSION=0x27B0
+; -Wno-unknown-pragmas
+;-----------------------------------------------------------
+
+
+;--- ESP8266 -----------------------------------------------
+#[env:nodemcuv2_ip]
+#platform = espressif8266
+#board = nodemcuv2
+#framework = arduino
+; We consider that the this projects is opened within its project directory
+; while working with VS Code.
+#lib_extra_dirs = ../../../
+
+#lib_deps =
+# WifiManager
+# knx
+
+#build_flags =
+# -DMASK_VERSION=0x57B0
+# -Wno-unknown-pragmas
+
+; [env:nodemcuv2_tp]
+; platform = espressif8266
+; board = nodemcuv2
+; framework = arduino
+; ; We consider that the this projects is opened within its project directory
+; ; while working with VS Code.
+; lib_extra_dirs = ../../../
+
+; lib_deps =
+; WifiManager
+; knx
+
+; build_flags =
+; -DMASK_VERSION=0x07B0
+; -Wno-unknown-pragmas
+
+;---------------------------------------------------------
+
+
+;--- ESP32 -----------------------------------------------
+; [env:esp32dev_ip]
+; platform = espressif32
+; board = esp32dev
+; framework = arduino
+; ; We consider that the this projects is opened within its project directory
+; ; while working with VS Code.
+; lib_extra_dirs = ../../../
+
+; lib_deps =
+; knx
+
+; build_flags =
+; -DMASK_VERSION=0x57B0
+; -Wno-unknown-pragmas
+
+; [env:esp32dev_tp]
+; platform = espressif32
+; board = esp32dev
+; framework = arduino
+; ; We consider that the this projects is opened within its project directory
+; ; while working with VS Code.
+; lib_extra_dirs = ../../../
+
+; lib_deps =
+; knx
+
+; build_flags =
+; -DMASK_VERSION=0x07B0
+; -Wno-unknown-pragmas
diff --git a/examples/knx-demo/knx-demo.ino b/examples/knx-demo/knx-demo.ino
index f062daf..a72b214 100644
--- a/examples/knx-demo/knx-demo.ino
+++ b/examples/knx-demo/knx-demo.ino
@@ -1,6 +1,7 @@
+#include
#include
-#ifdef ARDUINO_ARCH_ESP8266
+#if MASK_VERSION != 0x07B0 && (defined ARDUINO_ARCH_ESP8266 || defined ARDUINO_ARCH_ESP32)
#include
#endif
@@ -59,7 +60,7 @@ void setup()
randomSeed(millis());
-#ifdef ARDUINO_ARCH_ESP8266
+#if MASK_VERSION != 0x07B0 && (defined ARDUINO_ARCH_ESP8266 || defined ARDUINO_ARCH_ESP32)
WiFiManager wifiManager;
wifiManager.autoConnect("knx-demo");
#endif
diff --git a/examples/knx-demo/platformio-ci.ini b/examples/knx-demo/platformio-ci.ini
index e2b04e2..d2056ac 100644
--- a/examples/knx-demo/platformio-ci.ini
+++ b/examples/knx-demo/platformio-ci.ini
@@ -40,7 +40,7 @@ build_flags =
-DUSE_DATASECURE
[env:nodemcuv2_tp]
-platform = espressif8266
+platform = espressif8266@^2
board = nodemcuv2
framework = arduino
lib_deps =
@@ -61,6 +61,7 @@ platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
+ https://github.com/tzapu/WiFiManager.git
knx
build_flags =
diff --git a/examples/knx-demo/platformio.ini b/examples/knx-demo/platformio.ini
index edd9954..a706ccb 100644
--- a/examples/knx-demo/platformio.ini
+++ b/examples/knx-demo/platformio.ini
@@ -51,7 +51,7 @@ build_flags =
# -Wno-unknown-pragmas
[env:nodemcuv2_tp]
-platform = espressif8266
+platform = espressif8266@^2
board = nodemcuv2
framework = arduino
; We consider that the this projects is opened within its project directory
@@ -59,7 +59,7 @@ framework = arduino
lib_extra_dirs = ../../../
lib_deps =
- WifiManager
+ WifiManager@0.15.0
knx
build_flags =
@@ -79,6 +79,7 @@ framework = arduino
lib_extra_dirs = ../../../
lib_deps =
+ https://github.com/tzapu/WiFiManager.git
knx
build_flags =
diff --git a/examples/knx-linux-coupler/fdsk.cpp b/examples/knx-linux-coupler/fdsk.cpp
index 8d9b28c..bb62d57 100644
--- a/examples/knx-linux-coupler/fdsk.cpp
+++ b/examples/knx-linux-coupler/fdsk.cpp
@@ -82,7 +82,7 @@ int FdskCalculator::toBase32(uint8_t* in, long length, uint8_t*& out, bool usePa
int next = 1;
int bitsLeft = 8;
- while (count < bufSize && (bitsLeft > 0 || next < length))
+ while (bitsLeft > 0 || next < length)
{
if (bitsLeft < 5)
{
diff --git a/examples/knx-linux/fdsk.cpp b/examples/knx-linux/fdsk.cpp
index 8d9b28c..bb62d57 100644
--- a/examples/knx-linux/fdsk.cpp
+++ b/examples/knx-linux/fdsk.cpp
@@ -82,7 +82,7 @@ int FdskCalculator::toBase32(uint8_t* in, long length, uint8_t*& out, bool usePa
int next = 1;
int bitsLeft = 8;
- while (count < bufSize && (bitsLeft > 0 || next < length))
+ while (bitsLeft > 0 || next < length)
{
if (bitsLeft < 5)
{
diff --git a/examples/knx-pzem004/pzem-004t-v30.ino b/examples/knx-pzem004/pzem-004t-v30.ino
index 2bc92ff..2bf6527 100644
--- a/examples/knx-pzem004/pzem-004t-v30.ino
+++ b/examples/knx-pzem004/pzem-004t-v30.ino
@@ -38,7 +38,7 @@ const uint8_t physicalCount = 6; // voltage,current,power_factor,power,energy,fr
uint8_t percentCycle = 0; // better to define a global or read knx.paramByte each time... ?
uint32_t timePeriod = 0; // same here,
uint8_t resetPeriod = 0; //same here ...
-uint8_t resetEnergy = 0; // and here... disabled/day/week/month
+//uint8_t resetEnergy = 0; // and here... disabled/day/week/month
bool progMode = true;
@@ -54,11 +54,10 @@ struct Physical {
void loop(){
// unsigned long currentMillis = millis();
// Delta Change update as defined in ETS
- int32_t deltaPercent = ( 100 * ( _value - _lastValue ) / _value );
+ float deltaPercent = ( 100 * ( _value - _lastValue ) / _value );
if ( percentCycle != 0 && abs(deltaPercent) >= percentCycle )
{
_trigger = true;
- _lastValue = _value;
}
// Refresh groupAddress value as defined in ETS since last update
@@ -70,6 +69,7 @@ struct Physical {
// UpdateGO but send to bus only if triggered by time or value change percentage
if (_trigger){
knx.getGroupObject(_GOaddr).value(_value, _dpt);
+ _lastValue = _value;
_lastMillis = millis();
_trigger = false;
}else{
@@ -143,7 +143,6 @@ class Blinker
Blinker led = Blinker(ledPin);
-
void callBackProgMode(GroupObject& go){
progMode = (bool)go.value();
}
@@ -172,7 +171,7 @@ void resetCallback(GroupObject& go)
{
if (go.value())
{
- resetEnergy = true;
+ pzem.resetEnergy();
goReset.value(false);
}
}
@@ -181,7 +180,7 @@ void setup() {
pinPeripheral(PIN_SERIAL2_RX, PIO_SERCOM);
pinPeripheral(PIN_SERIAL2_TX, PIO_SERCOM);
- SerialUSB.begin(9600);
+// SerialUSB.begin(9600);
Serial2.begin(9600);
ArduinoPlatform::SerialDebug = &SerialUSB;
@@ -238,12 +237,17 @@ void loop() {
if (knx.configured() && !progMode)
{
refreshValueLoop();
- resetEnergyLoop();
for (uint8_t i=0; i< physicalCount; i++)
{
Physical[i].loop();
}
+
+ if (timeStatus() == timeSet && resetPeriod != 0)
+ {
+ resetEnergyLoop();
+ }
+
}
else if (progMode)
{
@@ -257,7 +261,7 @@ void refreshValueLoop(){
if (millis() - lastPzemUpdate >= pzemInterval)
{
- for (uint8_t i=0; i< physicalCount; i++)
+ for (uint8_t i=0; i < physicalCount; i++)
{
float isaValue;
switch (i) { //maybe a pointer or reference could be nicer...
@@ -282,11 +286,18 @@ void refreshValueLoop(){
default:
break;
}
+
if(!isnan(isaValue))
{
Physical[i].setValue(isaValue);
}
+ else
+ {
+ Physical[i].setValue(-1);
+ }
}
+ lastPzemUpdate = millis();
+ led.set(500, 1000);
}
}
@@ -339,14 +350,14 @@ void prodModeLoop(){ // run Only if progMode triggered ( at start or callback)
{
knx.progMode(true);
timerProgPrevMillis = millis();
- led.set(500, 250);
+ led.set(50, 100);
}
else
{
if (millis() - timerProgPrevMillis > timerProgMode) {
knx.progMode(false);
goProgMode.value(false);
- progMode = 0;
+ progMode = false;
}
}
}
diff --git a/examples/knx-usb/platformio-ci.ini b/examples/knx-usb/platformio-ci.ini
index 4e3322b..ce01930 100644
--- a/examples/knx-usb/platformio-ci.ini
+++ b/examples/knx-usb/platformio-ci.ini
@@ -8,7 +8,7 @@
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:adafruit_feather_m0]
-platform = atmelsam
+platform = atmelsam@6.0.1
board = adafruit_feather_m0
framework = arduino
diff --git a/examples/knx-usb/platformio.ini b/examples/knx-usb/platformio.ini
index c4b69f1..2d7a710 100644
--- a/examples/knx-usb/platformio.ini
+++ b/examples/knx-usb/platformio.ini
@@ -13,7 +13,7 @@
libdeps_dir = /tmp/libdeps
[env:adafruit_feather_m0]
-platform = atmelsam
+platform = atmelsam@6.0.1
board = adafruit_feather_m0
framework = arduino
; We consider that the this projects is opened within its project directory
@@ -27,7 +27,7 @@ board_build.usb_product="KNX RF - USB Interface"
lib_deps =
SPI
- Adafruit TinyUSB Library
+ Adafruit TinyUSB Library@0.7.1
https://github.com/thelsing/FlashStorage.git
knx
diff --git a/src/arduino_platform.cpp b/src/arduino_platform.cpp
index 65ec833..8c58dfb 100644
--- a/src/arduino_platform.cpp
+++ b/src/arduino_platform.cpp
@@ -2,9 +2,17 @@
#include "knx/bits.h"
#include
+#ifndef KNX_NO_SPI
#include
+#endif
+#ifndef KNX_NO_PRINT
Stream* ArduinoPlatform::SerialDebug = &Serial;
+#endif
+
+ArduinoPlatform::ArduinoPlatform() : _knxSerial(nullptr)
+{
+}
ArduinoPlatform::ArduinoPlatform(HardwareSerial* knxSerial) : _knxSerial(knxSerial)
{
@@ -27,7 +35,8 @@ void ArduinoPlatform::fatalError()
void ArduinoPlatform::knxUart( HardwareSerial* serial )
{
- closeUart();
+ if (_knxSerial)
+ closeUart();
_knxSerial = serial;
setupUart();
}
@@ -94,6 +103,7 @@ size_t ArduinoPlatform::readBytesUart(uint8_t *buffer, size_t length)
return length;
}
+#ifndef KNX_NO_SPI
void ArduinoPlatform::setupSpi()
{
SPI.begin();
@@ -111,7 +121,9 @@ int ArduinoPlatform::readWriteSpi(uint8_t *data, size_t len)
SPI.transfer(data, len);
return 0;
}
+#endif
+#ifndef KNX_NO_PRINT
void printUint64(uint64_t value, int base = DEC)
{
char buf[8 * sizeof(uint64_t) + 1];
@@ -284,3 +296,4 @@ void println(void)
{
ArduinoPlatform::SerialDebug->println();
}
+#endif // KNX_NO_PRINT
diff --git a/src/arduino_platform.h b/src/arduino_platform.h
index 10c10e6..3ef5047 100644
--- a/src/arduino_platform.h
+++ b/src/arduino_platform.h
@@ -2,11 +2,10 @@
#include "Arduino.h"
-extern Stream& _serialDBG;
-
class ArduinoPlatform : public Platform
{
public:
+ ArduinoPlatform();
ArduinoPlatform(HardwareSerial* knxSerial);
// basic stuff
@@ -24,11 +23,14 @@ class ArduinoPlatform : public Platform
virtual size_t readBytesUart(uint8_t* buffer, size_t length);
//spi
+#ifndef KNX_NO_SPI
void setupSpi() override;
void closeSpi() override;
int readWriteSpi (uint8_t *data, size_t len) override;
-
+#endif
+#ifndef KNX_NO_PRINT
static Stream* SerialDebug;
+#endif
protected:
HardwareSerial* _knxSerial;
diff --git a/src/cc1310_platform.cpp b/src/cc1310_platform.cpp
index ae7bc7b..18e1289 100644
--- a/src/cc1310_platform.cpp
+++ b/src/cc1310_platform.cpp
@@ -134,6 +134,7 @@ void delayMicroseconds (unsigned int howLong)
ClockP_usleep(howLong);
}
+#ifndef KNX_NO_PRINT
size_t write(uint8_t c)
{
#if defined(PRINT_UART)
@@ -402,6 +403,7 @@ void println(double num)
// default: print 10 digits
println(num, 10);
}
+#endif // KNX_NO_PRINT
uint32_t digitalRead(uint32_t dwPin)
{
diff --git a/src/esp32_platform.cpp b/src/esp32_platform.cpp
index cc902dd..6f49934 100644
--- a/src/esp32_platform.cpp
+++ b/src/esp32_platform.cpp
@@ -6,7 +6,10 @@
#include "knx/bits.h"
-Esp32Platform::Esp32Platform() : ArduinoPlatform(&Serial1)
+Esp32Platform::Esp32Platform()
+#ifndef KNX_NO_DEFAULT_UART
+ : ArduinoPlatform(&Serial1)
+#endif
{
}
@@ -34,6 +37,14 @@ void Esp32Platform::macAddress(uint8_t * addr)
esp_wifi_get_mac(WIFI_IF_STA, addr);
}
+uint32_t Esp32Platform::uniqueSerialNumber()
+{
+ uint64_t chipid = ESP.getEfuseMac();
+ uint32_t upperId = (chipid >> 32) & 0xFFFFFFFF;
+ uint32_t lowerId = (chipid & 0xFFFFFFFF);
+ return (upperId ^ lowerId);
+}
+
void Esp32Platform::restart()
{
println("restart");
@@ -81,6 +92,18 @@ int Esp32Platform::readBytesMultiCast(uint8_t * buffer, uint16_t maxLen)
return len;
}
+bool Esp32Platform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len)
+{
+ IPAddress ucastaddr(htonl(addr));
+ println("sendBytesUniCast endPacket fail");
+ if(_udp.beginPacket(ucastaddr, port) == 1) {
+ _udp.write(buffer, len);
+ if(_udp.endPacket() == 0) println("sendBytesUniCast endPacket fail");
+ }
+ else println("sendBytesUniCast beginPacket fail");
+ return true;
+}
+
uint8_t * Esp32Platform::getEepromBuffer(uint16_t size)
{
EEPROM.begin(size);
@@ -89,6 +112,7 @@ uint8_t * Esp32Platform::getEepromBuffer(uint16_t size)
void Esp32Platform::commitToEeprom()
{
+ EEPROM.getDataPtr(); // trigger dirty flag in EEPROM lib to make sure data will be written to flash
EEPROM.commit();
}
diff --git a/src/esp32_platform.h b/src/esp32_platform.h
index 3c006ba..07b0d75 100644
--- a/src/esp32_platform.h
+++ b/src/esp32_platform.h
@@ -16,6 +16,9 @@ public:
uint32_t currentDefaultGateway() override;
void macAddress(uint8_t* addr) override;
+ // unique serial number
+ uint32_t uniqueSerialNumber() override;
+
// basic stuff
void restart();
@@ -25,6 +28,9 @@ public:
bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override;
int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) override;
+ //unicast
+ bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override;
+
//memory
uint8_t* getEepromBuffer(uint16_t size);
void commitToEeprom();
diff --git a/src/esp_platform.cpp b/src/esp_platform.cpp
index f453fea..14a7c58 100644
--- a/src/esp_platform.cpp
+++ b/src/esp_platform.cpp
@@ -7,7 +7,10 @@
#include "knx/bits.h"
-EspPlatform::EspPlatform() : ArduinoPlatform(&Serial)
+EspPlatform::EspPlatform()
+#ifndef KNX_NO_DEFAULT_UART
+ : ArduinoPlatform(&Serial)
+#endif
{
}
@@ -35,6 +38,11 @@ void EspPlatform::macAddress(uint8_t * addr)
wifi_get_macaddr(STATION_IF, addr);
}
+uint32_t EspPlatform::uniqueSerialNumber()
+{
+ return ESP.getChipId();
+}
+
void EspPlatform::restart()
{
println("restart");
@@ -43,9 +51,9 @@ void EspPlatform::restart()
void EspPlatform::setupMultiCast(uint32_t addr, uint16_t port)
{
- _mulitcastAddr = htonl(addr);
- _mulitcastPort = port;
- IPAddress mcastaddr(_mulitcastAddr);
+ _multicastAddr = htonl(addr);
+ _multicastPort = port;
+ IPAddress mcastaddr(_multicastAddr);
Serial.printf("setup multicast addr: %s port: %d ip: %s\n", mcastaddr.toString().c_str(), port,
WiFi.localIP().toString().c_str());
@@ -61,7 +69,7 @@ void EspPlatform::closeMultiCast()
bool EspPlatform::sendBytesMultiCast(uint8_t * buffer, uint16_t len)
{
//printHex("<- ",buffer, len);
- _udp.beginPacketMulticast(_mulitcastAddr, _mulitcastPort, WiFi.localIP());
+ _udp.beginPacketMulticast(_multicastAddr, _multicastPort, WiFi.localIP());
_udp.write(buffer, len);
_udp.endPacket();
return true;
@@ -84,6 +92,18 @@ int EspPlatform::readBytesMultiCast(uint8_t * buffer, uint16_t maxLen)
return len;
}
+bool EspPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len)
+{
+ IPAddress ucastaddr(htonl(addr));
+ println("sendBytesUniCast endPacket fail");
+ if(_udp.beginPacket(ucastaddr, port) == 1) {
+ _udp.write(buffer, len);
+ if(_udp.endPacket() == 0) println("sendBytesUniCast endPacket fail");
+ }
+ else println("sendBytesUniCast beginPacket fail");
+ return true;
+}
+
uint8_t * EspPlatform::getEepromBuffer(uint16_t size)
{
EEPROM.begin(size);
diff --git a/src/esp_platform.h b/src/esp_platform.h
index cd026d8..c535bae 100644
--- a/src/esp_platform.h
+++ b/src/esp_platform.h
@@ -16,6 +16,9 @@ class EspPlatform : public ArduinoPlatform
uint32_t currentDefaultGateway() override;
void macAddress(uint8_t* addr) override;
+ // unique serial number
+ uint32_t uniqueSerialNumber() override;
+
// basic stuff
void restart();
@@ -25,13 +28,16 @@ class EspPlatform : public ArduinoPlatform
bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override;
int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) override;
+ //unicast
+ bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override;
+
//memory
uint8_t* getEepromBuffer(uint16_t size);
void commitToEeprom();
private:
WiFiUDP _udp;
- uint32_t _mulitcastAddr;
- uint16_t _mulitcastPort;
+ uint32_t _multicastAddr;
+ uint16_t _multicastPort;
};
#endif
diff --git a/src/knx/address_table_object.h b/src/knx/address_table_object.h
index 20d15f4..a8990c2 100644
--- a/src/knx/address_table_object.h
+++ b/src/knx/address_table_object.h
@@ -2,9 +2,9 @@
#include "table_object.h"
/**
- * This class represents the group address table. It provides a mapping between tranport layer
+ * This class represents the group address table. It provides a mapping between transport layer
* service access points (TSAP) and group addresses. The TSAP can be imagined as an index to the array
- * of group adresses.
+ * of group addresses.
*
* See section 4.10 of @cite knx:3/5/1 for further details.
* It implements realisation type 7 (see section 4.10.7 of @cite knx:3/5/1).
@@ -13,9 +13,9 @@ class AddressTableObject : public TableObject
{
public:
/**
- * The contructor.
+ * The constructor.
*
- * @param memory This parameter is only passed to the custructor of TableObject an not used by this class.
+ * @param memory This parameter is only passed to the constructor of TableObject and is not used by this class.
*/
AddressTableObject(Memory& memory);
const uint8_t* restore(const uint8_t* buffer) override;
@@ -35,7 +35,7 @@ class AddressTableObject : public TableObject
/**
* Get the TSAP mapped to a group address.
*
- * @param groupAddress the group address of whicht to get the TSAP for.
+ * @param groupAddress the group address of which to get the TSAP for.
*
* @return the TSAP if found or zero if no tsap was found.
*/
diff --git a/src/knx/application_layer.cpp b/src/knx/application_layer.cpp
index 7103974..581f8bd 100644
--- a/src/knx/application_layer.cpp
+++ b/src/knx/application_layer.cpp
@@ -66,7 +66,7 @@ void ApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priori
case GroupValueWrite:
_bau.groupValueWriteIndication(asap, priority, hopType, secCtrl, data, len);
default:
- /* other apdutypes ar not valid here. If the appear do nothing */
+ /* other apdutypes are not valid here. If they appear do nothing */
break;
}
}
@@ -908,7 +908,7 @@ void ApplicationLayer::groupValueSend(ApduType type, AckType ack, uint16_t asap,
uint8_t* apdudata = apdu.data();
if (dataLength == 0)
{
- // data size is six bit or less. So store int first byte
+ // data size is six bit or less. So store in first byte
*apdudata &= ~0x3f;
*apdudata |= (*data & 0x3f);
}
@@ -916,7 +916,7 @@ void ApplicationLayer::groupValueSend(ApduType type, AckType ack, uint16_t asap,
{
memcpy(apdudata + 1, data, dataLength);
}
- // no need to check if there is a tsap. This is a response, so the read got trough
+ // no need to check if there is a tsap. This is a response, so the read got through
uint16_t tsap = (uint16_t)_assocTable->translateAsap(asap);
dataGroupRequest(ack, hopType, priority, tsap, apdu, secCtrl);
dataGroupIndication(hopType, priority, tsap, apdu, secCtrl);
@@ -1129,7 +1129,7 @@ void ApplicationLayer::individualIndication(HopCountType hopType, Priority prior
_bau.keyWriteAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1]);
break;
default:
- print("Indiviual-indication: unhandled APDU-Type: ");
+ print("Individual-indication: unhandled APDU-Type: ");
println(apdu.type());
}
}
@@ -1240,7 +1240,7 @@ void ApplicationLayer::individualConfirm(AckType ack, HopCountType hopType, Prio
_bau.keyWriteResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[1], status);
break;
default:
- print("Indiviual-confirm: unhandled APDU-Type: ");
+ print("Individual-confirm: unhandled APDU-Type: ");
println(apdu.type());
}
}
diff --git a/src/knx/application_layer.h b/src/knx/application_layer.h
index ae6da70..c2d4578 100644
--- a/src/knx/application_layer.h
+++ b/src/knx/application_layer.h
@@ -11,7 +11,7 @@ class TransportLayer;
* This is an implementation of the application layer as specified in @cite knx:3/5/1.
* It provides methods for the BusAccessUnit to do different things and translates this
* call to an APDU and calls the correct method of the TransportLayer.
- * It also takes calls from TransportLayer, decodes the submitted APDU and calls the coresponding
+ * It also takes calls from TransportLayer, decodes the submitted APDU and calls the corresponding
* methods of the BusAccessUnit class.
*/
class ApplicationLayer
@@ -31,12 +31,12 @@ class ApplicationLayer
void associationTableObject(AssociationTableObject& assocTable);
// from transport layer
- // Note: without data secure feature, the application layer is just used with SecurtyControl.dataSecurity = None
+ // Note: without data secure feature, the application layer is just used with SecurityControl.dataSecurity = None
// hooks that can be implemented by derived class (e.g. SecureApplicationLayer)
#pragma region Transport - Layer - Callbacks
/**
- * Somebody send us an APDU via multicast communiation. See 3.2 of @cite knx:3/3/4.
+ * Somebody send us an APDU via multicast communication. See 3.2 of @cite knx:3/3/4.
* See also ApplicationLayer::dataGroupConfirm and TransportLayer::dataGroupRequest.
* This method is called by the TransportLayer.
*
@@ -51,7 +51,7 @@ class ApplicationLayer
*/
virtual void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu);
/**
- * Report the status of an APDU that we sent via multicast communiation back to us. See 3.2 of @cite knx:3/3/4.
+ * Report the status of an APDU that we sent via multicast communication back to us. See 3.2 of @cite knx:3/3/4.
* See also ApplicationLayer::dataGroupConfirm and TransportLayer::dataGroupRequest. This method is called by
* the TransportLayer.
*
diff --git a/src/knx/application_program_object.cpp b/src/knx/application_program_object.cpp
index e6628d2..598d0fe 100644
--- a/src/knx/application_program_object.cpp
+++ b/src/knx/application_program_object.cpp
@@ -29,6 +29,29 @@ ApplicationProgramObject::ApplicationProgramObject(Memory& memory)
TableObject::initializeProperties(sizeof(properties), properties);
}
+uint8_t* ApplicationProgramObject::save(uint8_t* buffer)
+{
+ uint8_t programVersion[5];
+ property(PID_PROG_VERSION)->read(programVersion);
+ buffer = pushByteArray(programVersion, 5, buffer);
+
+ return TableObject::save(buffer);
+}
+
+const uint8_t* ApplicationProgramObject::restore(const uint8_t* buffer)
+{
+ uint8_t programVersion[5];
+ buffer = popByteArray(programVersion, 5, buffer);
+ property(PID_PROG_VERSION)->write(programVersion);
+
+ return TableObject::restore(buffer);
+}
+
+uint16_t ApplicationProgramObject::saveSize()
+{
+ return TableObject::saveSize() + 5; // sizeof(programVersion)
+}
+
uint8_t * ApplicationProgramObject::data(uint32_t addr)
{
return TableObject::data() + addr;
diff --git a/src/knx/application_program_object.h b/src/knx/application_program_object.h
index 87b743d..c989a1c 100644
--- a/src/knx/application_program_object.h
+++ b/src/knx/application_program_object.h
@@ -7,6 +7,9 @@ class ApplicationProgramObject : public TableObject
{
public:
ApplicationProgramObject(Memory& memory);
+ uint8_t* save(uint8_t* buffer) override;
+ const uint8_t* restore(const uint8_t* buffer) override;
+ uint16_t saveSize() override;
uint8_t* data(uint32_t addr);
uint8_t getByte(uint32_t addr);
uint16_t getWord(uint32_t addr);
diff --git a/src/knx/association_table_object.cpp b/src/knx/association_table_object.cpp
index c78b244..0880fc7 100644
--- a/src/knx/association_table_object.cpp
+++ b/src/knx/association_table_object.cpp
@@ -25,7 +25,7 @@ uint16_t AssociationTableObject::entryCount()
uint16_t AssociationTableObject::getTSAP(uint16_t idx)
{
- if (idx < 0 || idx >= entryCount())
+ if (idx >= entryCount())
return 0;
return ntohs(_tableData[2 * idx + 1]);
@@ -33,7 +33,7 @@ uint16_t AssociationTableObject::getTSAP(uint16_t idx)
uint16_t AssociationTableObject::getASAP(uint16_t idx)
{
- if (idx < 0 || idx >= entryCount())
+ if (idx >= entryCount())
return 0;
return ntohs(_tableData[2 * idx + 2]);
diff --git a/src/knx/bau_systemB.cpp b/src/knx/bau_systemB.cpp
index f6795ec..3d1bfa7 100644
--- a/src/knx/bau_systemB.cpp
+++ b/src/knx/bau_systemB.cpp
@@ -62,7 +62,7 @@ uint8_t BauSystemB::checkmasterResetValidity(EraseCode eraseCode, uint8_t channe
case EraseCode::ResetIA:
{
// TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER)
- println("ResetAP requested. Not implemented yet.");
+ println("ResetIA requested. Not implemented yet.");
return successCode;
}
case EraseCode::ResetLinks:
@@ -500,7 +500,7 @@ bool BauSystemB::restartRequest(uint16_t asap, const SecurityControl secCtrl)
void BauSystemB::connectConfirm(uint16_t tsap)
{
- if (_restartState == Connecting && tsap >= 0)
+ if (_restartState == Connecting)
{
/* restart connection is confirmed, go to the next state */
_restartState = Connected;
@@ -532,7 +532,7 @@ void BauSystemB::nextRestartState()
}
break;
case Restarted:
- /* restart is finished, we send a discommect */
+ /* restart is finished, we send a disconnect */
if (millis() - _restartDelay > 30)
{
applicationLayer().disconnectRequest(SystemPriority);
diff --git a/src/knx/bau_systemB_device.cpp b/src/knx/bau_systemB_device.cpp
index 43d70f7..37289af 100644
--- a/src/knx/bau_systemB_device.cpp
+++ b/src/knx/bau_systemB_device.cpp
@@ -114,9 +114,13 @@ void BauSystemBDevice::updateGroupObject(GroupObject & go, uint8_t * data, uint8
memcpy(goData, data, length);
go.commFlag(Updated);
+#ifdef SMALL_GROUPOBJECT
+ GroupObject::processClassCallback(go);
+#else
GroupObjectUpdatedHandler handler = go.callback();
if (handler)
handler(go);
+#endif
}
bool BauSystemBDevice::configured()
diff --git a/src/knx/bits.cpp b/src/knx/bits.cpp
index 0a668f7..9b04145 100644
--- a/src/knx/bits.cpp
+++ b/src/knx/bits.cpp
@@ -8,6 +8,7 @@ const uint8_t* popByte(uint8_t& b, const uint8_t* data)
return data;
}
+#ifndef KNX_NO_PRINT
void printHex(const char* suffix, const uint8_t *data, size_t length, bool newline)
{
print(suffix);
@@ -21,6 +22,7 @@ void printHex(const char* suffix, const uint8_t *data, size_t length, bool newli
println();
}
}
+#endif
const uint8_t* popWord(uint16_t& w, const uint8_t* data)
{
diff --git a/src/knx/bits.h b/src/knx/bits.h
index c7fee15..b513ef9 100644
--- a/src/knx/bits.h
+++ b/src/knx/bits.h
@@ -63,6 +63,7 @@ typedef void (*voidFuncPtr)(void);
void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode);
#endif
+#ifndef KNX_NO_PRINT
void print(const char[]);
void print(char);
void print(unsigned char, int = DEC);
@@ -87,6 +88,11 @@ void println(double);
void println(void);
void printHex(const char* suffix, const uint8_t *data, size_t length, bool newline = true);
+#else
+#define print(...) do {} while(0)
+#define println(...) do {} while(0)
+#define printHex(...) do {} while(0)
+#endif
const uint8_t* popByte(uint8_t& b, const uint8_t* data);
const uint8_t* popWord(uint16_t& w, const uint8_t* data);
diff --git a/src/knx/config.h b/src/knx/config.h
index 0b3ce64..f937510 100644
--- a/src/knx/config.h
+++ b/src/knx/config.h
@@ -60,6 +60,22 @@
// Define via a compiler -D flag if required
// #define USE_DATASECURE
+// option to have GroupObjects (KO in German) use 8 bytes mangement information RAM instead of 19 bytes
+// see knx-demo-small-go for example
+// this option might be also set via compiler flag -DSMALL_GROUPOBJECT if required
+//#define SMALL_GROUPOBJECT
+
+// Some defines to reduce footprint
+// Do not perform conversion from KNXValue(const char*) to other types, it mainly avoids the expensive strtod
+//#define KNX_NO_STRTOx_CONVERSION
+// Do not print messages
+//#define KNX_NO_PRINT
+// Do not use SPI (Arduino variants)
+//#define KNX_NO_SPI
+// Do not use the default UART (Arduino variants), it must be defined by ArduinoPlatform::knxUart
+// (combined with other flags (HWSERIAL_NONE for stm32) - avoid allocation of RX/TX buffers for all serial lines)
+//#define KNX_NO_DEFAULT_UART
+
#endif
#if !defined(MASK_VERSION)
diff --git a/src/knx/data_property.cpp b/src/knx/data_property.cpp
index 1b68565..1bf0223 100644
--- a/src/knx/data_property.cpp
+++ b/src/knx/data_property.cpp
@@ -49,7 +49,7 @@ uint8_t DataProperty::write(uint16_t start, uint8_t count, const uint8_t* data)
start -= 1;
if (start + count > _currentElements)
{
- //reallocate memory for _data
+ // reallocate memory for _data
uint8_t* oldData = _data;
size_t oldDataSize = _currentElements * ElementSize();
diff --git a/src/knx/device_object.h b/src/knx/device_object.h
index 092fdfd..a7d80d4 100644
--- a/src/knx/device_object.h
+++ b/src/knx/device_object.h
@@ -39,5 +39,5 @@ public:
uint8_t defaultHopCount();
private:
uint8_t _prgMode = 0;
- uint16_t _ownAddress = 0;
+ uint16_t _ownAddress = 65535; // 15.15.255;
};
diff --git a/src/knx/dpt.h b/src/knx/dpt.h
index 5fc45fe..f6dcef3 100644
--- a/src/knx/dpt.h
+++ b/src/knx/dpt.h
@@ -357,6 +357,7 @@
#define DPT_FlaggedScaling Dpt(239, 1)
#define DPT_CombinedPosition Dpt(240, 800)
#define DPT_StatusSAB Dpt(241, 800)
+#define DPT_Colour_RGBW Dpt(251, 600)
class Dpt
{
diff --git a/src/knx/dptconvert.cpp b/src/knx/dptconvert.cpp
index ea55d73..6fc644f 100644
--- a/src/knx/dptconvert.cpp
+++ b/src/knx/dptconvert.cpp
@@ -22,12 +22,6 @@ int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatyp
if (datatype.mainGroup == 2 && datatype.subGroup >= 1 && datatype.subGroup <= 12 && datatype.index <= 1)
return busValueToBinaryControl(payload, payload_length, datatype, value);
// DPT 3.* - Step Control
- if (datatype.mainGroup == 3 && datatype.subGroup >= 7 && datatype.subGroup <= 8 && datatype.index <= 1)
- return busValueToStepControl(payload, payload_length, datatype, value);
- // DPT 4.* - Character// DPT 2.* - Binary Control
- if (datatype.mainGroup == 2 && datatype.subGroup >= 1 && datatype.subGroup <= 12 && datatype.index <= 1)
- return busValueToBinaryControl(payload, payload_length, datatype, value);
- // DPT 3.* - Step Control
if (datatype.mainGroup == 3 && datatype.subGroup >= 7 && datatype.subGroup <= 8 && datatype.index <= 1)
return busValueToStepControl(payload, payload_length, datatype, value);
// DPT 4.* - Character
@@ -42,8 +36,8 @@ int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatyp
// DPT 6.020 - Status with Mode
if (datatype.mainGroup == 6 && datatype.subGroup == 20 && datatype.index <= 5)
return busValueToStatusAndMode(payload, payload_length, datatype, value);
- // DPT 7.001/7.010/7.011/7.012/7.013 - Unsigned 16 Bit Integer
- if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13)) && !datatype.index)
+ // DPT 7.001/7.010/7.011/7.012/7.013/7.600 - Unsigned 16 Bit Integer
+ if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13) || (datatype.subGroup == 600)) && !datatype.index)
return busValueToUnsigned16(payload, payload_length, datatype, value);
// DPT 7.002-DPT 7.007 - Time Period
if (datatype.mainGroup == 7 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
@@ -55,108 +49,7 @@ int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatyp
if (datatype.mainGroup == 8 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
return busValueToTimeDelta(payload, payload_length, datatype, value);
// DPT 9.* - 16 Bit Float
- if (datatype.mainGroup == 9 && ((datatype.subGroup >= 1 && datatype.subGroup <= 11 && datatype.subGroup != 9) || (datatype.subGroup >= 20 && datatype.subGroup <= 28)) && !datatype.index)
- return busValueToFloat16(payload, payload_length, datatype, value);
- // DPT 10.* - Time and Weekday
- if (datatype.mainGroup == 10 && datatype.subGroup == 1 && datatype.index <= 1)
- return busValueToTime(payload, payload_length, datatype, value);
- // DPT 11.* - Date
- if (datatype.mainGroup == 11 && datatype.subGroup == 1 && !datatype.index)
- return busValueToDate(payload, payload_length, datatype, value);
- // DPT 12.* - Unsigned 32 Bit Integer
- if (datatype.mainGroup == 12 && datatype.subGroup == 1 && !datatype.index)
- return busValueToUnsigned32(payload, payload_length, datatype, value);
- // DPT 13.001/13.002/13.010-13.015 - Signed 32 Bit Integer
- if (datatype.mainGroup == 13 && (datatype.subGroup == 1 || datatype.subGroup == 2 || (datatype.subGroup >= 10 && datatype.subGroup <= 15)) && !datatype.index)
- return busValueToSigned32(payload, payload_length, datatype, value);
- // DPT 13.100 - Long Time Period
- if (datatype.mainGroup == 13 && datatype.subGroup == 100 && !datatype.index)
- return busValueToLongTimePeriod(payload, payload_length, datatype, value);
- // DPT 14.* - 32 Bit Float
- if (datatype.mainGroup == 14 && datatype.subGroup <= 79 && !datatype.index)
- return busValueToFloat32(payload, payload_length, datatype, value);
- // DPT 15.* - Access Data
- if (datatype.mainGroup == 15 && !datatype.subGroup && datatype.index <= 5)
- return busValueToAccess(payload, payload_length, datatype, value);
- // DPT 16.* - String
- if (datatype.mainGroup == 16 && datatype.subGroup <= 1 && !datatype.index)
- return busValueToString(payload, payload_length, datatype, value);
- // DPT 17.* - Scene Number
- if (datatype.mainGroup == 17 && datatype.subGroup == 1 && !datatype.index)
- return busValueToScene(payload, payload_length, datatype, value);
- // DPT 18.* - Scene Control
- if (datatype.mainGroup == 18 && datatype.subGroup == 1 && datatype.index <= 1)
- return busValueToSceneControl(payload, payload_length, datatype, value);
- // DPT 19.* - Date and Time
- if (datatype.mainGroup == 19 && datatype.subGroup == 1 && (datatype.index <= 3 || datatype.index == 9 || datatype.index == 10))
- return busValueToDateTime(payload, payload_length, datatype, value);
- // DPT 26.* - Scene Info
- if (datatype.mainGroup == 26 && datatype.subGroup == 1 && datatype.index <= 1)
- return busValueToSceneInfo(payload, payload_length, datatype, value);
- // DPT 28.* - Unicode String
- if (datatype.mainGroup == 28 && datatype.subGroup == 1 && !datatype.index)
- return busValueToUnicode(payload, payload_length, datatype, value);
- // DPT 29.* - Signed 64 Bit Integer
- if (datatype.mainGroup == 29 && datatype.subGroup >= 10 && datatype.subGroup <= 12 && !datatype.index)
- return busValueToSigned64(payload, payload_length, datatype, value);
- // DPT 219.* - Alarm Info
- if (datatype.mainGroup == 219 && datatype.subGroup == 1 && datatype.index <= 10)
- return busValueToAlarmInfo(payload, payload_length, datatype, value);
- // DPT 221.* - Serial Number
- if (datatype.mainGroup == 221 && datatype.subGroup == 1 && datatype.index <= 1)
- return busValueToSerialNumber(payload, payload_length, datatype, value);
- // DPT 217.* - Version
- if (datatype.mainGroup == 217 && datatype.subGroup == 1 && datatype.index <= 2)
- return busValueToVersion(payload, payload_length, datatype, value);
- // DPT 225.001/225.002 - Scaling Speed and Scaling Step Time
- if (datatype.mainGroup == 225 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && datatype.index <= 1)
- return busValueToScaling(payload, payload_length, datatype, value);
- // DPT 225.003 - Next Tariff
- if (datatype.mainGroup == 225 && datatype.subGroup == 3 && datatype.index <= 1)
- return busValueToTariff(payload, payload_length, datatype, value);
- // DPT 231.* - Locale
- if (datatype.mainGroup == 231 && datatype.subGroup == 1 && datatype.index <= 1)
- return busValueToLocale(payload, payload_length, datatype, value);
- // DPT 232.600 - RGB
- if (datatype.mainGroup == 232 && datatype.subGroup == 600 && !datatype.index)
- return busValueToRGB(payload, payload_length, datatype, value);
- // DPT 234.* - Language and Region
- if (datatype.mainGroup == 234 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && !datatype.index)
- return busValueToLocale(payload, payload_length, datatype, value);
- // DPT 235.* - Active Energy
- if (datatype.mainGroup == 235 && datatype.subGroup == 1 && datatype.index <= 3)
- return busValueToActiveEnergy(payload, payload_length, datatype, value);
- // DPT 238.* - Scene Config
- if (datatype.mainGroup == 238 && datatype.subGroup == 1 && datatype.index <= 2)
- return busValueToSceneConfig(payload, payload_length, datatype, value);
- // DPT 239.* - Flagged Scaling
- if (datatype.mainGroup == 239 && datatype.subGroup == 1 && datatype.index <= 1)
- return busValueToFlaggedScaling(payload, payload_length, datatype, value);
- if (datatype.mainGroup == 4 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && !datatype.index)
- return busValueToCharacter(payload, payload_length, datatype, value);
- // DPT 5.* - Unsigned 8 Bit Integer
- if (datatype.mainGroup == 5 && ((datatype.subGroup >= 1 && datatype.subGroup <= 6 && datatype.subGroup != 2) || datatype.subGroup == 10) && !datatype.index)
- return busValueToUnsigned8(payload, payload_length, datatype, value);
- // DPT 6.001/6.010 - Signed 8 Bit Integer
- if (datatype.mainGroup == 6 && (datatype.subGroup == 1 || datatype.subGroup == 10) && !datatype.index)
- return busValueToSigned8(payload, payload_length, datatype, value);
- // DPT 6.020 - Status with Mode
- if (datatype.mainGroup == 6 && datatype.subGroup == 20 && datatype.index <= 5)
- return busValueToStatusAndMode(payload, payload_length, datatype, value);
- // DPT 7.001/7.010/7.011/7.012/7.013 - Unsigned 16 Bit Integer
- if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13)) && !datatype.index)
- return busValueToUnsigned16(payload, payload_length, datatype, value);
- // DPT 7.002-DPT 7.007 - Time Period
- if (datatype.mainGroup == 7 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
- return busValueToTimePeriod(payload, payload_length, datatype, value);
- // DPT 8.001/8.010/8.011 - Signed 16 Bit Integer
- if (datatype.mainGroup == 8 && (datatype.subGroup == 1 || datatype.subGroup == 10 || datatype.subGroup == 11) && !datatype.index)
- return busValueToSigned16(payload, payload_length, datatype, value);
- // DPT 8.002-DPT 8.007 - Time Delta
- if (datatype.mainGroup == 8 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
- return busValueToTimeDelta(payload, payload_length, datatype, value);
- // DPT 9.* - 16 Bit Float
- if (datatype.mainGroup == 9 && ((datatype.subGroup >= 1 && datatype.subGroup <= 11 && datatype.subGroup != 9) || (datatype.subGroup >= 20 && datatype.subGroup <= 28)) && !datatype.index)
+ if (datatype.mainGroup == 9 && ((datatype.subGroup >= 1 && datatype.subGroup <= 11) || (datatype.subGroup >= 20 && datatype.subGroup <= 29)) && !datatype.index)
return busValueToFloat16(payload, payload_length, datatype, value);
// DPT 10.* - Time and Weekday
if (datatype.mainGroup == 10 && datatype.subGroup == 1 && datatype.index <= 1)
@@ -233,6 +126,9 @@ int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatyp
// DPT 239.* - Flagged Scaling
if (datatype.mainGroup == 239 && datatype.subGroup == 1 && datatype.index <= 1)
return busValueToFlaggedScaling(payload, payload_length, datatype, value);
+ // DPT 251.600 - RGBW
+ if (datatype.mainGroup == 251 && datatype.subGroup == 600 && datatype.index <= 1)
+ return busValueToRGBW(payload, payload_length, datatype, value);
}
return false;
}
@@ -260,8 +156,8 @@ int KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_len
// DPT 6.020 - Status with Mode
if (datatype.mainGroup == 6 && datatype.subGroup == 20 && datatype.index <= 5)
return valueToBusValueStatusAndMode(value, payload, payload_length, datatype);
- // DPT 7.001/7.010/7.011/7.012/7.013 - Unsigned 16 Bit Integer
- if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13)) && !datatype.index)
+ // DPT 7.001/7.010/7.011/7.012/7.013/7.600 - Unsigned 16 Bit Integer
+ if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13) || datatype.subGroup == 600) && !datatype.index)
return valueToBusValueUnsigned16(value, payload, payload_length, datatype);
// DPT 7.002-DPT 7.007 - Time Period
if (datatype.mainGroup == 7 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
@@ -273,7 +169,7 @@ int KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_len
if (datatype.mainGroup == 8 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
return valueToBusValueTimeDelta(value, payload, payload_length, datatype);
// DPT 9.* - 16 Bit Float
- if (datatype.mainGroup == 9 && ((datatype.subGroup >= 1 && datatype.subGroup <= 11 && datatype.subGroup != 9) || (datatype.subGroup >= 20 && datatype.subGroup <= 28)) && !datatype.index)
+ if (datatype.mainGroup == 9 && ((datatype.subGroup >= 1 && datatype.subGroup <= 11 ) || (datatype.subGroup >= 20 && datatype.subGroup <= 29)) && !datatype.index)
return valueToBusValueFloat16(value, payload, payload_length, datatype);
// DPT 10.* - Time and Weekday
if (datatype.mainGroup == 10 && datatype.subGroup == 1 && datatype.index <= 1)
@@ -350,6 +246,9 @@ int KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_len
// DPT 239.* - Flagged Scaling
if (datatype.mainGroup == 239 && datatype.subGroup == 1 && datatype.index <= 1)
return valueToBusValueFlaggedScaling(value, payload, payload_length, datatype);
+ // DPT 251.600 - RGBW
+ if (datatype.mainGroup == 251 && datatype.subGroup == 600 && datatype.index <= 1)
+ return valueToBusValueRGBW(value, payload, payload_length, datatype);
return false;
}
@@ -904,12 +803,27 @@ int busValueToRGB(const uint8_t* payload, size_t payload_length, const Dpt& data
{
ASSERT_PAYLOAD(3);
uint32_t rgb = unsigned16FromPayload(payload, 0) * 256 + unsigned8FromPayload(payload, 2);
- if (rgb > 16777215)
- return false;
value = rgb;
return true;
}
+int busValueToRGBW(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
+{
+ ASSERT_PAYLOAD(6);
+ switch (datatype.index) {
+ case 0: // The RGBW value
+ {
+ uint32_t rgbw = unsigned32FromPayload(payload, 0);
+ value = rgbw;
+ }
+ return true;
+ case 1: // The mask bits only
+ value = unsigned8FromPayload(payload,5);
+ return true;
+ }
+ return false;
+}
+
int busValueToFlaggedScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(2);
@@ -993,7 +907,7 @@ int valueToBusValueStepControl(const KNXValue& value, uint8_t* payload, size_t p
int valueToBusValueCharacter(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
- if ((uint64_t)value < INT64_C(0) || (uint64_t)value > INT64_C(255) || (datatype.subGroup == 1 && (uint64_t)value > INT64_C(127)))
+ if ((uint64_t)value > INT64_C(255) || (datatype.subGroup == 1 && (uint64_t)value > INT64_C(127)))
return false;
unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF);
return true;
@@ -1260,7 +1174,7 @@ int valueToBusValueAccess(const KNXValue& value, uint8_t* payload, size_t payloa
break;
case 5:
{
- if ((uint64_t)value < INT64_C(0) || (uint64_t)value > INT64_C(15))
+ if ((uint64_t)value > INT64_C(15))
return false;
bcdToPayload(payload, payload_length, 7, (uint64_t)value);
break;
@@ -1551,7 +1465,7 @@ int valueToBusValueScaling(const KNXValue& value, uint8_t* payload, size_t paylo
{
uint32_t duration = value;
- if (duration < INT64_C(0) || duration > INT64_C(65535))
+ if (duration > INT64_C(65535))
return false;
ENSURE_PAYLOAD(3);
@@ -1578,7 +1492,7 @@ int valueToBusValueTariff(const KNXValue& value, uint8_t* payload, size_t payloa
{
uint32_t duration = value;
- if (duration < INT64_C(0) || duration > INT64_C(65535))
+ if (duration > INT64_C(65535))
return false;
ENSURE_PAYLOAD(3);
@@ -1626,6 +1540,24 @@ int valueToBusValueRGB(const KNXValue& value, uint8_t* payload, size_t payload_l
return true;
}
+int valueToBusValueRGBW(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
+{
+ switch(datatype.index)
+ {
+ case 0: // RGBW
+ {
+ uint32_t rgbw = (uint32_t)value;
+ unsigned32ToPayload(payload, payload_length, 0, rgbw, 0xffffffff); // RGBW
+ }
+ break;
+ case 1: // Mask bits
+ unsigned8ToPayload(payload, payload_length, 5, (uint8_t)value, 0x0f);
+ break;
+
+ }
+ return true;
+}
+
int valueToBusValueFlaggedScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch (datatype.index)
@@ -1654,7 +1586,6 @@ int valueToBusValueActiveEnergy(const KNXValue& value, uint8_t* payload, size_t
{
case 0:
{
-
if ((int64_t)value < INT64_C(-2147483648) || (int64_t)value > INT64_C(2147483647))
return false;
ENSURE_PAYLOAD(6);
diff --git a/src/knx/dptconvert.h b/src/knx/dptconvert.h
index 9256b51..f341df8 100644
--- a/src/knx/dptconvert.h
+++ b/src/knx/dptconvert.h
@@ -78,6 +78,7 @@ int busValueToScaling(const uint8_t* payload, size_t payload_length, const Dpt&
int busValueToTariff(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
int busValueToLocale(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
int busValueToRGB(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
+int busValueToRGBW(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
int busValueToFlaggedScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
int busValueToActiveEnergy(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
@@ -116,6 +117,7 @@ int valueToBusValueScaling(const KNXValue& value, uint8_t* payload, size_t paylo
int valueToBusValueTariff(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
int valueToBusValueLocale(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
int valueToBusValueRGB(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
+int valueToBusValueRGBW(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
int valueToBusValueFlaggedScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
int valueToBusValueActiveEnergy(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
diff --git a/src/knx/group_object.cpp b/src/knx/group_object.cpp
index 2ed11d9..db92058 100644
--- a/src/knx/group_object.cpp
+++ b/src/knx/group_object.cpp
@@ -4,23 +4,30 @@
#include "datapoint_types.h"
#include "group_object_table_object.h"
+#ifdef SMALL_GROUPOBJECT
+GroupObjectUpdatedHandler GroupObject::_updateHandlerStatic = 0;
+#endif
+GroupObjectTableObject* GroupObject::_table = 0;
+
GroupObject::GroupObject()
{
_data = 0;
_commFlag = Ok;
- _table = 0;
_dataLength = 0;
+#ifndef SMALL_GROUPOBJECT
_updateHandler = 0;
+#endif
}
GroupObject::GroupObject(const GroupObject& other)
{
_data = new uint8_t[other._dataLength];
_commFlag = other._commFlag;
- _table = other._table;
_dataLength = other._dataLength;
_asap = other._asap;
+#ifndef SMALL_GROUPOBJECT
_updateHandler = other._updateHandler;
+#endif
memcpy(_data, other._data, _dataLength);
}
@@ -175,6 +182,24 @@ size_t GroupObject::sizeInTelegram()
return asapValueSize(code);
}
+#ifdef SMALL_GROUPOBJECT
+GroupObjectUpdatedHandler GroupObject::classCallback()
+{
+ return _updateHandlerStatic;
+}
+
+void GroupObject::classCallback(GroupObjectUpdatedHandler handler)
+{
+ _updateHandlerStatic = handler;
+}
+
+void GroupObject::processClassCallback(GroupObject& ko)
+{
+ if (_updateHandlerStatic != 0)
+ _updateHandlerStatic(ko);
+}
+
+#else
void GroupObject::callback(GroupObjectUpdatedHandler handler)
{
_updateHandler = handler;
@@ -185,6 +210,7 @@ GroupObjectUpdatedHandler GroupObject::callback()
{
return _updateHandler;
}
+#endif
void GroupObject::value(const KNXValue& value, const Dpt& type)
{
@@ -205,7 +231,7 @@ bool GroupObject::tryValue(KNXValue& value, const Dpt& type)
return KNX_Decode_Value(_data, _dataLength, type, value);
}
-
+#ifndef SMALL_GROUPOBJECT
void GroupObject::dataPointType(Dpt value)
{
_datapointType = value;
@@ -240,7 +266,7 @@ void GroupObject::valueNoSend(const KNXValue& value)
{
valueNoSend(value, _datapointType);
}
-
+#endif
void GroupObject::valueNoSend(const KNXValue& value, const Dpt& type)
{
diff --git a/src/knx/group_object.h b/src/knx/group_object.h
index 46499d9..91c8b56 100644
--- a/src/knx/group_object.h
+++ b/src/knx/group_object.h
@@ -133,6 +133,8 @@ class GroupObject
* (in german "KO-Nr")
*/
uint16_t asap();
+
+#ifndef SMALL_GROUPOBJECT
/**
* register a callback for this group object. The registered callback will be called if the group object was changed from the bus.
*/
@@ -141,16 +143,12 @@ class GroupObject
* returns the registered callback
*/
GroupObjectUpdatedHandler callback();
+#endif
/**
* return the current value of the group object.
* @param type the datapoint type used for the conversion. If this doesn't fit to the group object the returned value is invalid.
*/
KNXValue value(const Dpt& type);
- /**
- * return the current value of the group object. The datapoint type must be set with dataPointType(). Otherwise the returned
- * value is invalid.
- */
- KNXValue value();
/**
* set the current value of the group object and changes the state of the group object to ::WriteRequest.
* @param value the value the group object is set to
@@ -159,13 +157,6 @@ class GroupObject
* The parameters must fit the group object. Otherwise it will stay unchanged.
*/
void value(const KNXValue& value, const Dpt& type);
- /**
- * set the current value of the group object and changes the state of the group object to ::WriteRequest.
- * @param value the value the group object is set to
- *
- * The parameters must fit the group object and dhe datapoint type must be set with dataPointType(). Otherwise it will stay unchanged.
- */
- void value(const KNXValue& value);
/**
* set the current value of the group object.
* @param value the value the group object is set to
@@ -174,13 +165,6 @@ class GroupObject
* The parameters must fit the group object. Otherwise it will stay unchanged.
*/
void valueNoSend(const KNXValue& value, const Dpt& type);
- /**
- * set the current value of the group object.
- * @param value the value the group object is set to
- *
- * The parameters must fit the group object and dhe datapoint type must be set with dataPointType(). Otherwise it will stay unchanged.
- */
- void valueNoSend(const KNXValue& value);
/**
* set the current value of the group object.
* @param value the value the group object is set to
@@ -191,6 +175,27 @@ class GroupObject
* @returns true if the value of the group object was changed successfully.
*/
bool tryValue(KNXValue& value, const Dpt& type);
+
+#ifndef SMALL_GROUPOBJECT
+ /**
+ * return the current value of the group object. The datapoint type must be set with dataPointType(). Otherwise the returned
+ * value is invalid.
+ */
+ KNXValue value();
+ /**
+ * set the current value of the group object and changes the state of the group object to ::WriteRequest.
+ * @param value the value the group object is set to
+ *
+ * The parameters must fit the group object and dhe datapoint type must be set with dataPointType(). Otherwise it will stay unchanged.
+ */
+ void value(const KNXValue& value);
+ /**
+ * set the current value of the group object.
+ * @param value the value the group object is set to
+ *
+ * The parameters must fit the group object and dhe datapoint type must be set with dataPointType(). Otherwise it will stay unchanged.
+ */
+ void valueNoSend(const KNXValue& value);
/**
* set the current value of the group object.
* @param value the value the group object is set to
@@ -209,15 +214,32 @@ class GroupObject
* sets the datapoint type of the group object.
*/
void dataPointType(Dpt value);
+#else
+ /**
+ * Alternative callback processing: register one global callback for all group object.
+ * The registered callback will be called if any group object was changed from the bus.
+ * The callback method has to dispatch to the correct handler for this group object.
+ */
+ static GroupObjectUpdatedHandler classCallback();
+ static void classCallback(GroupObjectUpdatedHandler handler);
+ static void processClassCallback(GroupObject& ko);
+#endif
private:
+ // class members
+ static GroupObjectTableObject* _table;
+#ifdef SMALL_GROUPOBJECT
+ static GroupObjectUpdatedHandler _updateHandlerStatic;
+#endif
+
size_t asapValueSize(uint8_t code);
- GroupObjectUpdatedHandler _updateHandler;
size_t goSize();
uint16_t _asap = 0;
ComFlag _commFlag = Ok;
uint8_t* _data = 0;
uint8_t _dataLength = 0;
- GroupObjectTableObject* _table = 0;
+#ifndef SMALL_GROUPOBJECT
+ GroupObjectUpdatedHandler _updateHandler;
Dpt _datapointType;
+#endif
};
diff --git a/src/knx/ip_parameter_object.cpp b/src/knx/ip_parameter_object.cpp
index d894dab..dcbbba3 100644
--- a/src/knx/ip_parameter_object.cpp
+++ b/src/knx/ip_parameter_object.cpp
@@ -6,7 +6,7 @@
#include "data_property.h"
#include "callback_property.h"
-//224.0.23.12
+// 224.0.23.12
#define DEFAULT_MULTICAST_ADDR ((uint32_t)0xE000170C)
IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platform): _deviceObject(deviceObject),
@@ -46,7 +46,7 @@ IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platf
return 1;
}
- pushInt(io->_platform.currentIpAddress(), data);
+ pushInt(htonl(io->_platform.currentIpAddress()), data);
return 1;
}),
new CallbackProperty(this, PID_CURRENT_SUBNET_MASK, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0,
@@ -59,7 +59,7 @@ IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platf
return 1;
}
- pushInt(io->_platform.currentSubnetMask(), data);
+ pushInt(htonl(io->_platform.currentSubnetMask()), data);
return 1;
}),
new CallbackProperty(this, PID_CURRENT_DEFAULT_GATEWAY, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0,
@@ -72,7 +72,7 @@ IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platf
return 1;
}
- pushInt(io->_platform.currentDefaultGateway(), data);
+ pushInt(htonl(io->_platform.currentDefaultGateway()), data);
return 1;
}),
new DataProperty(PID_IP_ADDRESS, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3),
diff --git a/src/knx/knx_ip_device_information_dib.cpp b/src/knx/knx_ip_device_information_dib.cpp
index c6a5aa5..a13ad96 100644
--- a/src/knx/knx_ip_device_information_dib.cpp
+++ b/src/knx/knx_ip_device_information_dib.cpp
@@ -35,7 +35,7 @@ uint16_t KnxIpDeviceInformationDIB::individualAddress() const
}
-void KnxIpDeviceInformationDIB::indiviudalAddress(uint16_t value)
+void KnxIpDeviceInformationDIB::individualAddress(uint16_t value)
{
pushWord(value, _data + 4);
}
@@ -65,7 +65,7 @@ void KnxIpDeviceInformationDIB::serialNumber(const uint8_t* value)
}
-uint32_t KnxIpDeviceInformationDIB::routingMulicastAddress() const
+uint32_t KnxIpDeviceInformationDIB::routingMulticastAddress() const
{
return getInt(_data + 14);
}
diff --git a/src/knx/knx_ip_device_information_dib.h b/src/knx/knx_ip_device_information_dib.h
index 8acad60..32f24ba 100644
--- a/src/knx/knx_ip_device_information_dib.h
+++ b/src/knx/knx_ip_device_information_dib.h
@@ -16,12 +16,12 @@ class KnxIpDeviceInformationDIB : public KnxIpDIB
uint8_t status() const;
void status(uint8_t value);
uint16_t individualAddress() const;
- void indiviudalAddress(uint16_t value);
+ void individualAddress(uint16_t value);
uint16_t projectInstallationIdentifier() const;
void projectInstallationIdentifier(uint16_t value);
const uint8_t* serialNumber() const;
void serialNumber(const uint8_t* value);
- uint32_t routingMulicastAddress() const;
+ uint32_t routingMulticastAddress() const;
void routingMulticastAddress(uint32_t value);
const uint8_t* macAddress() const;
void macAddress(const uint8_t* value);
diff --git a/src/knx/knx_ip_search_response.cpp b/src/knx/knx_ip_search_response.cpp
index d051416..c4d8830 100644
--- a/src/knx/knx_ip_search_response.cpp
+++ b/src/knx/knx_ip_search_response.cpp
@@ -19,7 +19,7 @@ KnxIpSearchResponse::KnxIpSearchResponse(IpParameterObject& parameters, DeviceOb
_deviceInfo.code(DEVICE_INFO);
_deviceInfo.medium(0x20); //KNX-IP FIXME get this value from somewhere else
_deviceInfo.status(deviceObject.progMode());
- _deviceInfo.indiviudalAddress(parameters.propertyValue(PID_KNX_INDIVIDUAL_ADDRESS));
+ _deviceInfo.individualAddress(parameters.propertyValue(PID_KNX_INDIVIDUAL_ADDRESS));
_deviceInfo.projectInstallationIdentifier(parameters.propertyValue(PID_PROJECT_INSTALLATION_ID));
_deviceInfo.serialNumber(deviceObject.propertyData(PID_SERIAL_NUMBER));
_deviceInfo.routingMulticastAddress(parameters.propertyValue(PID_ROUTING_MULTICAST_ADDRESS));
diff --git a/src/knx/knx_value.cpp b/src/knx/knx_value.cpp
index 0a7c104..c8d9f54 100644
--- a/src/knx/knx_value.cpp
+++ b/src/knx/knx_value.cpp
@@ -187,7 +187,7 @@ KNXValue& KNXValue::operator=(const int16_t value)
KNXValue& KNXValue::operator=(const int32_t value)
{
- _value.boolValue = value;
+ _value.intValue = value;
_type = IntType;
return *this;
}
@@ -318,7 +318,7 @@ uint64_t KNXValue::ulongValue() const
switch (_type)
{
case ULongType:
- return _value.uintValue;
+ return _value.ulongValue;
case BoolType:
return _value.boolValue ? 1 : 0;
case UCharType:
@@ -343,7 +343,11 @@ uint64_t KNXValue::ulongValue() const
case DoubleType:
return (uint64_t)_value.doubleValue;
case StringType:
+#ifndef KNX_NO_STRTOx_CONVERSION
return (uint64_t)strtoul(_value.stringValue, NULL, 0);
+#else
+ return 0;
+#endif
}
return 0;
}
@@ -444,7 +448,11 @@ int64_t KNXValue::longValue() const
case DoubleType:
return (int64_t)_value.doubleValue;
case StringType:
+#ifndef KNX_NO_STRTOx_CONVERSION
return strtol(_value.stringValue, NULL, 0);
+#else
+ return 0;
+#endif
}
return 0;
}
@@ -476,7 +484,11 @@ double KNXValue::doubleValue() const
case LongType:
return _value.longValue;
case StringType:
+#ifndef KNX_NO_STRTOx_CONVERSION
return strtod(_value.stringValue, NULL);
+#else
+ return 0;
+#endif
}
return 0;
}
diff --git a/src/knx/memory.h b/src/knx/memory.h
index 75c4480..6014ed4 100644
--- a/src/knx/memory.h
+++ b/src/knx/memory.h
@@ -10,7 +10,7 @@
#define MAXTABLEOBJ 4
#ifndef KNX_FLASH_SIZE
-# define KNX_FLASH_SIZE 1024
+#define KNX_FLASH_SIZE 1024
#endif
class MemoryBlock
diff --git a/src/knx/platform.cpp b/src/knx/platform.cpp
index 78ce42c..2674c3c 100644
--- a/src/knx/platform.cpp
+++ b/src/knx/platform.cpp
@@ -74,6 +74,11 @@ uint32_t Platform::currentDefaultGateway()
void Platform::macAddress(uint8_t *data)
{}
+uint32_t Platform::uniqueSerialNumber()
+{
+ return 0x01020304;
+}
+
void Platform::setupMultiCast(uint32_t addr, uint16_t port)
{}
diff --git a/src/knx/platform.h b/src/knx/platform.h
index 1ac61e0..1251d0e 100644
--- a/src/knx/platform.h
+++ b/src/knx/platform.h
@@ -20,6 +20,9 @@ class Platform
virtual uint32_t currentDefaultGateway();
virtual void macAddress(uint8_t* data);
+ // unique serial number
+ virtual uint32_t uniqueSerialNumber();
+
// basic stuff
virtual void restart() = 0;
virtual void fatalError() = 0;
diff --git a/src/knx/rf_medium_object.cpp b/src/knx/rf_medium_object.cpp
index fb143f3..5416649 100644
--- a/src/knx/rf_medium_object.cpp
+++ b/src/knx/rf_medium_object.cpp
@@ -31,7 +31,7 @@ RfMediumObject::RfMediumObject()
resultData[2] = 0xFF; // permanent bidirectional device
resultLength = 3;
}),
-/* This properties are used in NMP_LinkBudget_Measure to diagnose the Link Budget of the communication.
+/* These properties are used in NMP_LinkBudget_Measure to diagnose the Link Budget of the communication.
This in not implemented yet.
new DataProperty(PID_RF_DIAG_SA_FILTER_TABLE, true, PDT_GENERIC_03, 8, ReadLv3 | WriteLv3),
new DataProperty(PID_RF_DIAG_BUDGET_TABLE, false, PDT_GENERIC_03, 8, ReadLv3 | WriteLv0),
diff --git a/src/knx/rf_physical_layer_cc1101.h b/src/knx/rf_physical_layer_cc1101.h
index ff5e7ab..76065d3 100644
--- a/src/knx/rf_physical_layer_cc1101.h
+++ b/src/knx/rf_physical_layer_cc1101.h
@@ -21,19 +21,19 @@ extern void delayMicroseconds (unsigned int howLong);
/*----------------------[CC1101 - misc]---------------------------------------*/
#define CRYSTAL_FREQUENCY 26000000
-#define CFG_REGISTER 0x2F //47 registers
-#define FIFOBUFFER 0x42 //size of Fifo Buffer +2 for rssi and lqi
-#define RSSI_OFFSET_868MHZ 0x4E //dec = 74
-#define TX_RETRIES_MAX 0x05 //tx_retries_max
-#define ACK_TIMEOUT 250 //ACK timeout in ms
-#define CC1101_COMPARE_REGISTER 0x00 //register compare 0=no compare 1=compare
-#define BROADCAST_ADDRESS 0x00 //broadcast address
+#define CFG_REGISTER 0x2F // 47 registers
+#define FIFOBUFFER 0x42 // size of Fifo Buffer +2 for rssi and lqi
+#define RSSI_OFFSET_868MHZ 0x4E // dec = 74
+#define TX_RETRIES_MAX 0x05 // tx_retries_max
+#define ACK_TIMEOUT 250 // ACK timeout in ms
+#define CC1101_COMPARE_REGISTER 0x00 // register compare 0=no compare 1=compare
+#define BROADCAST_ADDRESS 0x00 // broadcast address
#define CC1101_FREQ_315MHZ 0x01
#define CC1101_FREQ_434MHZ 0x02
#define CC1101_FREQ_868MHZ 0x03
#define CC1101_FREQ_915MHZ 0x04
-#define CC1101_TEMP_ADC_MV 3.225 //3.3V/1023 . mV pro digit
-#define CC1101_TEMP_CELS_CO 2.47 //Temperature coefficient 2.47mV per Grad Celsius
+#define CC1101_TEMP_ADC_MV 3.225 // 3.3V/1023 . mV pro digit
+#define CC1101_TEMP_CELS_CO 2.47 // Temperature coefficient 2.47mV per Grad Celsius
/*---------------------------[CC1101 - R/W offsets]---------------------------*/
#define WRITE_SINGLE_BYTE 0x00
@@ -43,12 +43,12 @@ extern void delayMicroseconds (unsigned int howLong);
/*---------------------------[END R/W offsets]--------------------------------*/
/*------------------------[CC1101 - FIFO commands]----------------------------*/
-#define TXFIFO_BURST 0x7F //write burst only
-#define TXFIFO_SINGLE_BYTE 0x3F //write single only
-#define RXFIFO_BURST 0xFF //read burst only
-#define RXFIFO_SINGLE_BYTE 0xBF //read single only
-#define PATABLE_BURST 0x7E //power control read/write
-#define PATABLE_SINGLE_BYTE 0xFE //power control read/write
+#define TXFIFO_BURST 0x7F // write burst only
+#define TXFIFO_SINGLE_BYTE 0x3F // write single only
+#define RXFIFO_BURST 0xFF // read burst only
+#define RXFIFO_SINGLE_BYTE 0xBF // read single only
+#define PATABLE_BURST 0x7E // power control read/write
+#define PATABLE_SINGLE_BYTE 0xFE // power control read/write
/*---------------------------[END FIFO commands]------------------------------*/
/*----------------------[CC1101 - config register]----------------------------*/
diff --git a/src/knx/rf_physical_layer_cc1310.cpp b/src/knx/rf_physical_layer_cc1310.cpp
index 35749a4..2016b95 100644
--- a/src/knx/rf_physical_layer_cc1310.cpp
+++ b/src/knx/rf_physical_layer_cc1310.cpp
@@ -132,8 +132,8 @@ void RfPhysicalLayerCC1310::setOutputPowerLevel(int8_t dBm)
rfPowerTableSize = PROP_RF_txPowerTableSize;
}
- //if max power is requested then the CCFG_FORCE_VDDR_HH must be set in
- //the ccfg
+ // if max power is requested then the CCFG_FORCE_VDDR_HH must be set in
+ // the ccfg
#if (CCFG_FORCE_VDDR_HH != 0x1)
if((newValue.paType == RF_TxPowerTable_DefaultPA) &&
(dBm == rfPowerTable[rfPowerTableSize-2].power))
diff --git a/src/knx/router_object.cpp b/src/knx/router_object.cpp
index 1bc1d5b..b7c7b62 100644
--- a/src/knx/router_object.cpp
+++ b/src/knx/router_object.cpp
@@ -84,7 +84,6 @@ void RouterObject::initialize(CouplerModel model, uint8_t objIndex, DptMedium me
Property* tableProperties[] =
{
new DataProperty( PID_COUPLER_SERVICES_CONTROL, true, PDT_GENERIC_01, 1, ReadLv3 | WriteLv0, (uint8_t) 0), // written by ETS TODO: implement
- new DataProperty( PID_MCB_TABLE, false, PDT_GENERIC_08, 1, ReadLv3 | WriteLv0), // TODO: improve: move to TableObject once segment size handling is clear
new DataProperty( PID_FILTER_TABLE_USE, true, PDT_BINARY_INFORMATION, 1, ReadLv3 | WriteLv0, (uint16_t) 0 ), // default: invalid filter table, do not use, written by ETS
new FunctionProperty(this, PID_ROUTETABLE_CONTROL,
// Command Callback of PID_ROUTETABLE_CONTROL
@@ -452,27 +451,9 @@ void RouterObject::beforeStateChange(LoadState& newState)
if (newState != LS_LOADED)
return;
- // calculate crc16-ccitt for PID_MCB_TABLE
- updateMcb();
-
_filterTableGroupAddresses = (uint16_t*)data();
}
-void RouterObject::updateMcb()
-{
- uint8_t mcb[propertySize(PID_MCB_TABLE)];
-
- static constexpr uint32_t segmentSize = kFilterTableSize;
- uint16_t crc16 = crc16Ccitt(data(), segmentSize);
-
- pushInt(segmentSize, &mcb[0]); // Segment size
- pushByte(0x00, &mcb[4]); // CRC control byte -> 0: always valid -> according to coupler spec. it shall always be a valid CRC
- pushByte(0xFF, &mcb[5]); // Read access 4 bits + Write access 4 bits (unknown: value taken from real coupler device)
- pushWord(crc16, &mcb[6]); // CRC-16 CCITT of filter table
-
- property(PID_MCB_TABLE)->write(mcb);
-}
-
void RouterObject::masterReset(EraseCode eraseCode, uint8_t channel)
{
if (eraseCode == FactoryReset)
diff --git a/src/knx/router_object.h b/src/knx/router_object.h
index 22faa56..e43838d 100644
--- a/src/knx/router_object.h
+++ b/src/knx/router_object.h
@@ -52,8 +52,6 @@ private:
void commandClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet);
bool statusClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet);
- void updateMcb();
-
bool _rfSbcRoutingEnabled = false;
bool _ipSbcRoutingEnabled = false;
uint16_t* _filterTableGroupAddresses = 0;
diff --git a/src/knx/table_object.cpp b/src/knx/table_object.cpp
index d1be31c..909337a 100644
--- a/src/knx/table_object.cpp
+++ b/src/knx/table_object.cpp
@@ -31,6 +31,8 @@ uint8_t* TableObject::save(uint8_t* buffer)
{
buffer = pushByte(_state, buffer);
+ buffer = pushInt(_size, buffer);
+
if (_data)
buffer = pushInt(_memory.toRelative(_data), buffer);
else
@@ -46,6 +48,8 @@ const uint8_t* TableObject::restore(const uint8_t* buffer)
buffer = popByte(state, buffer);
_state = (LoadState)state;
+ buffer = popInt(_size, buffer);
+
uint32_t relativeAddress = 0;
buffer = popInt(relativeAddress, buffer);
@@ -80,6 +84,8 @@ bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte)
if (doFill)
memset(_data, fillByte, size);
+ _size = size;
+
return true;
}
@@ -229,7 +235,7 @@ void TableObject::errorCode(ErrorCode errorCode)
uint16_t TableObject::saveSize()
{
- return 5 + InterfaceObject::saveSize();
+ return 5 + InterfaceObject::saveSize() + sizeof(_size);
}
void TableObject::initializeProperties(size_t propertiesSize, Property** properties)
@@ -267,6 +273,21 @@ void TableObject::initializeProperties(size_t propertiesSize, Property** propert
pushInt(obj->tableReference(), data);
return 1;
}),
+ new CallbackProperty(this, PID_MCB_TABLE, false, PDT_GENERIC_08, 1, ReadLv3 | WriteLv0,
+ [](TableObject* obj, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t {
+ if (obj->_state != LS_LOADED)
+ return 0; // need to check return code for invalid
+
+ uint32_t segmentSize = obj->_size;
+ uint16_t crc16 = crc16Ccitt(obj->data(), segmentSize);
+
+ pushInt(segmentSize, data); // Segment size
+ pushByte(0x00, data + 4); // CRC control byte -> 0: always valid
+ pushByte(0xFF, data + 5); // Read access 4 bits + Write access 4 bits
+ pushWord(crc16, data + 6); // CRC-16 CCITT of data
+
+ return 1;
+ }),
new DataProperty(PID_ERROR_CODE, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint8_t)E_NO_FAULT)
};
//TODO: missing
@@ -284,4 +305,4 @@ void TableObject::initializeProperties(size_t propertiesSize, Property** propert
memcpy(allProperties + propertyCount, ownProperties, sizeof(ownProperties));
InterfaceObject::initializeProperties(sizeof(allProperties), allProperties);
-}
+}
\ No newline at end of file
diff --git a/src/knx/table_object.h b/src/knx/table_object.h
index fc487e9..c4213b3 100644
--- a/src/knx/table_object.h
+++ b/src/knx/table_object.h
@@ -28,7 +28,7 @@ class TableObject: public InterfaceObject
uint8_t* save(uint8_t* buffer) override;
const uint8_t* restore(const uint8_t* buffer) override;
uint16_t saveSize() override;
-protected:
+ protected:
/**
* This method is called before the interface object enters a new ::LoadState.
* If there is a error changing the state newState should be set to ::LS_ERROR and errorCode()
@@ -47,7 +47,7 @@ protected:
void errorCode(ErrorCode errorCode);
void initializeProperties(size_t propertiesSize, Property** properties) override;
-
+
private:
uint32_t tableReference();
bool allocTable(uint32_t size, bool doFill, uint8_t fillByte);
@@ -68,4 +68,11 @@ protected:
LoadState _state = LS_UNLOADED;
Memory& _memory;
uint8_t *_data = 0;
+
+ /**
+ * used to store size of data() in allocTable(), needed for calculation of crc in PID_MCB_TABLE.
+ * This value is also saved and restored.
+ * The size of the memory block cannot be used because it is changed during alignment to page size.
+ */
+ uint32_t _size = 0;
};
diff --git a/src/knx/tpuart_data_link_layer.cpp b/src/knx/tpuart_data_link_layer.cpp
index fe0cb8f..96f41f7 100644
--- a/src/knx/tpuart_data_link_layer.cpp
+++ b/src/knx/tpuart_data_link_layer.cpp
@@ -11,6 +11,9 @@
#include
#include
+// Activate trace output
+//#define DBG_TRACE
+
// NCN5120
//#define NCN5120
@@ -75,25 +78,28 @@
#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
+//tx states
+enum {
+ TX_IDLE,
+ TX_FRAME,
+ TX_WAIT_ECHO,
+ TX_WAIT_CONN
+};
-#define BYTE_TIMEOUT 10 //milli seconds
+//rx states
+enum {
+ RX_WAIT_START,
+ RX_L_DATA,
+ RX_WAIT_EOP
+};
+
+#define EOP_TIMEOUT 2 //milli seconds; end of layer-2 packet gap
#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)
@@ -107,265 +113,317 @@ void TpUartDataLinkLayer::loop()
if (!_enabled)
return;
- switch (_loopState)
- {
- case IDLE:
- if (_platform.uartAvailable())
- {
- _loopState = RX_FIRST_BYTE;
- }
- else
- {
- if (!_waitConfirm && !isTxQueueEmpty())
+ // Signals to communicate from rx part with the tx part
+ bool isEchoComplete = false; // Flag that a complete echo is received
+ uint8_t dataConnMsg = 0; // The DATA_CONN message just seen or 0
+ do {
+ _receiveBuffer[0] = 0x29;
+ _receiveBuffer[1] = 0;
+ uint8_t* buffer = _receiveBuffer + 2;
+ uint8_t rxByte;
+ bool isEOP = (millis() - _lastByteRxTime > EOP_TIMEOUT); // Flag that an EOP gap is seen
+ switch (_rxState)
+ {
+ case RX_WAIT_START:
+ if (_platform.uartAvailable())
{
- loadNextTxFrame();
- _loopState = TX_FRAME;
+ rxByte = _platform.readUart();
+#ifdef DBG_TRACE
+ print(rxByte, HEX);
+#endif
+ _lastByteRxTime = millis();
+
+ // Check for layer-2 packets
+ _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;
+ _rxState = RX_L_DATA;
+#ifdef DBG_TRACE
+ println("RLS");
+#endif
+ break;
+ }
+ else if ((rxByte & L_DATA_MASK) == L_DATA_EXTENDED_IND)
+ {
+ buffer[_RxByteCnt++] = rxByte;
+ _xorSum ^= rxByte;
+ _convert = false;
+ _rxState = RX_L_DATA;
+#ifdef DBG_TRACE
+ println("RLX");
+#endif
+ break;
+ }
+
+ // Handle all single byte packets here
+ else if ((rxByte & L_DATA_CON_MASK) == L_DATA_CON)
+ {
+ dataConnMsg = rxByte;
+ }
+ 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:");
+ if (rxByte & 0x80) print (" SC");
+ if (rxByte & 0x40) print (" RE");
+ if (rxByte & 0x20) print (" TE");
+ if (rxByte & 0x10) print (" PE");
+ if (rxByte & 0x08) print (" TW");
+ 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();
+ }
}
+ break;
+ case RX_L_DATA:
+ if (isEOP)
+ {
+ _rxState = RX_WAIT_START;
+ print("EOP inside RX_L_DATA");
+ printHex(" => ", buffer, _RxByteCnt);
+ break;
+ }
+ if (!_platform.uartAvailable())
+ break;
+ _lastByteRxTime = millis();
+ rxByte = _platform.readUart();
+#ifdef DBG_TRACE
+ print(rxByte, HEX);
+#endif
+ if (_RxByteCnt == MAX_KNX_TELEGRAM_SIZE)
+ {
+ _rxState = RX_WAIT_EOP;
+ println("invalid telegram size");
+ }
+ else
+ {
+ buffer[_RxByteCnt++] = rxByte;
+ }
+
+ if (_RxByteCnt == 7)
+ {
+ //Destination Address + payload available
+ _xorSum ^= rxByte;
+ //check if echo
+ if (_sendBuffer != nullptr && (!((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;
+
+ // The bau knows everything and could either check the address table object (normal device)
+ // or any filter tables (coupler) to see if we are addressed.
+
+ //check if individual or group address
+ bool isGroupAddress = (buffer[1] & 0x80) != 0;
+ uint16_t addr = getWord(buffer + 4);
+
+ if (_cb.isAckRequired(addr, isGroupAddress))
+ {
+ c |= 0x01;
+ }
+
+ // Hint: We can send directly here, this doesn't disturb other transmissions
+ _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)
+ {
+ isEchoComplete = true;
+ }
+ else
+ {
+ frameBytesReceived(_receiveBuffer, _RxByteCnt + 2);
+ }
+ _rxState = RX_WAIT_START;
+#ifdef DBG_TRACE
+ println("RX_WAIT_START");
+#endif
+ }
+ else
+ {
+ println("frame with invalid crc ignored");
+ _rxState = RX_WAIT_EOP;
+ }
+ }
+ else
+ {
+ _xorSum ^= rxByte;
+ }
+ break;
+ case RX_WAIT_EOP:
+ if (isEOP)
+ {
+ _RxByteCnt = 0;
+ _rxState = RX_WAIT_START;
+#ifdef DBG_TRACE
+ println("RX_WAIT_START");
+#endif
+ break;
+ }
+ if (!_platform.uartAvailable())
+ break;
+ _lastByteRxTime = millis();
+ rxByte = _platform.readUart();
+#ifdef DBG_TRACE
+ print(rxByte, HEX);
+#endif
+ break;
+ default:
+ break;
+ }
+ } while (_rxState == RX_L_DATA);
+
+ // Check for spurios DATA_CONN message
+ if (dataConnMsg && _txState != TX_WAIT_CONN && _txState != TX_WAIT_ECHO) {
+ println("got unexpected L_DATA_CON");
+ }
+
+ switch (_txState)
+ {
+ case TX_IDLE:
+ if (!isTxQueueEmpty())
+ {
+ loadNextTxFrame();
+ _txState = TX_FRAME;
+#ifdef DBG_TRACE
+ println("TX_FRAME");
+#endif
}
break;
case TX_FRAME:
if (sendSingleFrameByte() == false)
{
- _waitConfirm = true;
_waitConfirmStartTime = millis();
- _loopState = IDLE;
+ _txState = TX_WAIT_ECHO;
+#ifdef DBG_TRACE
+ println("TX_WAIT_ECHO");
+#endif
}
break;
- case RX_FIRST_BYTE:
- rxByte = _platform.readUart();
- _lastByteRxTime = millis();
- _RxByteCnt = 0;
- _xorSum = 0;
- if ((rxByte & L_DATA_MASK) == L_DATA_STANDARD_IND)
+ case TX_WAIT_ECHO:
+ case TX_WAIT_CONN:
+ if (isEchoComplete)
{
- buffer[_RxByteCnt++] = rxByte;
- _xorSum ^= rxByte;
- _RxByteCnt++; //convert to L_DATA_EXTENDED
- _convert = true;
- _loopState = RX_L_DATA;
- break;
+ _txState = TX_WAIT_CONN;
+#ifdef DBG_TRACE
+ println("TX_WAIT_CONN");
+#endif
}
- else if ((rxByte & L_DATA_MASK) == L_DATA_EXTENDED_IND)
+ else if (dataConnMsg)
{
- 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;
+ bool waitEcho = (_txState == TX_WAIT_ECHO);
+ if (waitEcho) {
+ println("L_DATA_CON without echo");
}
- 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 (_sendBuffer != nullptr && (!((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;
-
- // The bau knows everything and could either check the address table object (normal device)
- // or any filter tables (coupler) to see if we are addressed.
-
- //check if individual or group address
- bool isGroupAddress = (buffer[1] & 0x80) != 0;
- uint16_t addr = getWord(buffer + 4);
-
- if (_cb.isAckRequired(addr, isGroupAddress))
- {
- 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;
+ dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, !waitEcho && ((dataConnMsg & SUCCESS) > 0));
delete[] _sendBuffer;
_sendBuffer = 0;
_sendBufferLength = 0;
- _loopState = IDLE;
+ _txState = TX_IDLE;
}
- else
+ else if (millis() - _waitConfirmStartTime > CONFIRM_TIMEOUT)
{
- //should not happen
- println("expected L_DATA_CON not received");
- dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, false);
- _waitConfirm = false;
+ 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);
delete[] _sendBuffer;
_sendBuffer = 0;
_sendBufferLength = 0;
- _loopState = IDLE;
+ _txState = TX_IDLE;
+#ifdef DBG_TRACE
+ println("TX_IDLE");
+#endif
}
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;
- }
}
}
@@ -496,16 +554,21 @@ bool TpUartDataLinkLayer::sendSingleFrameByte()
cmd[0] = U_L_DATA_END_REQ | _TxByteCnt;
cmd[1] = _sendBuffer[_TxByteCnt];
+#ifdef DBG_TRACE
+ print(cmd[1], HEX);
+#endif
_platform.writeUart(cmd, 2);
_TxByteCnt++;
- return true;
}
- else
+
+ // Check for last byte send
+ if (_TxByteCnt >= _sendBufferLength)
{
_TxByteCnt = 0;
return false;
}
+ return true;
}
void TpUartDataLinkLayer::addFrameTxQueue(CemiFrame& frame)
diff --git a/src/knx/tpuart_data_link_layer.h b/src/knx/tpuart_data_link_layer.h
index 61fe533..35305f3 100644
--- a/src/knx/tpuart_data_link_layer.h
+++ b/src/knx/tpuart_data_link_layer.h
@@ -31,16 +31,15 @@ class TpUartDataLinkLayer : public DataLinkLayer
private:
bool _enabled = false;
- bool _waitConfirm = false;
uint8_t* _sendBuffer = 0;
uint16_t _sendBufferLength = 0;
uint8_t _receiveBuffer[MAX_KNX_TELEGRAM_SIZE];
- uint8_t _loopState = 0;
+ uint8_t _txState = 0;
+ uint8_t _rxState = 0;
uint16_t _RxByteCnt = 0;
uint16_t _TxByteCnt = 0;
uint8_t _oldIdx = 0;
bool _isEcho = false;
- bool _isAddressed = false;
bool _convert = false;
uint8_t _xorSum = 0;
uint32_t _lastByteRxTime;
diff --git a/src/knx_facade.h b/src/knx_facade.h
index db62dae..b1ccb1b 100644
--- a/src/knx_facade.h
+++ b/src/knx_facade.h
@@ -8,6 +8,10 @@
#include "knx/bau2920.h"
#include "knx/bau57B0.h"
+#ifndef USERDATA_SAVE_SIZE
+#define USERDATA_SAVE_SIZE 0
+#endif
+
#ifdef ARDUINO_ARCH_SAMD
#include "samd_platform.h"
#ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE
@@ -45,7 +49,8 @@
#endif
#endif
-typedef uint8_t* (*SaveRestoreCallback)(uint8_t* buffer);
+typedef const uint8_t* (*RestoreCallback)(const uint8_t* buffer);
+typedef uint8_t* (*SaveCallback)(uint8_t* buffer);
typedef void (*IsrFunctionPtr)();
template class KnxFacade : private SaveRestore
@@ -54,18 +59,21 @@ template class KnxFacade : private SaveRestore
KnxFacade() : _platformPtr(new P()), _bauPtr(new B(*_platformPtr)), _bau(*_bauPtr)
{
manufacturerId(0xfa);
+ bauNumber(platform().uniqueSerialNumber());
_bau.addSaveRestore(this);
}
KnxFacade(B& bau) : _bau(bau)
{
manufacturerId(0xfa);
+ bauNumber(platform().uniqueSerialNumber());
_bau.addSaveRestore(this);
}
KnxFacade(IsrFunctionPtr buttonISRFunction) : _platformPtr(new P()), _bauPtr(new B(*_platformPtr)), _bau(*_bauPtr)
{
manufacturerId(0xfa);
+ bauNumber(platform().uniqueSerialNumber());
_bau.addSaveRestore(this);
setButtonISRFunction(buttonISRFunction);
}
@@ -226,7 +234,7 @@ template class KnxFacade : private SaveRestore
{
_bau.deviceObject().bauNumber(value);
}
-
+
void orderNumber(const uint8_t* value)
{
_bau.deviceObject().orderNumber(value);
@@ -236,7 +244,7 @@ template class KnxFacade : private SaveRestore
{
_bau.deviceObject().hardwareType(value);
}
-
+
void version(uint16_t value)
{
_bau.deviceObject().version(value);
@@ -268,12 +276,12 @@ template class KnxFacade : private SaveRestore
_progButtonISRFuncPtr = progButtonISRFuncPtr;
}
- void setSaveCallback(SaveRestoreCallback func)
+ void setSaveCallback(SaveCallback func)
{
_saveCallback = func;
}
- void setRestoreCallback(SaveRestoreCallback func)
+ void setRestoreCallback(RestoreCallback func)
{
_restoreCallback = func;
}
@@ -286,6 +294,40 @@ template class KnxFacade : private SaveRestore
return _bau.parameters().data(addr);
}
+ // paramBit(address, shift)
+ // get state of a parameter as a boolean like "enable/disable", ...
+ // Declaration in XML file:
+ // ...
+ //
+ //
+ //
+ //
+ //
+ //
+ // ...
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ // ...
+ // Usage in code :
+ // if ( knx.paramBit(1,1))
+ // {
+ // //do somthings ....
+ // }
+ bool paramBit(uint32_t addr, uint8_t shift)
+ {
+ if (!_bau.configured())
+ return 0;
+
+ return (bool) ((_bau.parameters().getByte(addr) >> (7-shift)) & 0x01);
+ }
+
uint8_t paramByte(uint32_t addr)
{
if (!_bau.configured())
@@ -293,7 +335,20 @@ template class KnxFacade : private SaveRestore
return _bau.parameters().getByte(addr);
}
+
+ // Same usage than paramByte(addresse) for signed parameters
+ // Declaration in XML file
+ //
+ //
+ //
+ int8_t paramSignedByte(uint32_t addr)
+ {
+ if (!_bau.configured())
+ return 0;
+ return (int8_t) _bau.parameters().getByte(addr);
+ }
+
uint16_t paramWord(uint32_t addr)
{
if (!_bau.configured())
@@ -338,11 +393,11 @@ template class KnxFacade : private SaveRestore
uint32_t _ledPin = LED_BUILTIN;
uint32_t _buttonPinInterruptOn = RISING;
uint32_t _buttonPin = 0;
- SaveRestoreCallback _saveCallback = 0;
- SaveRestoreCallback _restoreCallback = 0;
+ SaveCallback _saveCallback = 0;
+ RestoreCallback _restoreCallback = 0;
volatile bool _toggleProgMode = false;
bool _progLedState = false;
- uint16_t _saveSize = 0;
+ uint16_t _saveSize = USERDATA_SAVE_SIZE;
IsrFunctionPtr _progButtonISRFuncPtr = 0;
uint8_t* save(uint8_t* buffer)
@@ -353,7 +408,7 @@ template class KnxFacade : private SaveRestore
return buffer;
}
- uint8_t* restore(uint8_t* buffer)
+ const uint8_t* restore(const uint8_t* buffer)
{
if (_restoreCallback != 0)
return _restoreCallback(buffer);
diff --git a/src/linux_platform.cpp b/src/linux_platform.cpp
index 6c53aaf..b1ff65f 100644
--- a/src/linux_platform.cpp
+++ b/src/linux_platform.cpp
@@ -501,6 +501,7 @@ void LinuxPlatform::setupUart()
}
}
+#ifndef KNX_NO_PRINT
void printUint64(uint64_t value, int base = DEC)
{
char buf[8 * sizeof(uint64_t) + 1];
@@ -707,6 +708,7 @@ void println(void)
{
printf("\n");
}
+#endif // KNX_NO_PRINT
void pinMode(uint32_t dwPin, uint32_t dwMode)
{
diff --git a/src/samd_platform.cpp b/src/samd_platform.cpp
index db94c61..f370a33 100644
--- a/src/samd_platform.cpp
+++ b/src/samd_platform.cpp
@@ -6,7 +6,10 @@
#include
#include
-SamdPlatform::SamdPlatform() : ArduinoPlatform(&Serial1)
+SamdPlatform::SamdPlatform()
+#ifndef KNX_NO_DEFAULT_UART
+ : ArduinoPlatform(&Serial1)
+#endif
{
}
@@ -14,6 +17,26 @@ SamdPlatform::SamdPlatform( HardwareSerial* s) : ArduinoPlatform(s)
{
}
+uint32_t SamdPlatform::uniqueSerialNumber()
+{
+ #if defined (__SAMD51__)
+ // SAMD51 from section 9.6 of the datasheet
+ #define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x008061FC)
+ #define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x00806010)
+ #define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x00806014)
+ #define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x00806018)
+ #else
+ //#elif defined (__SAMD21E17A__) || defined(__SAMD21G18A__) || defined(__SAMD21E18A__) || defined(__SAMD21J18A__)
+ // SAMD21 from section 9.3.3 of the datasheet
+ #define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x0080A00C)
+ #define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x0080A040)
+ #define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x0080A044)
+ #define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x0080A048)
+ #endif
+
+ return SERIAL_NUMBER_WORD_0 ^ SERIAL_NUMBER_WORD_1 ^ SERIAL_NUMBER_WORD_2 ^ SERIAL_NUMBER_WORD_3;
+}
+
void SamdPlatform::restart()
{
println("restart");
diff --git a/src/samd_platform.h b/src/samd_platform.h
index 6b45c83..dd1765d 100644
--- a/src/samd_platform.h
+++ b/src/samd_platform.h
@@ -10,6 +10,9 @@ public:
SamdPlatform();
SamdPlatform( HardwareSerial* s);
+ // unique serial number
+ uint32_t uniqueSerialNumber() override;
+
void restart();
uint8_t* getEepromBuffer(uint16_t size);
void commitToEeprom();
diff --git a/src/stm32_platform.cpp b/src/stm32_platform.cpp
index e05ab34..8fbfaa3 100644
--- a/src/stm32_platform.cpp
+++ b/src/stm32_platform.cpp
@@ -1,10 +1,13 @@
#include "stm32_platform.h"
#ifdef ARDUINO_ARCH_STM32
-#include
+#include
#include "knx/bits.h"
-Stm32Platform::Stm32Platform() : ArduinoPlatform(&Serial2)
+Stm32Platform::Stm32Platform()
+#ifndef KNX_NO_DEFAULT_UART
+ : ArduinoPlatform(&Serial2)
+#endif
{
}
@@ -17,6 +20,11 @@ Stm32Platform::~Stm32Platform()
delete [] _eepromPtr;
}
+uint32_t Stm32Platform::uniqueSerialNumber()
+{
+ return HAL_GetUIDw0() ^ HAL_GetUIDw1() ^ HAL_GetUIDw2();
+}
+
void Stm32Platform::restart()
{
NVIC_SystemReset();
diff --git a/src/stm32_platform.h b/src/stm32_platform.h
index 04870ec..056a327 100644
--- a/src/stm32_platform.h
+++ b/src/stm32_platform.h
@@ -8,6 +8,9 @@ public:
Stm32Platform( HardwareSerial* s);
~Stm32Platform();
+ // unique serial number
+ uint32_t uniqueSerialNumber() override;
+
// basic stuff
void restart();