mirror of
https://github.com/thelsing/knx.git
synced 2025-08-08 13:47:01 +02:00
Merge pull request #215 from thelsing/master
merge master into feature branch
This commit is contained in:
commit
376ab5c84b
8
.github/workflows/cmake-arm.yml
vendored
8
.github/workflows/cmake-arm.yml
vendored
@ -22,7 +22,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install bare metal ARM toolchain
|
- name: Install bare metal ARM toolchain
|
||||||
run: sudo apt-get install binutils-arm-none-eabi gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib
|
run: sudo apt-get install binutils-arm-none-eabi gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib
|
||||||
|
|
||||||
- name: Show toolchain version
|
- name: Show toolchain version
|
||||||
run: arm-none-eabi-gcc --version
|
run: arm-none-eabi-gcc --version
|
||||||
|
|
||||||
@ -36,8 +36,8 @@ jobs:
|
|||||||
# access regardless of the host operating system
|
# access regardless of the host operating system
|
||||||
shell: bash
|
shell: bash
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
# Note the current convention is to use the -S and -B options here to specify source
|
# Note the current convention is to use the -S and -B options here to specify source
|
||||||
# and build directories, but this is only available with CMake 3.13 and higher.
|
# and build directories, but this is only available with CMake 3.13 and higher.
|
||||||
# The CMake binaries on the Github Actions machines are (as of this writing) 3.12
|
# The CMake binaries on the Github Actions machines are (as of this writing) 3.12
|
||||||
run: cmake $GITHUB_WORKSPACE/examples/knx-cc1310 -DCMAKE_BUILD_TYPE=$BUILD_TYPE
|
run: cmake $GITHUB_WORKSPACE/examples/knx-cc1310 -DCMAKE_BUILD_TYPE=$BUILD_TYPE
|
||||||
|
|
||||||
@ -50,6 +50,6 @@ jobs:
|
|||||||
# - name: Test
|
# - name: Test
|
||||||
# working-directory: ${{runner.workspace}}/build
|
# working-directory: ${{runner.workspace}}/build
|
||||||
# shell: bash
|
# shell: bash
|
||||||
# Execute tests defined by the CMake configuration.
|
# Execute tests defined by the CMake configuration.
|
||||||
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
|
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
|
||||||
# run: ctest -C $BUILD_TYPE
|
# run: ctest -C $BUILD_TYPE
|
||||||
|
6
.github/workflows/cmake-native.yml
vendored
6
.github/workflows/cmake-native.yml
vendored
@ -27,8 +27,8 @@ jobs:
|
|||||||
# access regardless of the host operating system
|
# access regardless of the host operating system
|
||||||
shell: bash
|
shell: bash
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
# Note the current convention is to use the -S and -B options here to specify source
|
# Note the current convention is to use the -S and -B options here to specify source
|
||||||
# and build directories, but this is only available with CMake 3.13 and higher.
|
# and build directories, but this is only available with CMake 3.13 and higher.
|
||||||
# The CMake binaries on the Github Actions machines are (as of this writing) 3.12
|
# The CMake binaries on the Github Actions machines are (as of this writing) 3.12
|
||||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE
|
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE
|
||||||
|
|
||||||
@ -41,6 +41,6 @@ jobs:
|
|||||||
# - name: Test
|
# - name: Test
|
||||||
# working-directory: ${{runner.workspace}}/build
|
# working-directory: ${{runner.workspace}}/build
|
||||||
# shell: bash
|
# shell: bash
|
||||||
# Execute tests defined by the CMake configuration.
|
# Execute tests defined by the CMake configuration.
|
||||||
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
|
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
|
||||||
# run: ctest -C $BUILD_TYPE
|
# run: ctest -C $BUILD_TYPE
|
||||||
|
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@ -47,7 +47,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
# By default, queries listed here will override any specified in a config file.
|
# By default, queries listed here will override any specified in a config file.
|
||||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||||
|
|
||||||
|
@ -8,8 +8,6 @@ For ESP8266 and ESP32 [WifiManager](https://github.com/tzapu/WiFiManager) is use
|
|||||||
|
|
||||||
Don't forget to reset ESP8266 manually (disconnect power) after flashing. The reboot doen't work during configuration with ETS otherwise.
|
Don't forget to reset ESP8266 manually (disconnect power) after flashing. The reboot doen't work during configuration with ETS otherwise.
|
||||||
|
|
||||||
The SAMD21 version uses my version of the [FlashStorage](https://github.com/thelsing/FlashStorage) lib (Pull request pending).
|
|
||||||
|
|
||||||
Generated documentation can be found [here](https://knx.readthedocs.io/en/latest/).
|
Generated documentation can be found [here](https://knx.readthedocs.io/en/latest/).
|
||||||
|
|
||||||
## Stack configuration possibilities
|
## Stack configuration possibilities
|
||||||
@ -52,4 +50,4 @@ void main ()
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
More configuration options can be found in the examples.
|
More configuration options can be found in the examples.
|
||||||
|
@ -15,7 +15,6 @@ board = adafruit_feather_m0
|
|||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps =
|
lib_deps =
|
||||||
SPI
|
SPI
|
||||||
https://github.com/thelsing/FlashStorage.git
|
|
||||||
knx
|
knx
|
||||||
|
|
||||||
build_flags =
|
build_flags =
|
||||||
|
@ -24,7 +24,6 @@ lib_extra_dirs = ../../../
|
|||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
SPI
|
SPI
|
||||||
https://github.com/thelsing/FlashStorage.git
|
|
||||||
knx
|
knx
|
||||||
|
|
||||||
build_flags =
|
build_flags =
|
||||||
|
@ -15,7 +15,6 @@ board = adafruit_feather_m0
|
|||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps =
|
lib_deps =
|
||||||
SPI
|
SPI
|
||||||
https://github.com/thelsing/FlashStorage.git
|
|
||||||
knx
|
knx
|
||||||
|
|
||||||
build_flags =
|
build_flags =
|
||||||
|
@ -24,7 +24,6 @@ lib_extra_dirs = ../../../
|
|||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
SPI
|
SPI
|
||||||
https://github.com/thelsing/FlashStorage.git
|
|
||||||
knx
|
knx
|
||||||
|
|
||||||
build_flags =
|
build_flags =
|
||||||
@ -100,3 +99,50 @@ lib_deps =
|
|||||||
build_flags =
|
build_flags =
|
||||||
-DMASK_VERSION=0x07B0
|
-DMASK_VERSION=0x07B0
|
||||||
-Wno-unknown-pragmas
|
-Wno-unknown-pragmas
|
||||||
|
|
||||||
|
;--- STM32/GD32 ---
|
||||||
|
[env:h8i8o]
|
||||||
|
platform = ststm32
|
||||||
|
board = genericSTM32F103CB
|
||||||
|
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 =
|
||||||
|
-DENABLE_HWSERIAL1
|
||||||
|
-DPIN_SERIAL1_TX=PA9
|
||||||
|
-DPIN_SERIAL1_RX=PA10
|
||||||
|
-DKNX_SERIAL=Serial1
|
||||||
|
-DKNX_BUTTON=PA11
|
||||||
|
-DKNX_LED=PA12
|
||||||
|
-DMASK_VERSION=0x07B0
|
||||||
|
-Wno-unknown-pragmas
|
||||||
|
|
||||||
|
extra_scripts = ../scripts/stm32rdu.py
|
||||||
|
|
||||||
|
[env:h8c09]
|
||||||
|
platform = ststm32
|
||||||
|
board = genericSTM32F103CB
|
||||||
|
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 =
|
||||||
|
-DENABLE_HWSERIAL1
|
||||||
|
-DPIN_SERIAL1_TX=PA9
|
||||||
|
-DPIN_SERIAL1_RX=PA10
|
||||||
|
-DKNX_SERIAL=Serial1
|
||||||
|
-DKNX_BUTTON=PB0
|
||||||
|
-DKNX_LED=PB5
|
||||||
|
-DMASK_VERSION=0x07B0
|
||||||
|
-Wno-unknown-pragmas
|
||||||
|
|
||||||
|
extra_scripts = ../scripts/stm32rdu.py
|
||||||
|
210
examples/knx-h8i8o/knx-h8i8o.ino
Normal file
210
examples/knx-h8i8o/knx-h8i8o.ino
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <knx.h>
|
||||||
|
|
||||||
|
#define NUMIOS 18
|
||||||
|
|
||||||
|
#define goInputOnOff(i) knx.getGroupObject(i + 1)
|
||||||
|
#define goOutputOnOff(i) knx.getGroupObject(i + 1 + NUMIOS)
|
||||||
|
#define goOutputScaling(i) knx.getGroupObject(i + 1 + NUMIOS * 2)
|
||||||
|
#define goOutputOnOffStatus(i) knx.getGroupObject(i + 1 + NUMIOS * 3)
|
||||||
|
#define goOutputScalingStatus(i) knx.getGroupObject(i + 1 + NUMIOS * 4)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CONFIG_NONE = 0,
|
||||||
|
CONFIG_IN = 1,
|
||||||
|
CONFIG_IN_TOGGLE = 2,
|
||||||
|
CONFIG_IN_TOGGLE_ON = 3,
|
||||||
|
CONFIG_OUT = 4,
|
||||||
|
CONFIG_OUT_ON = 5,
|
||||||
|
CONFIG_OUT_PWM = 6,
|
||||||
|
CONFIG_OUT_PWM_ON = 7,
|
||||||
|
} config_t;
|
||||||
|
|
||||||
|
inline void isrIn(uint8_t pin, uint8_t toggle);
|
||||||
|
|
||||||
|
// workaround for the weird Arduino interrupt handling
|
||||||
|
#define ISR_IN(NUM, TOGGLE) void isrIn##NUM##_##TOGGLE(){isrIn(NUM, TOGGLE);}
|
||||||
|
ISR_IN(0,0);
|
||||||
|
ISR_IN(1,0);
|
||||||
|
ISR_IN(2,0);
|
||||||
|
ISR_IN(3,0);
|
||||||
|
ISR_IN(4,0);
|
||||||
|
ISR_IN(5,0);
|
||||||
|
ISR_IN(6,0);
|
||||||
|
ISR_IN(7,0);
|
||||||
|
ISR_IN(8,0);
|
||||||
|
ISR_IN(9,0);
|
||||||
|
ISR_IN(10,0);
|
||||||
|
ISR_IN(11,0);
|
||||||
|
ISR_IN(12,0);
|
||||||
|
ISR_IN(13,0);
|
||||||
|
ISR_IN(14,0);
|
||||||
|
ISR_IN(15,0);
|
||||||
|
ISR_IN(16,0);
|
||||||
|
ISR_IN(17,0);
|
||||||
|
ISR_IN(0,1);
|
||||||
|
ISR_IN(1,1);
|
||||||
|
ISR_IN(2,1);
|
||||||
|
ISR_IN(3,1);
|
||||||
|
ISR_IN(4,1);
|
||||||
|
ISR_IN(5,1);
|
||||||
|
ISR_IN(6,1);
|
||||||
|
ISR_IN(7,1);
|
||||||
|
ISR_IN(8,1);
|
||||||
|
ISR_IN(9,1);
|
||||||
|
ISR_IN(10,1);
|
||||||
|
ISR_IN(11,1);
|
||||||
|
ISR_IN(12,1);
|
||||||
|
ISR_IN(13,1);
|
||||||
|
ISR_IN(14,1);
|
||||||
|
ISR_IN(15,1);
|
||||||
|
ISR_IN(16,1);
|
||||||
|
ISR_IN(17,1);
|
||||||
|
|
||||||
|
const uint32_t pinTbl[NUMIOS] = {PA15, PB3, PB4, PB5, PB6, PB7, PB8, PB9, PC13, PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PB0};
|
||||||
|
void (*inCbTbl[NUMIOS * 2])(void) = {isrIn0_0, isrIn1_0, isrIn2_0, isrIn3_0, isrIn4_0, isrIn5_0, isrIn6_0, isrIn7_0, isrIn8_0, isrIn9_0, isrIn10_0, isrIn11_0, isrIn12_0, isrIn13_0, isrIn14_0, isrIn15_0, isrIn16_0, isrIn17_0, isrIn0_1, isrIn1_1, isrIn2_1, isrIn3_1, isrIn4_1, isrIn5_1, isrIn6_1, isrIn7_1, isrIn8_1, isrIn9_1, isrIn10_1, isrIn11_1, isrIn12_1, isrIn13_1, isrIn14_1, isrIn15_1, isrIn16_1, isrIn17_1};
|
||||||
|
volatile uint16_t val[NUMIOS];
|
||||||
|
uint32_t lastEvent[NUMIOS];
|
||||||
|
|
||||||
|
// callback for OnOff events from KNX
|
||||||
|
void outOnOff(GroupObject& go)
|
||||||
|
{
|
||||||
|
uint8_t pin = go.asap() - 1 - NUMIOS;
|
||||||
|
val[pin] = go.value();
|
||||||
|
val[pin] &= 1;
|
||||||
|
digitalWrite(pinTbl[pin], val[pin]);
|
||||||
|
goOutputOnOffStatus(pin).value(val[pin]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback for OnOff events from KNX on PWM pins
|
||||||
|
void outOnOffPWM(GroupObject& go)
|
||||||
|
{
|
||||||
|
uint8_t pin = go.asap() - 1 - NUMIOS;
|
||||||
|
uint8_t tmp;
|
||||||
|
if(go.value()){
|
||||||
|
val[pin] |= 0x100;
|
||||||
|
analogWrite(pinTbl[pin], val[pin] & 0xff);
|
||||||
|
}else{
|
||||||
|
val[pin] &= 0xff;
|
||||||
|
analogWrite(pinTbl[pin], 0);
|
||||||
|
}
|
||||||
|
tmp = val[pin] >> 8;
|
||||||
|
goOutputOnOffStatus(pin).value(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback for 0-100% events from KNX
|
||||||
|
void outScaling(GroupObject& go)
|
||||||
|
{
|
||||||
|
uint8_t pin = go.asap() - NUMIOS * 2 - 1;
|
||||||
|
uint8_t tmp;
|
||||||
|
if(val[pin] > 0xFF){
|
||||||
|
tmp = *go.valueRef();
|
||||||
|
val[pin] = tmp | 1 << 8;
|
||||||
|
analogWrite(pinTbl[pin], val[pin] & 0xff);
|
||||||
|
}else{
|
||||||
|
tmp = *go.valueRef();
|
||||||
|
val[pin] = tmp;
|
||||||
|
}
|
||||||
|
*goOutputScalingStatus(pin).valueRef() = tmp;
|
||||||
|
goOutputScalingStatus(pin).objectWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback for input interrupts
|
||||||
|
inline void isrIn(uint8_t pin, uint8_t toggle)
|
||||||
|
{
|
||||||
|
uint32_t diff = millis() - lastEvent[pin];
|
||||||
|
if (diff >= 50 && diff <= 500){
|
||||||
|
if(toggle){
|
||||||
|
val[pin]++;
|
||||||
|
}else{
|
||||||
|
val[pin] = digitalRead(pinTbl[pin]);
|
||||||
|
}
|
||||||
|
val[pin] &= 1;
|
||||||
|
goInputOnOff(pin).value(val[pin]);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastEvent[pin] = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
// 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())
|
||||||
|
{
|
||||||
|
uint8_t progIn = knx.paramByte(0); // programming input
|
||||||
|
uint8_t progLed = knx.paramByte(1); // programming LED
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i < NUMIOS; i++){
|
||||||
|
config_t config = (config_t) knx.paramByte(i + 2);
|
||||||
|
// loop through all the pins and configure them correctly
|
||||||
|
switch(config){
|
||||||
|
case CONFIG_IN:
|
||||||
|
pinMode(pinTbl[i], INPUT_PULLUP);
|
||||||
|
if(progIn = i + 1){
|
||||||
|
knx.buttonPin(pinTbl[i]);
|
||||||
|
}else{
|
||||||
|
goInputOnOff(i).dataPointType(DPT_Switch);
|
||||||
|
#if (ARDUINO_API_VERSION >= 10200)
|
||||||
|
attachInterrupt(digitalPinToInterrupt(pinTbl[i]), inCbTbl[i], (PinStatus)CHANGE);
|
||||||
|
#else
|
||||||
|
attachInterrupt(digitalPinToInterrupt(pinTbl[i]), inCbTbl[i], CHANGE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CONFIG_IN_TOGGLE:
|
||||||
|
case CONFIG_IN_TOGGLE_ON:
|
||||||
|
goInputOnOff(i).dataPointType(DPT_Switch);
|
||||||
|
val[i] = config == CONFIG_IN_TOGGLE_ON;
|
||||||
|
pinMode(pinTbl[i], INPUT_PULLUP);
|
||||||
|
#if (ARDUINO_API_VERSION >= 10200)
|
||||||
|
attachInterrupt(digitalPinToInterrupt(pinTbl[i]), inCbTbl[i + NUMIOS], (PinStatus)CHANGE);
|
||||||
|
#else
|
||||||
|
attachInterrupt(digitalPinToInterrupt(pinTbl[i]), inCbTbl[i + NUMIOS], CHANGE);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case CONFIG_OUT:
|
||||||
|
case CONFIG_OUT_ON:
|
||||||
|
pinMode(pinTbl[i], OUTPUT);
|
||||||
|
val[i] = config == CONFIG_OUT_ON;
|
||||||
|
digitalWrite(pinTbl[i], val[i]);
|
||||||
|
if(progLed = i + 1){
|
||||||
|
knx.ledPin(pinTbl[i]);
|
||||||
|
}else{
|
||||||
|
goOutputOnOff(i).dataPointType(DPT_Switch);
|
||||||
|
goOutputOnOff(i).callback(outOnOff);
|
||||||
|
goOutputOnOffStatus(i).dataPointType(DPT_Switch);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CONFIG_OUT_PWM:
|
||||||
|
case CONFIG_OUT_PWM_ON:
|
||||||
|
pinMode(pinTbl[i], OUTPUT);
|
||||||
|
val[i] = config == CONFIG_OUT_PWM_ON ? 0 : 0x1ff;
|
||||||
|
analogWrite(pinTbl[i], val[i] & 0xff);
|
||||||
|
goOutputOnOff(i).dataPointType(DPT_Switch);
|
||||||
|
goOutputOnOff(i).callback(outOnOffPWM);
|
||||||
|
goOutputOnOffStatus(i).dataPointType(DPT_Switch);
|
||||||
|
goOutputScaling(i).dataPointType(DPT_Scaling);
|
||||||
|
goOutputScaling(i).callback(outScaling);
|
||||||
|
goOutputScalingStatus(i).dataPointType(DPT_Scaling);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// start the framework.
|
||||||
|
knx.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
// don't delay here too 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;
|
||||||
|
}
|
BIN
examples/knx-h8i8o/knx-h8i8o.knxprod
Normal file
BIN
examples/knx-h8i8o/knx-h8i8o.knxprod
Normal file
Binary file not shown.
2198
examples/knx-h8i8o/knx-h8i8o.xml
Normal file
2198
examples/knx-h8i8o/knx-h8i8o.xml
Normal file
File diff suppressed because it is too large
Load Diff
39
examples/knx-h8i8o/platformio.ini
Normal file
39
examples/knx-h8i8o/platformio.ini
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
;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 = .
|
||||||
|
|
||||||
|
;--- STM32/GD32 ---
|
||||||
|
[env:h8i8o]
|
||||||
|
platform = ststm32
|
||||||
|
board = genericSTM32F103CB
|
||||||
|
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 =
|
||||||
|
-DENABLE_HWSERIAL1
|
||||||
|
-DPIN_SERIAL1_TX=PA9
|
||||||
|
-DPIN_SERIAL1_RX=PA10
|
||||||
|
-DKNX_SERIAL=Serial1
|
||||||
|
-DKNX_BUTTON=PA11
|
||||||
|
-DKNX_LED=PA12
|
||||||
|
-DMASK_VERSION=0x07B0
|
||||||
|
-DKNX_NO_PRINT
|
||||||
|
-Wno-unknown-pragmas
|
||||||
|
|
||||||
|
extra_scripts = ../scripts/stm32rdu.py
|
@ -20,7 +20,6 @@ board_build.usb_product="KNX RF - USB Interface"
|
|||||||
lib_deps =
|
lib_deps =
|
||||||
SPI
|
SPI
|
||||||
Adafruit TinyUSB Library@0.7.1
|
Adafruit TinyUSB Library@0.7.1
|
||||||
https://github.com/thelsing/FlashStorage.git
|
|
||||||
knx
|
knx
|
||||||
|
|
||||||
build_flags =
|
build_flags =
|
||||||
|
34
examples/scripts/stm32rdu.py
Executable file
34
examples/scripts/stm32rdu.py
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
from subprocess import run
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from os.path import expanduser
|
||||||
|
|
||||||
|
ocddir = expanduser("~/.platformio/packages/tool-openocd/")
|
||||||
|
chip = "stm32f1x"
|
||||||
|
|
||||||
|
def unlock(*args, **kwargs):
|
||||||
|
print("Please connect the board within the next two minutes.")
|
||||||
|
endtime = datetime.now() + timedelta(minutes = 1)
|
||||||
|
ret = 1
|
||||||
|
while ret != 0 and datetime.now() < endtime:
|
||||||
|
ret = run(["bin/openocd", "-f", "interface/stlink.cfg", "-f", "target/" + chip + ".cfg", "-c", "init", "-c", "reset halt", "-c", chip + " unlock 0", "-c", "reset halt", "-c", "exit"], cwd = ocddir).returncode
|
||||||
|
if ret != 0:
|
||||||
|
print("Timeout")
|
||||||
|
return ret
|
||||||
|
|
||||||
|
try:
|
||||||
|
Import("env")
|
||||||
|
except NameError:
|
||||||
|
import sys
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
chip = sys.argv[1]
|
||||||
|
if len(sys.argv) > 2:
|
||||||
|
ocddir = sys.argv[2]
|
||||||
|
unlock(None, None)
|
||||||
|
else:
|
||||||
|
ocddir = env.PioPlatform().get_package_dir("tool-openocd")
|
||||||
|
options = env.GetProjectOptions()
|
||||||
|
for option in options:
|
||||||
|
if "unlock_chip" == option[0]:
|
||||||
|
chip = option[1]
|
||||||
|
env.AddCustomTarget("unlock", None, unlock)
|
@ -7,7 +7,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef KNX_NO_PRINT
|
#ifndef KNX_NO_PRINT
|
||||||
Stream* ArduinoPlatform::SerialDebug = &Serial;
|
Stream* ArduinoPlatform::SerialDebug = &KNX_DEBUG_SERIAL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ArduinoPlatform::ArduinoPlatform() : _knxSerial(nullptr)
|
ArduinoPlatform::ArduinoPlatform() : _knxSerial(nullptr)
|
||||||
@ -22,13 +22,13 @@ void ArduinoPlatform::fatalError()
|
|||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
#ifdef LED_BUILTIN
|
#ifdef KNX_LED
|
||||||
static const long LED_BLINK_PERIOD = 200;
|
static const long LED_BLINK_PERIOD = 200;
|
||||||
|
|
||||||
if ((millis() % LED_BLINK_PERIOD) > (LED_BLINK_PERIOD / 2))
|
if ((millis() % LED_BLINK_PERIOD) > (LED_BLINK_PERIOD / 2))
|
||||||
digitalWrite(LED_BUILTIN, HIGH);
|
digitalWrite(KNX_LED, HIGH);
|
||||||
else
|
else
|
||||||
digitalWrite(LED_BUILTIN, LOW);
|
digitalWrite(KNX_LED, LOW);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
#ifndef KNX_DEBUG_SERIAL
|
||||||
|
#define KNX_DEBUG_SERIAL Serial
|
||||||
|
#endif
|
||||||
|
|
||||||
class ArduinoPlatform : public Platform
|
class ArduinoPlatform : public Platform
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -17,11 +17,11 @@ class CC1310Platform : public Platform
|
|||||||
void init();
|
void init();
|
||||||
|
|
||||||
// basic stuff
|
// basic stuff
|
||||||
virtual void restart() final;
|
void restart() final;
|
||||||
virtual void fatalError() final;
|
void fatalError() final;
|
||||||
|
|
||||||
virtual uint8_t* getEepromBuffer(uint16_t size) final;
|
uint8_t* getEepromBuffer(uint16_t size) final;
|
||||||
virtual void commitToEeprom() final;
|
void commitToEeprom() final;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //DeviceFamily_CC13X0
|
#endif //DeviceFamily_CC13X0
|
||||||
|
@ -6,9 +6,13 @@
|
|||||||
|
|
||||||
#include "knx/bits.h"
|
#include "knx/bits.h"
|
||||||
|
|
||||||
|
#ifndef KNX_SERIAL
|
||||||
|
#define KNX_SERIAL Serial1
|
||||||
|
#endif
|
||||||
|
|
||||||
Esp32Platform::Esp32Platform()
|
Esp32Platform::Esp32Platform()
|
||||||
#ifndef KNX_NO_DEFAULT_UART
|
#ifndef KNX_NO_DEFAULT_UART
|
||||||
: ArduinoPlatform(&Serial1)
|
: ArduinoPlatform(&KNX_SERIAL)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -55,10 +59,10 @@ void Esp32Platform::setupMultiCast(uint32_t addr, uint16_t port)
|
|||||||
{
|
{
|
||||||
IPAddress mcastaddr(htonl(addr));
|
IPAddress mcastaddr(htonl(addr));
|
||||||
|
|
||||||
Serial.printf("setup multicast addr: %s port: %d ip: %s\n", mcastaddr.toString().c_str(), port,
|
KNX_DEBUG_SERIAL.printf("setup multicast addr: %s port: %d ip: %s\n", mcastaddr.toString().c_str(), port,
|
||||||
WiFi.localIP().toString().c_str());
|
WiFi.localIP().toString().c_str());
|
||||||
uint8_t result = _udp.beginMulticast(mcastaddr, port);
|
uint8_t result = _udp.beginMulticast(mcastaddr, port);
|
||||||
Serial.printf("result %d\n", result);
|
KNX_DEBUG_SERIAL.printf("result %d\n", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Esp32Platform::closeMultiCast()
|
void Esp32Platform::closeMultiCast()
|
||||||
@ -83,7 +87,7 @@ int Esp32Platform::readBytesMultiCast(uint8_t * buffer, uint16_t maxLen)
|
|||||||
|
|
||||||
if (len > maxLen)
|
if (len > maxLen)
|
||||||
{
|
{
|
||||||
Serial.printf("udp buffer to small. was %d, needed %d\n", maxLen, len);
|
KNX_DEBUG_SERIAL.printf("udp buffer to small. was %d, needed %d\n", maxLen, len);
|
||||||
fatalError();
|
fatalError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,8 +110,12 @@ bool Esp32Platform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buff
|
|||||||
|
|
||||||
uint8_t * Esp32Platform::getEepromBuffer(uint16_t size)
|
uint8_t * Esp32Platform::getEepromBuffer(uint16_t size)
|
||||||
{
|
{
|
||||||
EEPROM.begin(size);
|
uint8_t * eepromptr = EEPROM.getDataPtr();
|
||||||
return EEPROM.getDataPtr();
|
if(eepromptr == nullptr) {
|
||||||
|
EEPROM.begin(size);
|
||||||
|
eepromptr = EEPROM.getDataPtr();
|
||||||
|
}
|
||||||
|
return eepromptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Esp32Platform::commitToEeprom()
|
void Esp32Platform::commitToEeprom()
|
||||||
|
@ -7,9 +7,13 @@
|
|||||||
|
|
||||||
#include "knx/bits.h"
|
#include "knx/bits.h"
|
||||||
|
|
||||||
|
#ifndef KNX_SERIAL
|
||||||
|
#define KNX_SERIAL Serial
|
||||||
|
#endif
|
||||||
|
|
||||||
EspPlatform::EspPlatform()
|
EspPlatform::EspPlatform()
|
||||||
#ifndef KNX_NO_DEFAULT_UART
|
#ifndef KNX_NO_DEFAULT_UART
|
||||||
: ArduinoPlatform(&Serial)
|
: ArduinoPlatform(&KNX_SERIAL)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -55,10 +59,10 @@ void EspPlatform::setupMultiCast(uint32_t addr, uint16_t port)
|
|||||||
_multicastPort = port;
|
_multicastPort = port;
|
||||||
IPAddress mcastaddr(_multicastAddr);
|
IPAddress mcastaddr(_multicastAddr);
|
||||||
|
|
||||||
Serial.printf("setup multicast addr: %s port: %d ip: %s\n", mcastaddr.toString().c_str(), port,
|
KNX_DEBUG_SERIAL.printf("setup multicast addr: %s port: %d ip: %s\n", mcastaddr.toString().c_str(), port,
|
||||||
WiFi.localIP().toString().c_str());
|
WiFi.localIP().toString().c_str());
|
||||||
uint8 result = _udp.beginMulticast(WiFi.localIP(), mcastaddr, port);
|
uint8 result = _udp.beginMulticast(WiFi.localIP(), mcastaddr, port);
|
||||||
Serial.printf("result %d\n", result);
|
KNX_DEBUG_SERIAL.printf("result %d\n", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EspPlatform::closeMultiCast()
|
void EspPlatform::closeMultiCast()
|
||||||
@ -83,7 +87,7 @@ int EspPlatform::readBytesMultiCast(uint8_t * buffer, uint16_t maxLen)
|
|||||||
|
|
||||||
if (len > maxLen)
|
if (len > maxLen)
|
||||||
{
|
{
|
||||||
Serial.printf("udp buffer to small. was %d, needed %d\n", maxLen, len);
|
KNX_DEBUG_SERIAL.printf("udp buffer to small. was %d, needed %d\n", maxLen, len);
|
||||||
fatalError();
|
fatalError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,8 +110,12 @@ bool EspPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer
|
|||||||
|
|
||||||
uint8_t * EspPlatform::getEepromBuffer(uint16_t size)
|
uint8_t * EspPlatform::getEepromBuffer(uint16_t size)
|
||||||
{
|
{
|
||||||
EEPROM.begin(size);
|
uint8_t * eepromptr = EEPROM.getDataPtr();
|
||||||
return EEPROM.getDataPtr();
|
if(eepromptr == nullptr) {
|
||||||
|
EEPROM.begin(size);
|
||||||
|
eepromptr = EEPROM.getDataPtr();
|
||||||
|
}
|
||||||
|
return eepromptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EspPlatform::commitToEeprom()
|
void EspPlatform::commitToEeprom()
|
||||||
|
@ -19,7 +19,8 @@ AddressTableObject::AddressTableObject(Memory& memory)
|
|||||||
|
|
||||||
uint16_t AddressTableObject::entryCount()
|
uint16_t AddressTableObject::entryCount()
|
||||||
{
|
{
|
||||||
if (loadState() != LS_LOADED)
|
// after programming without GA the module hangs
|
||||||
|
if (loadState() != LS_LOADED || _groupAddresses[0] == 0xFFFF)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return ntohs(_groupAddresses[0]);
|
return ntohs(_groupAddresses[0]);
|
||||||
@ -104,6 +105,7 @@ bool AddressTableObject::contains(uint16_t addr)
|
|||||||
|
|
||||||
void AddressTableObject::beforeStateChange(LoadState& newState)
|
void AddressTableObject::beforeStateChange(LoadState& newState)
|
||||||
{
|
{
|
||||||
|
TableObject::beforeStateChange(newState);
|
||||||
if (newState != LS_LOADED)
|
if (newState != LS_LOADED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ class AddressTableObject : public TableObject
|
|||||||
bool contains(uint16_t groupAddress);
|
bool contains(uint16_t groupAddress);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void beforeStateChange(LoadState& newState) override;
|
void beforeStateChange(LoadState& newState) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t* _groupAddresses = 0;
|
uint16_t* _groupAddresses = 0;
|
||||||
|
@ -347,7 +347,7 @@ void ApplicationLayer::dataConnectedConfirm(uint16_t tsap)
|
|||||||
|
|
||||||
void ApplicationLayer::dataConnectedConfirm(uint16_t tsap, const SecurityControl& secCtrl)
|
void ApplicationLayer::dataConnectedConfirm(uint16_t tsap, const SecurityControl& secCtrl)
|
||||||
{
|
{
|
||||||
|
//FIXME: implement dataConnectedConfirm DataSecurity
|
||||||
}
|
}
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
void ApplicationLayer::groupValueReadRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl)
|
void ApplicationLayer::groupValueReadRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl)
|
||||||
|
@ -157,7 +157,6 @@ class ApplicationLayer
|
|||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
#pragma region hooks
|
#pragma region hooks
|
||||||
void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl &secCtrl);
|
void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl &secCtrl);
|
||||||
void dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap,
|
void dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap,
|
||||||
|
@ -84,6 +84,7 @@ int32_t AssociationTableObject::translateAsap(uint16_t asap)
|
|||||||
|
|
||||||
void AssociationTableObject::beforeStateChange(LoadState& newState)
|
void AssociationTableObject::beforeStateChange(LoadState& newState)
|
||||||
{
|
{
|
||||||
|
TableObject::beforeStateChange(newState);
|
||||||
if (newState != LS_LOADED)
|
if (newState != LS_LOADED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -338,3 +338,12 @@ void BusAccessUnit::propertyValueWrite(ObjectType objectType, uint8_t objectInst
|
|||||||
uint8_t* data, uint32_t length)
|
uint8_t* data, uint32_t length)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::beforeRestartCallback(BeforeRestartCallback func)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BeforeRestartCallback BusAccessUnit::beforeRestartCallback()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#include "knx_types.h"
|
#include "knx_types.h"
|
||||||
#include "interface_object.h"
|
#include "interface_object.h"
|
||||||
|
|
||||||
|
typedef void (*BeforeRestartCallback)(void);
|
||||||
|
|
||||||
class BusAccessUnit
|
class BusAccessUnit
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -161,4 +163,6 @@ class BusAccessUnit
|
|||||||
virtual void propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId,
|
virtual void propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId,
|
||||||
uint8_t& numberOfElements, uint16_t startIndex,
|
uint8_t& numberOfElements, uint16_t startIndex,
|
||||||
uint8_t* data, uint32_t length);
|
uint8_t* data, uint32_t length);
|
||||||
|
virtual void beforeRestartCallback(BeforeRestartCallback func);
|
||||||
|
virtual BeforeRestartCallback beforeRestartCallback();
|
||||||
};
|
};
|
||||||
|
@ -12,16 +12,16 @@ class Bau07B0 : public BauSystemBDevice, public ITpUartCallBacks
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Bau07B0(Platform& platform);
|
Bau07B0(Platform& platform);
|
||||||
virtual void loop() override;
|
void loop() override;
|
||||||
virtual bool enabled() override;
|
bool enabled() override;
|
||||||
virtual void enabled(bool value) override;
|
void enabled(bool value) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
InterfaceObject* getInterfaceObject(uint8_t idx);
|
InterfaceObject* getInterfaceObject(uint8_t idx);
|
||||||
InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance);
|
InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance);
|
||||||
|
|
||||||
// For TP1 only
|
// For TP1 only
|
||||||
virtual bool isAckRequired(uint16_t address, bool isGrpAddr) override;
|
bool isAckRequired(uint16_t address, bool isGrpAddr) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TpUartDataLinkLayer _dlLayer;
|
TpUartDataLinkLayer _dlLayer;
|
||||||
|
@ -14,18 +14,18 @@ class Bau091A : public BauSystemBCoupler, public ITpUartCallBacks
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Bau091A(Platform& platform);
|
Bau091A(Platform& platform);
|
||||||
virtual void loop() override;
|
void loop() override;
|
||||||
virtual bool enabled() override;
|
bool enabled() override;
|
||||||
virtual void enabled(bool value) override;
|
void enabled(bool value) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
InterfaceObject* getInterfaceObject(uint8_t idx);
|
InterfaceObject* getInterfaceObject(uint8_t idx);
|
||||||
InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance);
|
InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance);
|
||||||
|
|
||||||
// For TP1 only
|
// For TP1 only
|
||||||
virtual bool isAckRequired(uint16_t address, bool isGrpAddr) override;
|
bool isAckRequired(uint16_t address, bool isGrpAddr) override;
|
||||||
|
|
||||||
virtual void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
||||||
private:
|
private:
|
||||||
RouterObject _routerObj;
|
RouterObject _routerObj;
|
||||||
IpParameterObject _ipParameters;
|
IpParameterObject _ipParameters;
|
||||||
|
@ -18,15 +18,15 @@ class Bau27B0 : public BauSystemBDevice
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Bau27B0(Platform& platform);
|
Bau27B0(Platform& platform);
|
||||||
virtual void loop() override;
|
void loop() override;
|
||||||
virtual bool enabled() override;
|
bool enabled() override;
|
||||||
virtual void enabled(bool value) override;
|
void enabled(bool value) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
InterfaceObject* getInterfaceObject(uint8_t idx);
|
InterfaceObject* getInterfaceObject(uint8_t idx);
|
||||||
InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance);
|
InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance);
|
||||||
|
|
||||||
virtual void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
||||||
private:
|
private:
|
||||||
RfDataLinkLayer _dlLayer;
|
RfDataLinkLayer _dlLayer;
|
||||||
RfMediumObject _rfMediumObj;
|
RfMediumObject _rfMediumObj;
|
||||||
|
@ -18,15 +18,15 @@ class Bau2920 : public BauSystemBCoupler
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Bau2920(Platform& platform);
|
Bau2920(Platform& platform);
|
||||||
virtual void loop() override;
|
void loop() override;
|
||||||
virtual bool enabled() override;
|
bool enabled() override;
|
||||||
virtual void enabled(bool value) override;
|
void enabled(bool value) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
InterfaceObject* getInterfaceObject(uint8_t idx);
|
InterfaceObject* getInterfaceObject(uint8_t idx);
|
||||||
InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance);
|
InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance);
|
||||||
|
|
||||||
virtual void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
||||||
private:
|
private:
|
||||||
RouterObject _rtObjPrimary;
|
RouterObject _rtObjPrimary;
|
||||||
RouterObject _rtObjSecondary;
|
RouterObject _rtObjSecondary;
|
||||||
|
@ -12,15 +12,15 @@ class Bau57B0 : public BauSystemBDevice
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Bau57B0(Platform& platform);
|
Bau57B0(Platform& platform);
|
||||||
virtual void loop() override;
|
void loop() override;
|
||||||
virtual bool enabled() override;
|
bool enabled() override;
|
||||||
virtual void enabled(bool value) override;
|
void enabled(bool value) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
InterfaceObject* getInterfaceObject(uint8_t idx);
|
InterfaceObject* getInterfaceObject(uint8_t idx);
|
||||||
InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance);
|
InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance);
|
||||||
|
|
||||||
virtual void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
||||||
private:
|
private:
|
||||||
IpParameterObject _ipParameters;
|
IpParameterObject _ipParameters;
|
||||||
IpDataLinkLayer _dlLayer;
|
IpDataLinkLayer _dlLayer;
|
||||||
|
@ -31,6 +31,11 @@ void BauSystemB::writeMemory()
|
|||||||
_memory.writeMemory();
|
_memory.writeMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Platform& BauSystemB::platform()
|
||||||
|
{
|
||||||
|
return _platform;
|
||||||
|
}
|
||||||
|
|
||||||
ApplicationProgramObject& BauSystemB::parameters()
|
ApplicationProgramObject& BauSystemB::parameters()
|
||||||
{
|
{
|
||||||
return _appProgram;
|
return _appProgram;
|
||||||
@ -112,9 +117,14 @@ void BauSystemB::memoryWriteIndication(Priority priority, HopCountType hopType,
|
|||||||
uint16_t memoryAddress, uint8_t * data)
|
uint16_t memoryAddress, uint8_t * data)
|
||||||
{
|
{
|
||||||
_memory.writeMemory(memoryAddress, number, data);
|
_memory.writeMemory(memoryAddress, number, data);
|
||||||
|
|
||||||
if (_deviceObj.verifyMode())
|
if (_deviceObj.verifyMode())
|
||||||
memoryReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress);
|
memoryReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t * data)
|
||||||
|
{
|
||||||
|
applicationLayer().memoryReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BauSystemB::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number,
|
void BauSystemB::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number,
|
||||||
@ -147,6 +157,8 @@ void BauSystemB::restartRequestIndication(Priority priority, HopCountType hopTyp
|
|||||||
if (restartType == RestartType::BasicRestart)
|
if (restartType == RestartType::BasicRestart)
|
||||||
{
|
{
|
||||||
println("Basic restart requested");
|
println("Basic restart requested");
|
||||||
|
if (_beforeRestart != 0)
|
||||||
|
_beforeRestart();
|
||||||
}
|
}
|
||||||
else if (restartType == RestartType::MasterReset)
|
else if (restartType == RestartType::MasterReset)
|
||||||
{
|
{
|
||||||
@ -606,3 +618,23 @@ Memory& BauSystemB::memory()
|
|||||||
{
|
{
|
||||||
return _memory;
|
return _memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BauSystemB::versionCheckCallback(VersionCheckCallback func)
|
||||||
|
{
|
||||||
|
_memory.versionCheckCallback(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionCheckCallback BauSystemB::versionCheckCallback()
|
||||||
|
{
|
||||||
|
return _memory.versionCheckCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::beforeRestartCallback(BeforeRestartCallback func)
|
||||||
|
{
|
||||||
|
_beforeRestart = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
BeforeRestartCallback BauSystemB::beforeRestartCallback()
|
||||||
|
{
|
||||||
|
return _beforeRestart;
|
||||||
|
}
|
||||||
|
@ -21,6 +21,7 @@ class BauSystemB : protected BusAccessUnit
|
|||||||
virtual bool enabled() = 0;
|
virtual bool enabled() = 0;
|
||||||
virtual void enabled(bool value) = 0;
|
virtual void enabled(bool value) = 0;
|
||||||
|
|
||||||
|
Platform& platform();
|
||||||
ApplicationProgramObject& parameters();
|
ApplicationProgramObject& parameters();
|
||||||
DeviceObject& deviceObject();
|
DeviceObject& deviceObject();
|
||||||
|
|
||||||
@ -38,6 +39,10 @@ class BauSystemB : protected BusAccessUnit
|
|||||||
void propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId,
|
void propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId,
|
||||||
uint8_t& numberOfElements, uint16_t startIndex,
|
uint8_t& numberOfElements, uint16_t startIndex,
|
||||||
uint8_t* data, uint32_t length) override;
|
uint8_t* data, uint32_t length) override;
|
||||||
|
void versionCheckCallback(VersionCheckCallback func);
|
||||||
|
VersionCheckCallback versionCheckCallback();
|
||||||
|
void beforeRestartCallback(BeforeRestartCallback func);
|
||||||
|
BeforeRestartCallback beforeRestartCallback();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ApplicationLayer& applicationLayer() = 0;
|
virtual ApplicationLayer& applicationLayer() = 0;
|
||||||
@ -48,6 +53,8 @@ class BauSystemB : protected BusAccessUnit
|
|||||||
uint16_t memoryAddress, uint8_t* data) override;
|
uint16_t memoryAddress, uint8_t* data) override;
|
||||||
void memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number,
|
void memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number,
|
||||||
uint16_t memoryAddress) override;
|
uint16_t memoryAddress) override;
|
||||||
|
void memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t * data);
|
||||||
void memoryExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number,
|
void memoryExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number,
|
||||||
uint32_t memoryAddress, uint8_t* data) override;
|
uint32_t memoryAddress, uint8_t* data) override;
|
||||||
void memoryExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number,
|
void memoryExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number,
|
||||||
@ -105,4 +112,5 @@ class BauSystemB : protected BusAccessUnit
|
|||||||
RestartState _restartState = Idle;
|
RestartState _restartState = Idle;
|
||||||
SecurityControl _restartSecurity;
|
SecurityControl _restartSecurity;
|
||||||
uint32_t _restartDelay = 0;
|
uint32_t _restartDelay = 0;
|
||||||
|
BeforeRestartCallback _beforeRestart = 0;
|
||||||
};
|
};
|
||||||
|
@ -21,7 +21,6 @@ BauSystemBCoupler::BauSystemBCoupler(Platform& platform) :
|
|||||||
#ifdef USE_DATASECURE
|
#ifdef USE_DATASECURE
|
||||||
_memory.addSaveRestore(&_secIfObj);
|
_memory.addSaveRestore(&_secIfObj);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplicationLayer& BauSystemBCoupler::applicationLayer()
|
ApplicationLayer& BauSystemBCoupler::applicationLayer()
|
||||||
|
@ -18,13 +18,13 @@ class BauSystemBCoupler : public BauSystemB
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BauSystemBCoupler(Platform& platform);
|
BauSystemBCoupler(Platform& platform);
|
||||||
virtual void loop() override;
|
void loop() override;
|
||||||
virtual bool configured() override;
|
bool configured() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ApplicationLayer& applicationLayer() override;
|
ApplicationLayer& applicationLayer() override;
|
||||||
|
|
||||||
virtual void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
||||||
|
|
||||||
Platform& _platform;
|
Platform& _platform;
|
||||||
|
|
||||||
|
@ -23,9 +23,9 @@ BauSystemBDevice::BauSystemBDevice(Platform& platform) :
|
|||||||
_transLayer.groupAddressTable(_addrTable);
|
_transLayer.groupAddressTable(_addrTable);
|
||||||
|
|
||||||
_memory.addSaveRestore(&_deviceObj);
|
_memory.addSaveRestore(&_deviceObj);
|
||||||
|
_memory.addSaveRestore(&_groupObjTable); // changed order for better memory management
|
||||||
_memory.addSaveRestore(&_addrTable);
|
_memory.addSaveRestore(&_addrTable);
|
||||||
_memory.addSaveRestore(&_assocTable);
|
_memory.addSaveRestore(&_assocTable);
|
||||||
_memory.addSaveRestore(&_groupObjTable);
|
|
||||||
#ifdef USE_DATASECURE
|
#ifdef USE_DATASECURE
|
||||||
_memory.addSaveRestore(&_secIfObj);
|
_memory.addSaveRestore(&_secIfObj);
|
||||||
#endif
|
#endif
|
||||||
@ -69,8 +69,21 @@ void BauSystemBDevice::sendNextGroupTelegram()
|
|||||||
if (flag != ReadRequest && flag != WriteRequest)
|
if (flag != ReadRequest && flag != WriteRequest)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (flag == WriteRequest)
|
||||||
|
{
|
||||||
|
#ifdef SMALL_GROUPOBJECT
|
||||||
|
GroupObject::processClassCallback(go);
|
||||||
|
#else
|
||||||
|
GroupObjectUpdatedHandler handler = go.callback();
|
||||||
|
if (handler)
|
||||||
|
handler(go);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
if (!go.communicationEnable())
|
if (!go.communicationEnable())
|
||||||
|
{
|
||||||
|
go.commFlag(Ok);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
SecurityControl goSecurity;
|
SecurityControl goSecurity;
|
||||||
goSecurity.toolAccess = false; // Secured group communication never uses the toolkey. ETS knows all keys, also the group keys.
|
goSecurity.toolAccess = false; // Secured group communication never uses the toolkey. ETS knows all keys, also the group keys.
|
||||||
@ -113,14 +126,21 @@ void BauSystemBDevice::updateGroupObject(GroupObject & go, uint8_t * data, uint8
|
|||||||
|
|
||||||
memcpy(goData, data, length);
|
memcpy(goData, data, length);
|
||||||
|
|
||||||
go.commFlag(Updated);
|
if (go.commFlag() != WriteRequest)
|
||||||
|
{
|
||||||
|
go.commFlag(Updated);
|
||||||
#ifdef SMALL_GROUPOBJECT
|
#ifdef SMALL_GROUPOBJECT
|
||||||
GroupObject::processClassCallback(go);
|
GroupObject::processClassCallback(go);
|
||||||
#else
|
#else
|
||||||
GroupObjectUpdatedHandler handler = go.callback();
|
GroupObjectUpdatedHandler handler = go.callback();
|
||||||
if (handler)
|
if (handler)
|
||||||
handler(go);
|
handler(go);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
go.commFlag(Updated);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BauSystemBDevice::configured()
|
bool BauSystemBDevice::configured()
|
||||||
|
@ -20,12 +20,12 @@ class BauSystemBDevice : public BauSystemB
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BauSystemBDevice(Platform& platform);
|
BauSystemBDevice(Platform& platform);
|
||||||
virtual void loop() override;
|
void loop() override;
|
||||||
virtual bool configured() override;
|
bool configured() override;
|
||||||
GroupObjectTableObject& groupObjectTable();
|
GroupObjectTableObject& groupObjectTable();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ApplicationLayer& applicationLayer() override;
|
ApplicationLayer& applicationLayer() override;
|
||||||
|
|
||||||
void groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl &secCtrl,
|
void groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl &secCtrl,
|
||||||
uint8_t* data, uint8_t dataLength, bool status) override;
|
uint8_t* data, uint8_t dataLength, bool status) override;
|
||||||
@ -39,7 +39,7 @@ class BauSystemBDevice : public BauSystemB
|
|||||||
void sendNextGroupTelegram();
|
void sendNextGroupTelegram();
|
||||||
void updateGroupObject(GroupObject& go, uint8_t* data, uint8_t length);
|
void updateGroupObject(GroupObject& go, uint8_t* data, uint8_t length);
|
||||||
|
|
||||||
virtual void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
||||||
|
|
||||||
AddressTableObject _addrTable;
|
AddressTableObject _addrTable;
|
||||||
AssociationTableObject _assocTable;
|
AssociationTableObject _assocTable;
|
||||||
|
@ -124,21 +124,19 @@ uint64_t sixBytesToUInt64(uint8_t* data)
|
|||||||
|
|
||||||
uint16_t crc16Ccitt(uint8_t* input, uint16_t length)
|
uint16_t crc16Ccitt(uint8_t* input, uint16_t length)
|
||||||
{
|
{
|
||||||
uint32_t polynom = 0x1021;
|
uint32_t polynom = 0x1021;
|
||||||
uint8_t padded[length+2];
|
|
||||||
|
|
||||||
memcpy(padded, input, length);
|
uint32_t result = 0xffff;
|
||||||
memset(padded+length, 0x00, 2);
|
for (uint32_t i = 0; i < 8 * ((uint32_t)length + 2); i++)
|
||||||
|
{
|
||||||
uint32_t result = 0xffff;
|
result <<= 1;
|
||||||
for (uint32_t i = 0; i < 8 * (uint32_t)sizeof(padded); i++) {
|
uint32_t nextBit;
|
||||||
result <<= 1;
|
nextBit = ((i / 8) < length) ? ((input[i / 8] >> (7 - (i % 8))) & 0x1) : 0;
|
||||||
uint32_t nextBit = (padded[i / 8] >> (7 - (i % 8))) & 0x1;
|
result |= nextBit;
|
||||||
result |= nextBit;
|
if ((result & 0x10000) != 0)
|
||||||
if ((result & 0x10000) != 0)
|
result ^= polynom;
|
||||||
result ^= polynom;
|
}
|
||||||
}
|
return result & 0xffff;
|
||||||
return result & 0xffff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t crc16Dnp(uint8_t* input, uint16_t length)
|
uint16_t crc16Dnp(uint8_t* input, uint16_t length)
|
||||||
|
@ -18,14 +18,14 @@ template <class T> class CallbackProperty : public Property
|
|||||||
: Property(id, writeEnable, type, maxElements, access), _interfaceObject(io), _readCallback(readCallback)
|
: Property(id, writeEnable, type, maxElements, access), _interfaceObject(io), _readCallback(readCallback)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const override
|
uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const override
|
||||||
{
|
{
|
||||||
if (count == 0 || _readCallback == nullptr || start > _maxElements || start + count > _maxElements + 1)
|
if (count == 0 || _readCallback == nullptr || start > _maxElements || start + count > _maxElements + 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return _readCallback(_interfaceObject, start, count, data);
|
return _readCallback(_interfaceObject, start, count, data);
|
||||||
}
|
}
|
||||||
virtual uint8_t write(uint16_t start, uint8_t count, const uint8_t* data) override
|
uint8_t write(uint16_t start, uint8_t count, const uint8_t* data) override
|
||||||
{
|
{
|
||||||
if (count == 0 || start > _maxElements || start + count > _maxElements + 1 || _writeCallback == nullptr)
|
if (count == 0 || start > _maxElements || start + count > _maxElements + 1 || _writeCallback == nullptr)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -10,12 +10,12 @@ class DataProperty : public Property
|
|||||||
DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, uint16_t value);
|
DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, uint16_t value);
|
||||||
DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, uint32_t value);
|
DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, uint32_t value);
|
||||||
DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, const uint8_t* value);
|
DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, const uint8_t* value);
|
||||||
virtual ~DataProperty() override;
|
~DataProperty() override;
|
||||||
virtual uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const override;
|
uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const override;
|
||||||
virtual uint8_t write(uint16_t start, uint8_t count, const uint8_t* data) override;
|
uint8_t write(uint16_t start, uint8_t count, const uint8_t* data) override;
|
||||||
virtual uint8_t* save(uint8_t* buffer) override;
|
uint8_t* save(uint8_t* buffer) override;
|
||||||
virtual const uint8_t* restore(const uint8_t* buffer) override;
|
const uint8_t* restore(const uint8_t* buffer) override;
|
||||||
virtual uint16_t saveSize() override;
|
uint16_t saveSize() override;
|
||||||
const uint8_t* data();
|
const uint8_t* data();
|
||||||
const uint8_t* data(uint16_t elementIndex);
|
const uint8_t* data(uint16_t elementIndex);
|
||||||
|
|
||||||
|
@ -91,7 +91,6 @@ DeviceObject::DeviceObject()
|
|||||||
#ifdef USE_RF
|
#ifdef USE_RF
|
||||||
new DataProperty(PID_RF_DOMAIN_ADDRESS_CEMI_SERVER, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv3),
|
new DataProperty(PID_RF_DOMAIN_ADDRESS_CEMI_SERVER, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv3),
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
initializeProperties(sizeof(properties), properties);
|
initializeProperties(sizeof(properties), properties);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,10 @@
|
|||||||
class DeviceObject: public InterfaceObject
|
class DeviceObject: public InterfaceObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
// increase this version anytime DeviceObject-API changes
|
||||||
|
// the following value represents the serialized representation of DeviceObject.
|
||||||
|
const uint16_t apiVersion = 1;
|
||||||
|
|
||||||
DeviceObject();
|
DeviceObject();
|
||||||
uint8_t* save(uint8_t* buffer) override;
|
uint8_t* save(uint8_t* buffer) override;
|
||||||
const uint8_t* restore(const uint8_t* buffer) override;
|
const uint8_t* restore(const uint8_t* buffer) override;
|
||||||
|
@ -135,7 +135,6 @@ int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatyp
|
|||||||
|
|
||||||
int KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
|
int KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (datatype.mainGroup == 1 && datatype.subGroup >= 1 && datatype.subGroup <= 23 && datatype.subGroup != 20 && !datatype.index)
|
if (datatype.mainGroup == 1 && datatype.subGroup >= 1 && datatype.subGroup <= 23 && datatype.subGroup != 20 && !datatype.index)
|
||||||
return valueToBusValueBinary(value, payload, payload_length, datatype);
|
return valueToBusValueBinary(value, payload, payload_length, datatype);
|
||||||
// DPT 2.* - Binary Control
|
// DPT 2.* - Binary Control
|
||||||
@ -1553,7 +1552,6 @@ int valueToBusValueRGBW(const KNXValue& value, uint8_t* payload, size_t payload_
|
|||||||
case 1: // Mask bits
|
case 1: // Mask bits
|
||||||
unsigned8ToPayload(payload, payload_length, 5, (uint8_t)value, 0x0f);
|
unsigned8ToPayload(payload, payload_length, 5, (uint8_t)value, 0x0f);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1757,7 +1755,7 @@ void float16ToPayload(uint8_t* payload, size_t payload_length, int index, double
|
|||||||
if (wasNegative)
|
if (wasNegative)
|
||||||
mantissa *= -1;
|
mantissa *= -1;
|
||||||
|
|
||||||
println(mantissa);
|
// println(mantissa);
|
||||||
|
|
||||||
signed16ToPayload(payload, payload_length, index, mantissa, mask);
|
signed16ToPayload(payload, payload_length, index, mantissa, mask);
|
||||||
unsigned8ToPayload(payload, payload_length, index, exponent << 3, 0x78 & (mask >> 8));
|
unsigned8ToPayload(payload, payload_length, index, exponent << 3, 0x78 & (mask >> 8));
|
||||||
|
@ -14,17 +14,17 @@ template <class T> class FunctionProperty : public Property
|
|||||||
/* max_elements is set to 1, read and write level any value so we use Lv0, see 3.3.7 Application Layer p.68 */
|
/* max_elements is set to 1, read and write level any value so we use Lv0, see 3.3.7 Application Layer p.68 */
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const override
|
uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const override
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual uint8_t write(uint16_t start, uint8_t count, const uint8_t* data) override
|
uint8_t write(uint16_t start, uint8_t count, const uint8_t* data) override
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void command(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) override
|
void command(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) override
|
||||||
{
|
{
|
||||||
if (length == 0 || _commandCallback == nullptr )
|
if (length == 0 || _commandCallback == nullptr )
|
||||||
{
|
{
|
||||||
@ -34,7 +34,7 @@ template <class T> class FunctionProperty : public Property
|
|||||||
_commandCallback(_interfaceObject, data, length, resultData, resultLength);
|
_commandCallback(_interfaceObject, data, length, resultData, resultLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void state(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) override
|
void state(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) override
|
||||||
{
|
{
|
||||||
if (length == 0 || _stateCallback == nullptr )
|
if (length == 0 || _stateCallback == nullptr )
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,7 @@ GroupObjectTableObject* GroupObject::_table = 0;
|
|||||||
GroupObject::GroupObject()
|
GroupObject::GroupObject()
|
||||||
{
|
{
|
||||||
_data = 0;
|
_data = 0;
|
||||||
_commFlag = Ok;
|
_commFlag = Uninitialized;
|
||||||
_dataLength = 0;
|
_dataLength = 0;
|
||||||
#ifndef SMALL_GROUPOBJECT
|
#ifndef SMALL_GROUPOBJECT
|
||||||
_updateHandler = 0;
|
_updateHandler = 0;
|
||||||
@ -74,6 +74,10 @@ bool GroupObject::readEnable()
|
|||||||
if (!_table)
|
if (!_table)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// we forbid reading of new (uninitialized) go
|
||||||
|
if (_commFlag == Uninitialized)
|
||||||
|
return false;
|
||||||
|
|
||||||
return bitRead(ntohs(_table->_tableData[_asap]), 11) > 0;
|
return bitRead(ntohs(_table->_tableData[_asap]), 11) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,5 +274,8 @@ void GroupObject::valueNoSend(const KNXValue& value)
|
|||||||
|
|
||||||
void GroupObject::valueNoSend(const KNXValue& value, const Dpt& type)
|
void GroupObject::valueNoSend(const KNXValue& value, const Dpt& type)
|
||||||
{
|
{
|
||||||
|
if (_commFlag == Uninitialized)
|
||||||
|
_commFlag = Ok;
|
||||||
|
|
||||||
KNX_Encode_Value(value, _data, _dataLength, type);
|
KNX_Encode_Value(value, _data, _dataLength, type);
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ enum ComFlag
|
|||||||
WriteRequest = 2, //!< Write was requested but was not processed
|
WriteRequest = 2, //!< Write was requested but was not processed
|
||||||
Transmitting = 3, //!< Group Object is processed a the moment (read or write)
|
Transmitting = 3, //!< Group Object is processed a the moment (read or write)
|
||||||
Ok = 4, //!< read or write request were send successfully
|
Ok = 4, //!< read or write request were send successfully
|
||||||
Error = 5 //!< there was an error on processing a request
|
Error = 5, //!< there was an error on processing a request
|
||||||
|
Uninitialized = 6 //!< uninitialized Group Object, its value is not valid
|
||||||
};
|
};
|
||||||
|
|
||||||
class GroupObject;
|
class GroupObject;
|
||||||
@ -235,7 +236,7 @@ class GroupObject
|
|||||||
size_t asapValueSize(uint8_t code);
|
size_t asapValueSize(uint8_t code);
|
||||||
size_t goSize();
|
size_t goSize();
|
||||||
uint16_t _asap = 0;
|
uint16_t _asap = 0;
|
||||||
ComFlag _commFlag = Ok;
|
ComFlag _commFlag = Uninitialized;
|
||||||
uint8_t* _data = 0;
|
uint8_t* _data = 0;
|
||||||
uint8_t _dataLength = 0;
|
uint8_t _dataLength = 0;
|
||||||
#ifndef SMALL_GROUPOBJECT
|
#ifndef SMALL_GROUPOBJECT
|
||||||
|
@ -77,6 +77,7 @@ void GroupObjectTableObject::groupObjects(GroupObject * objs, uint16_t size)
|
|||||||
|
|
||||||
void GroupObjectTableObject::beforeStateChange(LoadState& newState)
|
void GroupObjectTableObject::beforeStateChange(LoadState& newState)
|
||||||
{
|
{
|
||||||
|
TableObject::beforeStateChange(newState);
|
||||||
if (newState != LS_LOADED)
|
if (newState != LS_LOADED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -183,12 +183,11 @@ class InterfaceObject : public SaveRestore
|
|||||||
*/
|
*/
|
||||||
const Property* property(PropertyID id) const;
|
const Property* property(PropertyID id) const;
|
||||||
|
|
||||||
virtual uint8_t* save(uint8_t* buffer) override;
|
uint8_t* save(uint8_t* buffer) override;
|
||||||
virtual const uint8_t* restore(const uint8_t* buffer) override;
|
const uint8_t* restore(const uint8_t* buffer) override;
|
||||||
virtual uint16_t saveSize() override;
|
uint16_t saveSize() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Intializes the Property-array the the supplied values.
|
* Intializes the Property-array the the supplied values.
|
||||||
*/
|
*/
|
||||||
|
@ -18,7 +18,7 @@ class IpDataLinkLayer : public DataLinkLayer
|
|||||||
void loop();
|
void loop();
|
||||||
void enabled(bool value);
|
void enabled(bool value);
|
||||||
bool enabled() const;
|
bool enabled() const;
|
||||||
virtual DptMedium mediumType() const override;
|
DptMedium mediumType() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _enabled = false;
|
bool _enabled = false;
|
||||||
|
@ -29,9 +29,6 @@ enum KnxIpServiceType
|
|||||||
TunnelingAck = 0x421,
|
TunnelingAck = 0x421,
|
||||||
RoutingIndication = 0x530,
|
RoutingIndication = 0x530,
|
||||||
RoutingLostMessage = 0x531,
|
RoutingLostMessage = 0x531,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class KnxIpFrame
|
class KnxIpFrame
|
||||||
|
@ -49,7 +49,6 @@ class KNXValue
|
|||||||
KNXValue& operator=(const float value);
|
KNXValue& operator=(const float value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool boolValue() const;
|
bool boolValue() const;
|
||||||
uint8_t ucharValue() const;
|
uint8_t ucharValue() const;
|
||||||
uint16_t ushortValue() const;
|
uint16_t ushortValue() const;
|
||||||
|
@ -1,73 +1,115 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "bits.h"
|
#include "bits.h"
|
||||||
|
|
||||||
Memory::Memory(Platform& platform, DeviceObject& deviceObject)
|
Memory::Memory(Platform& platform, DeviceObject& deviceObject)
|
||||||
: _platform(platform), _deviceObject(deviceObject)
|
: _platform(platform), _deviceObject(deviceObject)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
Memory::~Memory()
|
||||||
|
{}
|
||||||
|
|
||||||
void Memory::readMemory()
|
void Memory::readMemory()
|
||||||
{
|
{
|
||||||
println("readMemory");
|
println("readMemory");
|
||||||
if (_data != nullptr)
|
|
||||||
|
uint8_t* flashStart = _platform.getNonVolatileMemoryStart();
|
||||||
|
size_t flashSize = _platform.getNonVolatileMemorySize();
|
||||||
|
if (flashStart == nullptr)
|
||||||
|
{
|
||||||
|
println("no user flash available;");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t flashSize = KNX_FLASH_SIZE;
|
printHex("RESTORED ", flashStart, _metadataSize);
|
||||||
_data = _platform.getEepromBuffer(flashSize);
|
|
||||||
|
|
||||||
printHex("RESTORED ", _data, _metadataSize);
|
|
||||||
|
|
||||||
uint16_t metadataBlockSize = alignToPageSize(_metadataSize);
|
uint16_t metadataBlockSize = alignToPageSize(_metadataSize);
|
||||||
|
|
||||||
_freeList = new MemoryBlock(_data + metadataBlockSize, flashSize - metadataBlockSize);
|
_freeList = new MemoryBlock(flashStart + metadataBlockSize, flashSize - metadataBlockSize);
|
||||||
|
|
||||||
|
uint16_t apiVersion = 0;
|
||||||
|
const uint8_t* buffer = popWord(apiVersion, flashStart);
|
||||||
|
|
||||||
uint16_t manufacturerId = 0;
|
uint16_t manufacturerId = 0;
|
||||||
const uint8_t* buffer = popWord(manufacturerId, _data);
|
buffer = popWord(manufacturerId, buffer);
|
||||||
|
|
||||||
uint8_t hardwareType[LEN_HARDWARE_TYPE] = {0};
|
uint8_t hardwareType[LEN_HARDWARE_TYPE] = {0};
|
||||||
buffer = popByteArray(hardwareType, LEN_HARDWARE_TYPE, buffer);
|
buffer = popByteArray(hardwareType, LEN_HARDWARE_TYPE, buffer);
|
||||||
|
|
||||||
uint16_t version = 0;
|
uint16_t version = 0;
|
||||||
buffer = popWord(version, buffer);
|
buffer = popWord(version, buffer);
|
||||||
|
|
||||||
|
VersionCheckResult versionCheck = FlashAllInvalid;
|
||||||
|
|
||||||
if (_deviceObject.manufacturerId() != manufacturerId
|
// first check correct format of deviceObject-API
|
||||||
|| _deviceObject.version() != version
|
if (_deviceObject.apiVersion == apiVersion)
|
||||||
|| memcmp(_deviceObject.hardwareType(), hardwareType, LEN_HARDWARE_TYPE) != 0)
|
|
||||||
{
|
{
|
||||||
println("saved memory doesn't match manufacturerId, version or hardwaretype");
|
if (_versionCheckCallback != 0) {
|
||||||
print("manufacturerId: ");
|
versionCheck = _versionCheckCallback(manufacturerId, hardwareType, version);
|
||||||
print(manufacturerId, HEX);
|
// callback should provide infomation about version check failure reasons
|
||||||
print(" ");
|
}
|
||||||
println(_deviceObject.manufacturerId(), HEX);
|
else if (_deviceObject.manufacturerId() == manufacturerId &&
|
||||||
print("version: ");
|
memcmp(_deviceObject.hardwareType(), hardwareType, LEN_HARDWARE_TYPE) == 0)
|
||||||
print(version, HEX);
|
{
|
||||||
print(" ");
|
if (_deviceObject.version() == version) {
|
||||||
println(_deviceObject.version(), HEX);
|
versionCheck = FlashValid;
|
||||||
print("hardwareType: ");
|
}
|
||||||
printHex("", hardwareType, LEN_HARDWARE_TYPE);
|
else
|
||||||
print(" ");
|
{
|
||||||
printHex("", _deviceObject.hardwareType(), LEN_HARDWARE_TYPE);
|
versionCheck = FlashTablesInvalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
println("manufacturerId or hardwareType are different");
|
||||||
|
print("expexted manufacturerId: ");
|
||||||
|
print(_deviceObject.manufacturerId(), HEX);
|
||||||
|
print(", stored manufacturerId: ");
|
||||||
|
println(manufacturerId, HEX);
|
||||||
|
print("expexted hardwareType: ");
|
||||||
|
printHex("", _deviceObject.hardwareType(), LEN_HARDWARE_TYPE);
|
||||||
|
print(", stored hardwareType: ");
|
||||||
|
printHex("", hardwareType, LEN_HARDWARE_TYPE);
|
||||||
|
println("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
println("DataObject api changed, any data stored in flash is invalid.");
|
||||||
|
print("expexted DataObject api version: ");
|
||||||
|
print(_deviceObject.apiVersion, HEX);
|
||||||
|
print(", stored api version: ");
|
||||||
|
println(apiVersion, HEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (versionCheck == FlashAllInvalid)
|
||||||
|
{
|
||||||
|
println("ETS has to reprogram PA and application!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
println("manufacturerId, version and hardwareType matches");
|
println("restoring data from flash...");
|
||||||
print("saverestores ");
|
print("saverestores ");
|
||||||
println(_saveCount);
|
println(_saveCount);
|
||||||
for (int i = 0; i < _saveCount; i++)
|
for (int i = 0; i < _saveCount; i++)
|
||||||
{
|
{
|
||||||
println(_data - buffer);
|
println(flashStart - buffer);
|
||||||
println(".");
|
println(".");
|
||||||
buffer = _saveRestores[i]->restore(buffer);
|
buffer = _saveRestores[i]->restore(buffer);
|
||||||
}
|
}
|
||||||
println("restored saveRestores");
|
println("restored saveRestores");
|
||||||
|
if (versionCheck == FlashTablesInvalid)
|
||||||
|
{
|
||||||
|
println("TableObjects are referring to an older firmware version and are not loaded");
|
||||||
|
return;
|
||||||
|
}
|
||||||
print("tableObjs ");
|
print("tableObjs ");
|
||||||
println(_tableObjCount);
|
println(_tableObjCount);
|
||||||
for (int i = 0; i < _tableObjCount; i++)
|
for (int i = 0; i < _tableObjCount; i++)
|
||||||
{
|
{
|
||||||
println(_data - buffer);
|
println(flashStart - buffer);
|
||||||
println(".");
|
println(".");
|
||||||
buffer = _tableObjects[i]->restore(buffer);
|
buffer = _tableObjects[i]->restore(buffer);
|
||||||
uint16_t memorySize = 0;
|
uint16_t memorySize = 0;
|
||||||
@ -84,48 +126,62 @@ void Memory::readMemory()
|
|||||||
|
|
||||||
void Memory::writeMemory()
|
void Memory::writeMemory()
|
||||||
{
|
{
|
||||||
uint8_t* buffer = _data;
|
// first get the necessary size of the writeBuffer
|
||||||
buffer = pushWord(_deviceObject.manufacturerId(), buffer);
|
size_t writeBufferSize = _metadataSize;
|
||||||
buffer = pushByteArray(_deviceObject.hardwareType(), LEN_HARDWARE_TYPE, buffer);
|
for (int i = 0; i < _saveCount; i++)
|
||||||
buffer = pushWord(_deviceObject.version(), buffer);
|
writeBufferSize = MAX(writeBufferSize, _saveRestores[i]->saveSize());
|
||||||
|
|
||||||
|
for (int i = 0; i < _tableObjCount; i++)
|
||||||
|
writeBufferSize = MAX(writeBufferSize, _tableObjects[i]->saveSize() + 2 /*for memory pos*/);
|
||||||
|
|
||||||
|
uint8_t buffer[writeBufferSize];
|
||||||
|
uint32_t flashPos = 0;
|
||||||
|
uint8_t* bufferPos = buffer;
|
||||||
|
|
||||||
|
bufferPos = pushWord(_deviceObject.apiVersion, bufferPos);
|
||||||
|
bufferPos = pushWord(_deviceObject.manufacturerId(), bufferPos);
|
||||||
|
bufferPos = pushByteArray(_deviceObject.hardwareType(), LEN_HARDWARE_TYPE, bufferPos);
|
||||||
|
bufferPos = pushWord(_deviceObject.version(), bufferPos);
|
||||||
|
|
||||||
|
flashPos = _platform.writeNonVolatileMemory(flashPos, buffer, bufferPos - buffer);
|
||||||
|
|
||||||
print("save saveRestores ");
|
print("save saveRestores ");
|
||||||
println(_saveCount);
|
println(_saveCount);
|
||||||
for (int i = 0; i < _saveCount; i++)
|
for (int i = 0; i < _saveCount; i++)
|
||||||
{
|
{
|
||||||
println(_data - buffer);
|
bufferPos = _saveRestores[i]->save(buffer);
|
||||||
println(".");
|
flashPos = _platform.writeNonVolatileMemory(flashPos, buffer, bufferPos - buffer);
|
||||||
//println((long)_saveRestores[i], HEX);
|
|
||||||
buffer = _saveRestores[i]->save(buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
print("save tableobjs ");
|
print("save tableobjs ");
|
||||||
println(_tableObjCount);
|
println(_tableObjCount);
|
||||||
for (int i = 0; i < _tableObjCount; i++)
|
for (int i = 0; i < _tableObjCount; i++)
|
||||||
{
|
{
|
||||||
println(_data - buffer);
|
bufferPos = _tableObjects[i]->save(buffer);
|
||||||
println(".");
|
|
||||||
//println((long)_tableObjects[i], HEX);
|
|
||||||
buffer = _tableObjects[i]->save(buffer);
|
|
||||||
|
|
||||||
//save to size of the memoryblock for tableobject too, so that we can rebuild the usedList and freeList
|
//save to size of the memoryblock for tableobject too, so that we can rebuild the usedList and freeList
|
||||||
if (_tableObjects[i]->_data != nullptr)
|
if (_tableObjects[i]->_data != nullptr)
|
||||||
{
|
{
|
||||||
|
|
||||||
MemoryBlock* block = findBlockInList(_usedList, _tableObjects[i]->_data);
|
MemoryBlock* block = findBlockInList(_usedList, _tableObjects[i]->_data);
|
||||||
if (block == nullptr)
|
if (block == nullptr)
|
||||||
{
|
{
|
||||||
println("_data of TableObject not in errorlist");
|
println("_data of TableObject not in _usedList");
|
||||||
_platform.fatalError();
|
_platform.fatalError();
|
||||||
}
|
}
|
||||||
buffer = pushWord(block->size, buffer);
|
bufferPos = pushWord(block->size, bufferPos);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
buffer = pushWord(0, buffer);
|
bufferPos = pushWord(0, bufferPos);
|
||||||
|
|
||||||
|
flashPos = _platform.writeNonVolatileMemory(flashPos, buffer, bufferPos - buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
_platform.commitToEeprom();
|
_platform.commitNonVolatileMemory();
|
||||||
printHex("SAVED ", _data, _metadataSize);
|
}
|
||||||
|
|
||||||
|
void Memory::saveMemory()
|
||||||
|
{
|
||||||
|
_platform.commitNonVolatileMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Memory::addSaveRestore(SaveRestore* obj)
|
void Memory::addSaveRestore(SaveRestore* obj)
|
||||||
@ -151,7 +207,7 @@ void Memory::addSaveRestore(TableObject* obj)
|
|||||||
|
|
||||||
uint8_t* Memory::allocMemory(size_t size)
|
uint8_t* Memory::allocMemory(size_t size)
|
||||||
{
|
{
|
||||||
// always allocate aligned to 32 bit
|
// always allocate aligned to pagesize
|
||||||
size = alignToPageSize(size);
|
size = alignToPageSize(size);
|
||||||
|
|
||||||
MemoryBlock* freeBlock = _freeList;
|
MemoryBlock* freeBlock = _freeList;
|
||||||
@ -220,19 +276,19 @@ void Memory::freeMemory(uint8_t* ptr)
|
|||||||
|
|
||||||
void Memory::writeMemory(uint32_t relativeAddress, size_t size, uint8_t* data)
|
void Memory::writeMemory(uint32_t relativeAddress, size_t size, uint8_t* data)
|
||||||
{
|
{
|
||||||
memcpy(toAbsolute(relativeAddress), data, size);
|
_platform.writeNonVolatileMemory(relativeAddress, data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8_t* Memory::toAbsolute(uint32_t relativeAddress)
|
uint8_t* Memory::toAbsolute(uint32_t relativeAddress)
|
||||||
{
|
{
|
||||||
return _data + (ptrdiff_t)relativeAddress;
|
return _platform.getNonVolatileMemoryStart() + (ptrdiff_t)relativeAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t Memory::toRelative(uint8_t* absoluteAddress)
|
uint32_t Memory::toRelative(uint8_t* absoluteAddress)
|
||||||
{
|
{
|
||||||
return absoluteAddress - _data;
|
return absoluteAddress - _platform.getNonVolatileMemoryStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryBlock* Memory::removeFromList(MemoryBlock* head, MemoryBlock* item)
|
MemoryBlock* Memory::removeFromList(MemoryBlock* head, MemoryBlock* item)
|
||||||
@ -354,8 +410,9 @@ void Memory::addToFreeList(MemoryBlock* block)
|
|||||||
|
|
||||||
uint16_t Memory::alignToPageSize(size_t size)
|
uint16_t Memory::alignToPageSize(size_t size)
|
||||||
{
|
{
|
||||||
// to 32 bit for now
|
size_t pageSize = 4; //_platform.flashPageSize(); // align to 32bit for now, as aligning to flash-page-size causes side effects in programming
|
||||||
return (size + 3) & ~0x3;
|
// pagesize should be a multiply of two
|
||||||
|
return (size + pageSize - 1) & (-1*pageSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryBlock* Memory::findBlockInList(MemoryBlock* head, uint8_t* address)
|
MemoryBlock* Memory::findBlockInList(MemoryBlock* head, uint8_t* address)
|
||||||
@ -429,3 +486,13 @@ void Memory::addNewUsedBlock(uint8_t* address, size_t size)
|
|||||||
MemoryBlock* newUsedBlock = new MemoryBlock(address, size);
|
MemoryBlock* newUsedBlock = new MemoryBlock(address, size);
|
||||||
addToUsedList(newUsedBlock);
|
addToUsedList(newUsedBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Memory::versionCheckCallback(VersionCheckCallback func)
|
||||||
|
{
|
||||||
|
_versionCheckCallback = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionCheckCallback Memory::versionCheckCallback()
|
||||||
|
{
|
||||||
|
return _versionCheckCallback;
|
||||||
|
}
|
||||||
|
@ -24,12 +24,23 @@ class MemoryBlock
|
|||||||
MemoryBlock* next = nullptr;
|
MemoryBlock* next = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum VersionCheckResult
|
||||||
|
{
|
||||||
|
FlashAllInvalid = 0, //!< All flash content is not valid for this firmware, we delete it
|
||||||
|
FlashTablesInvalid = 1,//!< All table objects are invalid for this firmware, device object and saveRestores are OK
|
||||||
|
FlashValid = 2 //!< Flash content is valid and will be used
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef VersionCheckResult (*VersionCheckCallback)(uint16_t manufacturerId, uint8_t* hardwareType, uint16_t version);
|
||||||
|
|
||||||
class Memory
|
class Memory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Memory(Platform& platform, DeviceObject& deviceObject);
|
Memory(Platform& platform, DeviceObject& deviceObject);
|
||||||
|
virtual ~Memory();
|
||||||
void readMemory();
|
void readMemory();
|
||||||
void writeMemory();
|
void writeMemory();
|
||||||
|
void saveMemory();
|
||||||
void addSaveRestore(SaveRestore* obj);
|
void addSaveRestore(SaveRestore* obj);
|
||||||
void addSaveRestore(TableObject* obj);
|
void addSaveRestore(TableObject* obj);
|
||||||
|
|
||||||
@ -39,6 +50,9 @@ public:
|
|||||||
uint8_t* toAbsolute(uint32_t relativeAddress);
|
uint8_t* toAbsolute(uint32_t relativeAddress);
|
||||||
uint32_t toRelative(uint8_t* absoluteAddress);
|
uint32_t toRelative(uint8_t* absoluteAddress);
|
||||||
|
|
||||||
|
void versionCheckCallback(VersionCheckCallback func);
|
||||||
|
VersionCheckCallback versionCheckCallback();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void removeFromFreeList(MemoryBlock* block);
|
void removeFromFreeList(MemoryBlock* block);
|
||||||
void addToUsedList(MemoryBlock* block);
|
void addToUsedList(MemoryBlock* block);
|
||||||
@ -49,14 +63,19 @@ public:
|
|||||||
MemoryBlock* findBlockInList(MemoryBlock* head, uint8_t* address);
|
MemoryBlock* findBlockInList(MemoryBlock* head, uint8_t* address);
|
||||||
void addNewUsedBlock(uint8_t* address, size_t size);
|
void addNewUsedBlock(uint8_t* address, size_t size);
|
||||||
|
|
||||||
|
void readEraseBlockToBuffer(uint32_t blockNum);
|
||||||
|
uint8_t* eraseBlockStart(uint32_t blockNum);
|
||||||
|
uint8_t* eraseBlockEnd(uint32_t blockNum);
|
||||||
|
void saveBufferdEraseBlock();
|
||||||
|
|
||||||
|
VersionCheckCallback _versionCheckCallback = 0;
|
||||||
Platform& _platform;
|
Platform& _platform;
|
||||||
DeviceObject& _deviceObject;
|
DeviceObject& _deviceObject;
|
||||||
SaveRestore* _saveRestores[MAXSAVE] = {0};
|
SaveRestore* _saveRestores[MAXSAVE] = {0};
|
||||||
TableObject* _tableObjects[MAXTABLEOBJ] = {0};
|
TableObject* _tableObjects[MAXTABLEOBJ] = {0};
|
||||||
uint8_t _saveCount = 0;
|
uint8_t _saveCount = 0;
|
||||||
uint8_t _tableObjCount = 0;
|
uint8_t _tableObjCount = 0;
|
||||||
uint8_t* _data = nullptr;
|
|
||||||
MemoryBlock* _freeList = nullptr;
|
MemoryBlock* _freeList = nullptr;
|
||||||
MemoryBlock* _usedList = nullptr;
|
MemoryBlock* _usedList = nullptr;
|
||||||
uint16_t _metadataSize = 4 + LEN_HARDWARE_TYPE; // accounting for 2x pushWord and pushByteArray of length LEN_HARDWARE_TYPE
|
uint16_t _metadataSize = 6 + LEN_HARDWARE_TYPE; // accounting for 3x pushWord and pushByteArray of length LEN_HARDWARE_TYPE
|
||||||
};
|
};
|
||||||
|
@ -27,10 +27,10 @@ class NetworkLayerCoupler : public NetworkLayer
|
|||||||
void rtObj(RouterObject& rtObj); // Coupler model 1.x
|
void rtObj(RouterObject& rtObj); // Coupler model 1.x
|
||||||
|
|
||||||
// from transport layer
|
// from transport layer
|
||||||
virtual void dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override;
|
void dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override;
|
||||||
virtual void dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override;
|
void dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override;
|
||||||
virtual void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override;
|
void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override;
|
||||||
virtual void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override;
|
void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum CouplerType
|
enum CouplerType
|
||||||
@ -46,16 +46,16 @@ class NetworkLayerCoupler : public NetworkLayer
|
|||||||
static constexpr uint8_t kLocalIfIndex = 99;
|
static constexpr uint8_t kLocalIfIndex = 99;
|
||||||
|
|
||||||
// from entities
|
// from entities
|
||||||
virtual void dataIndication(AckType ack, AddressType addType, uint16_t destination, FrameFormat format, NPDU& npdu,
|
void dataIndication(AckType ack, AddressType addType, uint16_t destination, FrameFormat format, NPDU& npdu,
|
||||||
Priority priority, uint16_t source, uint8_t srcIfIdx) override;
|
Priority priority, uint16_t source, uint8_t srcIfIdx) override;
|
||||||
virtual void dataConfirm(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, Priority priority,
|
void dataConfirm(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, Priority priority,
|
||||||
uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override;
|
uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override;
|
||||||
virtual void broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu,
|
void broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu,
|
||||||
Priority priority, uint16_t source, uint8_t srcIfIdx) override;
|
Priority priority, uint16_t source, uint8_t srcIfIdx) override;
|
||||||
virtual void broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override;
|
void broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override;
|
||||||
virtual void systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu,
|
void systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu,
|
||||||
Priority priority, uint16_t source, uint8_t srcIfIdx) override;
|
Priority priority, uint16_t source, uint8_t srcIfIdx) override;
|
||||||
virtual void systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override;
|
void systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override;
|
||||||
|
|
||||||
void routeDataIndividual(AckType ack, uint16_t destination, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIndex);
|
void routeDataIndividual(AckType ack, uint16_t destination, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIndex);
|
||||||
void sendMsgHopCount(AckType ack, AddressType addrType, uint16_t destination, NPDU& npdu, Priority priority,
|
void sendMsgHopCount(AckType ack, AddressType addrType, uint16_t destination, NPDU& npdu, Priority priority,
|
||||||
|
@ -19,23 +19,23 @@ class NetworkLayerDevice : public NetworkLayer
|
|||||||
NetworkLayerEntity& getInterface();
|
NetworkLayerEntity& getInterface();
|
||||||
|
|
||||||
// from transport layer
|
// from transport layer
|
||||||
virtual void dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override;
|
void dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override;
|
||||||
virtual void dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override;
|
void dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu) override;
|
||||||
virtual void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override;
|
void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override;
|
||||||
virtual void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override;
|
void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// from entities
|
// from entities
|
||||||
virtual void dataIndication(AckType ack, AddressType addType, uint16_t destination, FrameFormat format, NPDU& npdu,
|
void dataIndication(AckType ack, AddressType addType, uint16_t destination, FrameFormat format, NPDU& npdu,
|
||||||
Priority priority, uint16_t source, uint8_t srcIfIdx) override;
|
Priority priority, uint16_t source, uint8_t srcIfIdx) override;
|
||||||
virtual void dataConfirm(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, Priority priority,
|
void dataConfirm(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, Priority priority,
|
||||||
uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override;
|
uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override;
|
||||||
virtual void broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu,
|
void broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu,
|
||||||
Priority priority, uint16_t source, uint8_t srcIfIdx) override;
|
Priority priority, uint16_t source, uint8_t srcIfIdx) override;
|
||||||
virtual void broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override;
|
void broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override;
|
||||||
virtual void systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu,
|
void systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu,
|
||||||
Priority priority, uint16_t source, uint8_t srcIfIdx) override;
|
Priority priority, uint16_t source, uint8_t srcIfIdx) override;
|
||||||
virtual void systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override;
|
void systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx) override;
|
||||||
|
|
||||||
// Support only a single physical interface for normal devices
|
// Support only a single physical interface for normal devices
|
||||||
NetworkLayerEntity _netLayerEntities[1];
|
NetworkLayerEntity _netLayerEntities[1];
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
|
#include "bits.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
NvMemoryType Platform::NonVolatileMemoryType()
|
NvMemoryType Platform::NonVolatileMemoryType()
|
||||||
{
|
{
|
||||||
return _memoryType;
|
return _memoryType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Platform::NonVolatileMemoryType(NvMemoryType type)
|
void Platform::NonVolatileMemoryType(NvMemoryType type)
|
||||||
{
|
{
|
||||||
_memoryType = type;
|
_memoryType = type;
|
||||||
@ -97,3 +100,155 @@ int Platform::readBytesMultiCast(uint8_t *buffer, uint16_t maxLen)
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t Platform::flashEraseBlockSize()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Platform::flashPageSize()
|
||||||
|
{
|
||||||
|
// align to 32bit as default for Eeprom Emulation plattforms
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *Platform::userFlashStart()
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Platform::userFlashSizeEraseBlocks()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Platform::flashErase(uint16_t eraseBlockNum)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void Platform::flashWritePage(uint16_t pageNumber, uint8_t* data)
|
||||||
|
{}
|
||||||
|
|
||||||
|
uint8_t * Platform::getEepromBuffer(uint16_t size)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Platform::commitToEeprom()
|
||||||
|
{}
|
||||||
|
|
||||||
|
uint8_t* Platform::getNonVolatileMemoryStart()
|
||||||
|
{
|
||||||
|
if(_memoryType == Flash)
|
||||||
|
return userFlashStart();
|
||||||
|
else
|
||||||
|
return getEepromBuffer(KNX_FLASH_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Platform::getNonVolatileMemorySize()
|
||||||
|
{
|
||||||
|
if(_memoryType == Flash)
|
||||||
|
return userFlashSizeEraseBlocks() * flashEraseBlockSize() * flashPageSize();
|
||||||
|
else
|
||||||
|
return KNX_FLASH_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Platform::commitNonVolatileMemory()
|
||||||
|
{
|
||||||
|
if(_memoryType == Flash)
|
||||||
|
{
|
||||||
|
if(_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty)
|
||||||
|
{
|
||||||
|
writeBufferedEraseBlock();
|
||||||
|
|
||||||
|
free(_eraseblockBuffer);
|
||||||
|
_eraseblockBuffer = nullptr;
|
||||||
|
_bufferedEraseblockNumber = -1; // does that make sense?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
commitToEeprom();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Platform::writeNonVolatileMemory(uint32_t relativeAddress, uint8_t* buffer, size_t size)
|
||||||
|
{
|
||||||
|
if(_memoryType == Flash)
|
||||||
|
{
|
||||||
|
while (size > 0)
|
||||||
|
{
|
||||||
|
loadEraseblockContaining(relativeAddress);
|
||||||
|
uint32_t start = _bufferedEraseblockNumber * (flashEraseBlockSize() * flashPageSize());
|
||||||
|
uint32_t end = start + (flashEraseBlockSize() * flashPageSize());
|
||||||
|
|
||||||
|
ptrdiff_t offset = relativeAddress - start;
|
||||||
|
ptrdiff_t length = end - relativeAddress;
|
||||||
|
if(length > size)
|
||||||
|
length = size;
|
||||||
|
memcpy(_eraseblockBuffer + offset, buffer, length);
|
||||||
|
_bufferedEraseblockDirty = true;
|
||||||
|
|
||||||
|
relativeAddress += length;
|
||||||
|
buffer += length;
|
||||||
|
size -= length;
|
||||||
|
}
|
||||||
|
return relativeAddress;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(getEepromBuffer(KNX_FLASH_SIZE)+relativeAddress, buffer, size);
|
||||||
|
return relativeAddress+size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Platform::loadEraseblockContaining(uint32_t relativeAddress)
|
||||||
|
{
|
||||||
|
int32_t blockNum = getEraseBlockNumberOf(relativeAddress);
|
||||||
|
if (blockNum < 0)
|
||||||
|
{
|
||||||
|
println("loadEraseblockContaining could not get valid eraseblock number");
|
||||||
|
fatalError();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blockNum != _bufferedEraseblockNumber && _bufferedEraseblockNumber >= 0)
|
||||||
|
writeBufferedEraseBlock();
|
||||||
|
|
||||||
|
bufferEraseBlock(blockNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t Platform::getEraseBlockNumberOf(uint32_t relativeAddress)
|
||||||
|
{
|
||||||
|
return relativeAddress / (flashEraseBlockSize() * flashPageSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Platform::writeBufferedEraseBlock()
|
||||||
|
{
|
||||||
|
if(_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty)
|
||||||
|
{
|
||||||
|
flashErase(_bufferedEraseblockNumber);
|
||||||
|
for(int i = 0; i < flashEraseBlockSize(); i++)
|
||||||
|
{
|
||||||
|
int32_t pageNumber = _bufferedEraseblockNumber * flashEraseBlockSize() + i;
|
||||||
|
uint8_t *data = _eraseblockBuffer + flashPageSize() * i;
|
||||||
|
flashWritePage(pageNumber, data);
|
||||||
|
}
|
||||||
|
_bufferedEraseblockDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Platform::bufferEraseBlock(uint32_t eraseBlockNumber)
|
||||||
|
{
|
||||||
|
if(_bufferedEraseblockNumber == eraseBlockNumber)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(_eraseblockBuffer == nullptr)
|
||||||
|
{
|
||||||
|
_eraseblockBuffer = (uint8_t*)malloc(flashEraseBlockSize() * flashPageSize());
|
||||||
|
}
|
||||||
|
memcpy(_eraseblockBuffer, userFlashStart() + eraseBlockNumber * flashEraseBlockSize() * flashPageSize(), flashEraseBlockSize() * flashPageSize());
|
||||||
|
|
||||||
|
_bufferedEraseblockNumber = eraseBlockNumber;
|
||||||
|
_bufferedEraseblockDirty = false;
|
||||||
|
}
|
||||||
|
@ -4,6 +4,11 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "save_restore.h"
|
#include "save_restore.h"
|
||||||
|
|
||||||
|
#ifndef KNX_FLASH_SIZE
|
||||||
|
#define KNX_FLASH_SIZE 1024
|
||||||
|
#pragma warning "KNX_FLASH_SIZE not defined, using 1024"
|
||||||
|
#endif
|
||||||
|
|
||||||
enum NvMemoryType
|
enum NvMemoryType
|
||||||
{
|
{
|
||||||
Eeprom,
|
Eeprom,
|
||||||
@ -49,21 +54,62 @@ class Platform
|
|||||||
virtual void setupSpi();
|
virtual void setupSpi();
|
||||||
virtual void closeSpi();
|
virtual void closeSpi();
|
||||||
virtual int readWriteSpi(uint8_t *data, size_t len);
|
virtual int readWriteSpi(uint8_t *data, size_t len);
|
||||||
#if 0
|
|
||||||
// Flash memory
|
//Memory
|
||||||
virtual size_t flashEraseBlockSize(); // in pages
|
|
||||||
virtual size_t flashPageSize(); // in bytes
|
// --- Overwrite these methods in the device-plattform to use the EEPROM Emulation API for UserMemory ----
|
||||||
virtual uint8_t* userFlashStart(); // start of user flash aligned to start of an erase block
|
//
|
||||||
virtual size_t userFlashSizeEraseBlocks(); // in eraseBlocks
|
// --- changes to the UserMemory are written directly into the address space starting at getEepromBuffer
|
||||||
virtual void flashErase(uint16_t eraseBlockNum); //relativ to userFlashStart
|
// --- commitToEeprom must save this to a non-volatile area if neccessary
|
||||||
virtual void flashWritePage(uint16_t pageNumber, uint8_t* data); //write a single page to flash (pageNumber relative to userFashStart
|
virtual uint8_t* getEepromBuffer(uint16_t size);
|
||||||
#endif
|
virtual void commitToEeprom();
|
||||||
virtual uint8_t* getEepromBuffer(uint16_t size) = 0;
|
// -------------------------------------------------------------------------------------------------------
|
||||||
virtual void commitToEeprom() = 0;
|
|
||||||
|
virtual uint8_t* getNonVolatileMemoryStart();
|
||||||
|
virtual size_t getNonVolatileMemorySize();
|
||||||
|
virtual void commitNonVolatileMemory();
|
||||||
|
// address is relative to start of nonvolatile memory
|
||||||
|
virtual uint32_t writeNonVolatileMemory(uint32_t relativeAddress, uint8_t* buffer, size_t size);
|
||||||
|
|
||||||
NvMemoryType NonVolatileMemoryType();
|
NvMemoryType NonVolatileMemoryType();
|
||||||
void NonVolatileMemoryType(NvMemoryType type);
|
void NonVolatileMemoryType(NvMemoryType type);
|
||||||
|
|
||||||
|
// --- Overwrite these methods in the device-plattform to use flash memory handling by the knx stack ---
|
||||||
|
// --- also set _memoryType = Flash in the device-plattform's contructor
|
||||||
|
// --- optional: overwrite writeBufferedEraseBlock() in the device-plattform to reduce overhead when flashing multiple pages
|
||||||
|
|
||||||
|
// size of one flash page in bytes
|
||||||
|
virtual size_t flashPageSize();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// size of one EraseBlock in pages
|
||||||
|
virtual size_t flashEraseBlockSize();
|
||||||
|
// start of user flash aligned to start of an erase block
|
||||||
|
virtual uint8_t* userFlashStart();
|
||||||
|
// size of the user flash in EraseBlocks
|
||||||
|
virtual size_t userFlashSizeEraseBlocks();
|
||||||
|
//relativ to userFlashStart
|
||||||
|
virtual void flashErase(uint16_t eraseBlockNum);
|
||||||
|
//write a single page to flash (pageNumber relative to userFashStart
|
||||||
|
virtual void flashWritePage(uint16_t pageNumber, uint8_t* data);
|
||||||
|
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
NvMemoryType _memoryType = Eeprom;
|
NvMemoryType _memoryType = Eeprom;
|
||||||
|
|
||||||
|
void loadEraseblockContaining(uint32_t relativeAddress);
|
||||||
|
int32_t getEraseBlockNumberOf(uint32_t relativeAddress);
|
||||||
|
// writes _eraseblockBuffer to flash
|
||||||
|
virtual void writeBufferedEraseBlock();
|
||||||
|
// copies a EraseBlock into the _eraseblockBuffer
|
||||||
|
void bufferEraseBlock(uint32_t eraseBlockNumber);
|
||||||
|
|
||||||
|
// in theory we would have to use this buffer for memory reads too,
|
||||||
|
// but because ets always restarts the device after programming it
|
||||||
|
// we can ignore this issue
|
||||||
|
uint8_t* _eraseblockBuffer = nullptr;
|
||||||
|
int32_t _bufferedEraseblockNumber = -1;
|
||||||
|
bool _bufferedEraseblockDirty = false;
|
||||||
};
|
};
|
@ -27,7 +27,7 @@ class RfDataLinkLayer : public DataLinkLayer
|
|||||||
void loop();
|
void loop();
|
||||||
void enabled(bool value);
|
void enabled(bool value);
|
||||||
bool enabled() const;
|
bool enabled() const;
|
||||||
virtual DptMedium mediumType() const override;
|
DptMedium mediumType() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _enabled = false;
|
bool _enabled = false;
|
||||||
|
@ -679,7 +679,6 @@ void RfPhysicalLayerCC1101::loop()
|
|||||||
bytesLeft -= (32 - 1);
|
bytesLeft -= (32 - 1);
|
||||||
pByteIndex += (32 - 1);
|
pByteIndex += (32 - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -719,7 +718,6 @@ void RfPhysicalLayerCC1101::loop()
|
|||||||
packetStartTime = millis();
|
packetStartTime = millis();
|
||||||
syncStart = true;
|
syncStart = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -26,9 +26,9 @@ class RfPhysicalLayerCC1310 : public RfPhysicalLayer
|
|||||||
public:
|
public:
|
||||||
RfPhysicalLayerCC1310(RfDataLinkLayer& rfDataLinkLayer, Platform& platform);
|
RfPhysicalLayerCC1310(RfDataLinkLayer& rfDataLinkLayer, Platform& platform);
|
||||||
|
|
||||||
virtual bool InitChip() override;
|
bool InitChip() override;
|
||||||
virtual void stopChip() override;
|
void stopChip() override;
|
||||||
virtual void loop() override;
|
void loop() override;
|
||||||
|
|
||||||
void setOutputPowerLevel(int8_t dBm);
|
void setOutputPowerLevel(int8_t dBm);
|
||||||
|
|
||||||
|
@ -34,12 +34,12 @@ public:
|
|||||||
bool isRfSbcRoutingEnabled();
|
bool isRfSbcRoutingEnabled();
|
||||||
bool isIpSbcRoutingEnabled();
|
bool isIpSbcRoutingEnabled();
|
||||||
|
|
||||||
virtual void masterReset(EraseCode eraseCode, uint8_t channel) override;
|
void masterReset(EraseCode eraseCode, uint8_t channel) override;
|
||||||
|
|
||||||
const uint8_t* restore(const uint8_t* buffer) override;
|
const uint8_t* restore(const uint8_t* buffer) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void beforeStateChange(LoadState& newState) override;
|
void beforeStateChange(LoadState& newState) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Function properties
|
// Function properties
|
||||||
|
@ -21,7 +21,6 @@ class BusAccessUnit;
|
|||||||
*/
|
*/
|
||||||
class SecureApplicationLayer : public ApplicationLayer
|
class SecureApplicationLayer : public ApplicationLayer
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* The constructor.
|
* The constructor.
|
||||||
@ -33,31 +32,29 @@ class SecureApplicationLayer : public ApplicationLayer
|
|||||||
void groupAddressTable(AddressTableObject& addrTable);
|
void groupAddressTable(AddressTableObject& addrTable);
|
||||||
|
|
||||||
// from transport layer
|
// from transport layer
|
||||||
virtual void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) override;
|
void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) override;
|
||||||
virtual void dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap,
|
void dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap,
|
||||||
APDU& apdu, bool status) override;
|
APDU& apdu, bool status) override;
|
||||||
virtual void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override;
|
void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override;
|
||||||
virtual void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, bool status) override;
|
void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, bool status) override;
|
||||||
virtual void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override;
|
void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override;
|
||||||
virtual void dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, bool status) override;
|
void dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, bool status) override;
|
||||||
virtual void dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override;
|
void dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override;
|
||||||
virtual void dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status) override;
|
void dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status) override;
|
||||||
virtual void dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu) override;
|
void dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu) override;
|
||||||
virtual void dataConnectedConfirm(uint16_t tsap) override;
|
void dataConnectedConfirm(uint16_t tsap) override;
|
||||||
|
|
||||||
void loop();
|
void loop();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// to transport layer
|
// to transport layer
|
||||||
virtual void dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) override;
|
void dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl) override;
|
||||||
virtual void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl) override;
|
void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl) override;
|
||||||
virtual void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl) override;
|
void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl) override;
|
||||||
virtual void dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu, const SecurityControl& secCtrl) override;
|
void dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu, const SecurityControl& secCtrl) override;
|
||||||
virtual void dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu, const SecurityControl& secCtrl) override; // apdu must be valid until it was confirmed
|
void dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu, const SecurityControl& secCtrl) override; // apdu must be valid until it was confirmed
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
enum class AddrType : uint8_t
|
enum class AddrType : uint8_t
|
||||||
{
|
{
|
||||||
group,
|
group,
|
||||||
|
@ -490,7 +490,6 @@ uint16_t SecurityInterfaceObject::getNumberOfElements(PropertyID propId)
|
|||||||
|
|
||||||
uint64_t SecurityInterfaceObject::getLastValidSequenceNumber(uint16_t deviceAddr)
|
uint64_t SecurityInterfaceObject::getLastValidSequenceNumber(uint16_t deviceAddr)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Get number of entries for this property
|
// Get number of entries for this property
|
||||||
uint16_t numElements = getNumberOfElements(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE);
|
uint16_t numElements = getNumberOfElements(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE);
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ class SecurityInterfaceObject: public InterfaceObject
|
|||||||
public:
|
public:
|
||||||
SecurityInterfaceObject();
|
SecurityInterfaceObject();
|
||||||
|
|
||||||
virtual void masterReset(EraseCode eraseCode, uint8_t channel) override;
|
void masterReset(EraseCode eraseCode, uint8_t channel) override;
|
||||||
|
|
||||||
bool isSecurityModeEnabled();
|
bool isSecurityModeEnabled();
|
||||||
|
|
||||||
|
@ -6,6 +6,19 @@
|
|||||||
#include "callback_property.h"
|
#include "callback_property.h"
|
||||||
#include "data_property.h"
|
#include "data_property.h"
|
||||||
|
|
||||||
|
BeforeTablesUnloadCallback TableObject::_beforeTablesUnload = 0;
|
||||||
|
uint8_t TableObject::_tableUnloadCount = 0;
|
||||||
|
|
||||||
|
void TableObject::beforeTablesUnloadCallback(BeforeTablesUnloadCallback func)
|
||||||
|
{
|
||||||
|
_beforeTablesUnload = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
BeforeTablesUnloadCallback TableObject::beforeTablesUnloadCallback()
|
||||||
|
{
|
||||||
|
return _beforeTablesUnload;
|
||||||
|
}
|
||||||
|
|
||||||
TableObject::TableObject(Memory& memory)
|
TableObject::TableObject(Memory& memory)
|
||||||
: _memory(memory)
|
: _memory(memory)
|
||||||
{}
|
{}
|
||||||
@ -13,6 +26,19 @@ TableObject::TableObject(Memory& memory)
|
|||||||
TableObject::~TableObject()
|
TableObject::~TableObject()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
void TableObject::beforeStateChange(LoadState& newState)
|
||||||
|
{
|
||||||
|
if (newState == LS_LOADED && _tableUnloadCount > 0)
|
||||||
|
_tableUnloadCount--;
|
||||||
|
if (_tableUnloadCount > 0)
|
||||||
|
return;
|
||||||
|
if (newState == LS_UNLOADED) {
|
||||||
|
_tableUnloadCount++;
|
||||||
|
if (_beforeTablesUnload != 0)
|
||||||
|
_beforeTablesUnload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LoadState TableObject::loadState()
|
LoadState TableObject::loadState()
|
||||||
{
|
{
|
||||||
return _state;
|
return _state;
|
||||||
@ -82,7 +108,11 @@ bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (doFill)
|
if (doFill)
|
||||||
memset(_data, fillByte, size);
|
{
|
||||||
|
uint32_t addr = _memory.toRelative(_data);
|
||||||
|
for(int i = 0; i< size;i++)
|
||||||
|
_memory.writeMemory(addr+i, 1, &fillByte);
|
||||||
|
}
|
||||||
|
|
||||||
_size = size;
|
_size = size;
|
||||||
|
|
||||||
@ -139,6 +169,7 @@ void TableObject::loadEventLoading(const uint8_t* data)
|
|||||||
case LE_START_LOADING:
|
case LE_START_LOADING:
|
||||||
break;
|
break;
|
||||||
case LE_LOAD_COMPLETED:
|
case LE_LOAD_COMPLETED:
|
||||||
|
_memory.saveMemory();
|
||||||
loadState(LS_LOADED);
|
loadState(LS_LOADED);
|
||||||
break;
|
break;
|
||||||
case LE_UNLOAD:
|
case LE_UNLOAD:
|
||||||
@ -293,7 +324,6 @@ void TableObject::initializeProperties(size_t propertiesSize, Property** propert
|
|||||||
//TODO: missing
|
//TODO: missing
|
||||||
|
|
||||||
// 23 PID_TABLE 3 / (3)
|
// 23 PID_TABLE 3 / (3)
|
||||||
// 27 PID_MCB_TABLE 3 / 3
|
|
||||||
|
|
||||||
uint8_t ownPropertiesCount = sizeof(ownProperties) / sizeof(Property*);
|
uint8_t ownPropertiesCount = sizeof(ownProperties) / sizeof(Property*);
|
||||||
|
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
#include "interface_object.h"
|
#include "interface_object.h"
|
||||||
|
|
||||||
class Memory;
|
class Memory;
|
||||||
|
|
||||||
|
typedef void (*BeforeTablesUnloadCallback)();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides common functionality for interface objects that are configured by ETS with MemorWrite.
|
* This class provides common functionality for interface objects that are configured by ETS with MemorWrite.
|
||||||
*/
|
*/
|
||||||
@ -28,14 +31,18 @@ class TableObject: public InterfaceObject
|
|||||||
uint8_t* save(uint8_t* buffer) override;
|
uint8_t* save(uint8_t* buffer) override;
|
||||||
const uint8_t* restore(const uint8_t* buffer) override;
|
const uint8_t* restore(const uint8_t* buffer) override;
|
||||||
uint16_t saveSize() override;
|
uint16_t saveSize() override;
|
||||||
protected:
|
|
||||||
|
static void beforeTablesUnloadCallback(BeforeTablesUnloadCallback func);
|
||||||
|
static BeforeTablesUnloadCallback beforeTablesUnloadCallback();
|
||||||
|
|
||||||
|
protected:
|
||||||
/**
|
/**
|
||||||
* This method is called before the interface object enters a new ::LoadState.
|
* 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()
|
* If there is a error changing the state newState should be set to ::LS_ERROR and errorCode()
|
||||||
* to a reason for the failure.
|
* to a reason for the failure.
|
||||||
*/
|
*/
|
||||||
virtual void beforeStateChange(LoadState& newState) {}
|
virtual void beforeStateChange(LoadState& newState);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the internal data of the interface object. This pointer belongs to the TableObject class and
|
* returns the internal data of the interface object. This pointer belongs to the TableObject class and
|
||||||
* must not be freed.
|
* must not be freed.
|
||||||
@ -47,7 +54,9 @@ class TableObject: public InterfaceObject
|
|||||||
void errorCode(ErrorCode errorCode);
|
void errorCode(ErrorCode errorCode);
|
||||||
|
|
||||||
void initializeProperties(size_t propertiesSize, Property** properties) override;
|
void initializeProperties(size_t propertiesSize, Property** properties) override;
|
||||||
|
|
||||||
|
static BeforeTablesUnloadCallback _beforeTablesUnload;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t tableReference();
|
uint32_t tableReference();
|
||||||
bool allocTable(uint32_t size, bool doFill, uint8_t fillByte);
|
bool allocTable(uint32_t size, bool doFill, uint8_t fillByte);
|
||||||
@ -68,6 +77,7 @@ class TableObject: public InterfaceObject
|
|||||||
LoadState _state = LS_UNLOADED;
|
LoadState _state = LS_UNLOADED;
|
||||||
Memory& _memory;
|
Memory& _memory;
|
||||||
uint8_t *_data = 0;
|
uint8_t *_data = 0;
|
||||||
|
static uint8_t _tableUnloadCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* used to store size of data() in allocTable(), needed for calculation of crc in PID_MCB_TABLE.
|
* used to store size of data() in allocTable(), needed for calculation of crc in PID_MCB_TABLE.
|
||||||
|
@ -31,6 +31,9 @@
|
|||||||
#define U_STOP_MODE_REQ 0x0E
|
#define U_STOP_MODE_REQ 0x0E
|
||||||
#define U_EXIT_STOP_MODE_REQ 0x0F
|
#define U_EXIT_STOP_MODE_REQ 0x0F
|
||||||
#define U_ACK_REQ 0x10 //-0x17
|
#define U_ACK_REQ 0x10 //-0x17
|
||||||
|
#define U_ACK_REQ_NACK 0x04
|
||||||
|
#define U_ACK_REQ_BUSY 0x02
|
||||||
|
#define U_ACK_REQ_ADRESSED 0x01
|
||||||
#define U_CONFIGURE_REQ 0x18
|
#define U_CONFIGURE_REQ 0x18
|
||||||
#define U_INT_REG_WR_REQ 0x28
|
#define U_INT_REG_WR_REQ 0x28
|
||||||
#define U_INT_REG_RD_REQ 0x38
|
#define U_INT_REG_RD_REQ 0x38
|
||||||
@ -82,7 +85,6 @@
|
|||||||
enum {
|
enum {
|
||||||
TX_IDLE,
|
TX_IDLE,
|
||||||
TX_FRAME,
|
TX_FRAME,
|
||||||
TX_WAIT_ECHO,
|
|
||||||
TX_WAIT_CONN
|
TX_WAIT_CONN
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -100,10 +102,23 @@ enum {
|
|||||||
#define RESET_TIMEOUT 100 //milli seconds
|
#define RESET_TIMEOUT 100 //milli seconds
|
||||||
#define TX_TIMEPAUSE 0 // 0 means 1 milli seconds
|
#define TX_TIMEPAUSE 0 // 0 means 1 milli seconds
|
||||||
|
|
||||||
|
#define OVERRUN_COUNT 7 //bytes; max. allowed bytes in receive buffer (on start) to see it as overrun
|
||||||
|
|
||||||
// If this threshold is reached loop() goes into
|
// If this threshold is reached loop() goes into
|
||||||
// "hog mode" where it stays in loop() while L2 address reception
|
// "hog mode" where it stays in loop() while L2 address reception
|
||||||
#define HOGMODE_THRESHOLD 3 // milli seconds
|
#define HOGMODE_THRESHOLD 3 // milli seconds
|
||||||
|
|
||||||
|
void TpUartDataLinkLayer::enterRxWaitEOP()
|
||||||
|
{
|
||||||
|
// Flush input
|
||||||
|
while (_platform.uartAvailable())
|
||||||
|
{
|
||||||
|
_platform.readUart();
|
||||||
|
}
|
||||||
|
_lastByteRxTime = millis();
|
||||||
|
_rxState = RX_WAIT_EOP;
|
||||||
|
}
|
||||||
|
|
||||||
void TpUartDataLinkLayer::loop()
|
void TpUartDataLinkLayer::loop()
|
||||||
{
|
{
|
||||||
if (!_enabled)
|
if (!_enabled)
|
||||||
@ -122,7 +137,6 @@ void TpUartDataLinkLayer::loop()
|
|||||||
// Loop once and repeat as long we have rx data available
|
// Loop once and repeat as long we have rx data available
|
||||||
do {
|
do {
|
||||||
// Signals to communicate from rx part with the tx part
|
// 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
|
uint8_t dataConnMsg = 0; // The DATA_CONN message just seen or 0
|
||||||
|
|
||||||
#ifdef KNX_WAIT_FOR_ADDR
|
#ifdef KNX_WAIT_FOR_ADDR
|
||||||
@ -150,6 +164,12 @@ void TpUartDataLinkLayer::loop()
|
|||||||
case RX_WAIT_START:
|
case RX_WAIT_START:
|
||||||
if (_platform.uartAvailable())
|
if (_platform.uartAvailable())
|
||||||
{
|
{
|
||||||
|
if (_platform.uartAvailable() > OVERRUN_COUNT)
|
||||||
|
{
|
||||||
|
print("input buffer overrun: "); println(_platform.uartAvailable());
|
||||||
|
enterRxWaitEOP();
|
||||||
|
break;
|
||||||
|
}
|
||||||
rxByte = _platform.readUart();
|
rxByte = _platform.readUart();
|
||||||
#ifdef DBG_TRACE
|
#ifdef DBG_TRACE
|
||||||
print(rxByte, HEX);
|
print(rxByte, HEX);
|
||||||
@ -258,7 +278,7 @@ void TpUartDataLinkLayer::loop()
|
|||||||
if (millis() - _lastByteRxTime > EOPR_TIMEOUT)
|
if (millis() - _lastByteRxTime > EOPR_TIMEOUT)
|
||||||
{
|
{
|
||||||
_rxState = RX_WAIT_START;
|
_rxState = RX_WAIT_START;
|
||||||
print("EOPR inside RX_L_ADDR");
|
println("EOPR @ RX_L_ADDR");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!_platform.uartAvailable())
|
if (!_platform.uartAvailable())
|
||||||
@ -274,27 +294,19 @@ void TpUartDataLinkLayer::loop()
|
|||||||
if (_RxByteCnt == 7)
|
if (_RxByteCnt == 7)
|
||||||
{
|
{
|
||||||
//Destination Address + payload available
|
//Destination Address + payload available
|
||||||
//check if echo
|
//check if echo; ignore repeat bit of control byte
|
||||||
if (_sendBuffer != nullptr && (!((buffer[0] ^ _sendBuffer[0]) & ~0x20) && !memcmp(buffer + _convert + 1, _sendBuffer + 1, 5)))
|
_isEcho = (_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
|
//convert into Extended.ind
|
||||||
if (_convert)
|
if (_convert)
|
||||||
{
|
{
|
||||||
uint8_t payloadLength = buffer[6] & 0x0F;
|
|
||||||
buffer[1] = buffer[6] & 0xF0;
|
buffer[1] = buffer[6] & 0xF0;
|
||||||
buffer[6] = payloadLength;
|
buffer[6] &= 0x0F;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_isEcho)
|
if (!_isEcho)
|
||||||
{
|
{
|
||||||
uint8_t c = 0x10;
|
uint8_t c = U_ACK_REQ;
|
||||||
|
|
||||||
// The bau knows everything and could either check the address table object (normal device)
|
// 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.
|
// or any filter tables (coupler) to see if we are addressed.
|
||||||
@ -305,11 +317,11 @@ void TpUartDataLinkLayer::loop()
|
|||||||
|
|
||||||
if (_cb.isAckRequired(addr, isGroupAddress))
|
if (_cb.isAckRequired(addr, isGroupAddress))
|
||||||
{
|
{
|
||||||
c |= 0x01;
|
c |= U_ACK_REQ_ADRESSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hint: We can send directly here, this doesn't disturb other transmissions
|
// Hint: We can send directly here, this doesn't disturb other transmissions
|
||||||
// We don't have to update _lastByteTxTime because after ACK the timing is not so tight
|
// We don't have to update _lastByteTxTime because after U_ACK_REQ the timing is not so tight
|
||||||
_platform.writeUart(c);
|
_platform.writeUart(c);
|
||||||
}
|
}
|
||||||
_rxState = RX_L_DATA;
|
_rxState = RX_L_DATA;
|
||||||
@ -325,8 +337,8 @@ void TpUartDataLinkLayer::loop()
|
|||||||
#endif
|
#endif
|
||||||
if (_RxByteCnt == MAX_KNX_TELEGRAM_SIZE)
|
if (_RxByteCnt == MAX_KNX_TELEGRAM_SIZE)
|
||||||
{
|
{
|
||||||
_rxState = RX_WAIT_EOP;
|
|
||||||
println("invalid telegram size");
|
println("invalid telegram size");
|
||||||
|
enterRxWaitEOP();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -336,26 +348,25 @@ void TpUartDataLinkLayer::loop()
|
|||||||
if (_RxByteCnt == buffer[6] + 7 + 2)
|
if (_RxByteCnt == buffer[6] + 7 + 2)
|
||||||
{
|
{
|
||||||
//complete Frame received, payloadLength+1 for TCPI +1 for CRC
|
//complete Frame received, payloadLength+1 for TCPI +1 for CRC
|
||||||
|
//check if crc is correct
|
||||||
if (rxByte == (uint8_t)(~_xorSum))
|
if (rxByte == (uint8_t)(~_xorSum))
|
||||||
{
|
{
|
||||||
//check if crc is correct
|
if (!_isEcho)
|
||||||
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
|
|
||||||
{
|
{
|
||||||
_receiveBuffer[0] = 0x29;
|
_receiveBuffer[0] = 0x29;
|
||||||
_receiveBuffer[1] = 0;
|
_receiveBuffer[1] = 0;
|
||||||
|
#ifdef DBG_TRACE
|
||||||
|
unsigned long runTime = millis();
|
||||||
|
#endif
|
||||||
frameBytesReceived(_receiveBuffer, _RxByteCnt + 2);
|
frameBytesReceived(_receiveBuffer, _RxByteCnt + 2);
|
||||||
|
#ifdef DBG_TRACE
|
||||||
|
runTime = millis() - runTime;
|
||||||
|
if (runTime > (OVERRUN_COUNT*14)/10)
|
||||||
|
{
|
||||||
|
// complain when the runtime was long than the OVERRUN_COUNT allows
|
||||||
|
print("processing received frame took: "); print(runTime); println(" ms");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
_rxState = RX_WAIT_START;
|
_rxState = RX_WAIT_START;
|
||||||
#ifdef DBG_TRACE
|
#ifdef DBG_TRACE
|
||||||
@ -365,7 +376,7 @@ void TpUartDataLinkLayer::loop()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
println("frame with invalid crc ignored");
|
println("frame with invalid crc ignored");
|
||||||
_rxState = RX_WAIT_EOP;
|
enterRxWaitEOP();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -376,20 +387,18 @@ void TpUartDataLinkLayer::loop()
|
|||||||
case RX_WAIT_EOP:
|
case RX_WAIT_EOP:
|
||||||
if (millis() - _lastByteRxTime > EOP_TIMEOUT)
|
if (millis() - _lastByteRxTime > EOP_TIMEOUT)
|
||||||
{
|
{
|
||||||
_RxByteCnt = 0;
|
// found a gap
|
||||||
_rxState = RX_WAIT_START;
|
_rxState = RX_WAIT_START;
|
||||||
#ifdef DBG_TRACE
|
#ifdef DBG_TRACE
|
||||||
println("RX_WAIT_START");
|
println("RX_WAIT_START");
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!_platform.uartAvailable())
|
if (_platform.uartAvailable())
|
||||||
break;
|
{
|
||||||
_lastByteRxTime = millis();
|
_platform.readUart();
|
||||||
rxByte = _platform.readUart();
|
_lastByteRxTime = millis();
|
||||||
#ifdef DBG_TRACE
|
}
|
||||||
print(rxByte, HEX);
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -397,8 +406,8 @@ void TpUartDataLinkLayer::loop()
|
|||||||
} while (_rxState == RX_L_ADDR && (stayInRx || _platform.uartAvailable()));
|
} while (_rxState == RX_L_ADDR && (stayInRx || _platform.uartAvailable()));
|
||||||
|
|
||||||
// Check for spurios DATA_CONN message
|
// Check for spurios DATA_CONN message
|
||||||
if (dataConnMsg && _txState != TX_WAIT_CONN && _txState != TX_WAIT_ECHO) {
|
if (dataConnMsg && _txState != TX_WAIT_CONN) {
|
||||||
println("got unexpected L_DATA_CON");
|
println("unexpected L_DATA_CON");
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_txState)
|
switch (_txState)
|
||||||
@ -419,9 +428,9 @@ void TpUartDataLinkLayer::loop()
|
|||||||
if (sendSingleFrameByte() == false)
|
if (sendSingleFrameByte() == false)
|
||||||
{
|
{
|
||||||
_waitConfirmStartTime = millis();
|
_waitConfirmStartTime = millis();
|
||||||
_txState = TX_WAIT_ECHO;
|
_txState = TX_WAIT_CONN;
|
||||||
#ifdef DBG_TRACE
|
#ifdef DBG_TRACE
|
||||||
println("TX_WAIT_ECHO");
|
println("TX_WAIT_CONN");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -430,22 +439,10 @@ void TpUartDataLinkLayer::loop()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TX_WAIT_ECHO:
|
|
||||||
case TX_WAIT_CONN:
|
case TX_WAIT_CONN:
|
||||||
if (isEchoComplete)
|
if (dataConnMsg)
|
||||||
{
|
{
|
||||||
_txState = TX_WAIT_CONN;
|
dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, (dataConnMsg & SUCCESS));
|
||||||
#ifdef DBG_TRACE
|
|
||||||
println("TX_WAIT_CONN");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else if (dataConnMsg)
|
|
||||||
{
|
|
||||||
bool waitEcho = (_txState == TX_WAIT_ECHO);
|
|
||||||
if (waitEcho) {
|
|
||||||
println("L_DATA_CON without echo");
|
|
||||||
}
|
|
||||||
dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, !waitEcho && ((dataConnMsg & SUCCESS) > 0));
|
|
||||||
delete[] _sendBuffer;
|
delete[] _sendBuffer;
|
||||||
_sendBuffer = 0;
|
_sendBuffer = 0;
|
||||||
_sendBufferLength = 0;
|
_sendBufferLength = 0;
|
||||||
@ -579,7 +576,8 @@ DptMedium TpUartDataLinkLayer::mediumType() const
|
|||||||
bool TpUartDataLinkLayer::sendSingleFrameByte()
|
bool TpUartDataLinkLayer::sendSingleFrameByte()
|
||||||
{
|
{
|
||||||
uint8_t cmd[2];
|
uint8_t cmd[2];
|
||||||
uint8_t idx = _TxByteCnt / 64;
|
|
||||||
|
uint8_t idx = _TxByteCnt >> 6;
|
||||||
|
|
||||||
if (_sendBuffer == NULL)
|
if (_sendBuffer == NULL)
|
||||||
return false;
|
return false;
|
||||||
@ -594,9 +592,9 @@ bool TpUartDataLinkLayer::sendSingleFrameByte()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_TxByteCnt != _sendBufferLength - 1)
|
if (_TxByteCnt != _sendBufferLength - 1)
|
||||||
cmd[0] = U_L_DATA_START_CONT_REQ | _TxByteCnt;
|
cmd[0] = U_L_DATA_START_CONT_REQ | (_TxByteCnt & 0x3F);
|
||||||
else
|
else
|
||||||
cmd[0] = U_L_DATA_END_REQ | _TxByteCnt;
|
cmd[0] = U_L_DATA_END_REQ | (_TxByteCnt & 0x3F);
|
||||||
|
|
||||||
cmd[1] = _sendBuffer[_TxByteCnt];
|
cmd[1] = _sendBuffer[_TxByteCnt];
|
||||||
#ifdef DBG_TRACE
|
#ifdef DBG_TRACE
|
||||||
@ -618,7 +616,6 @@ bool TpUartDataLinkLayer::sendSingleFrameByte()
|
|||||||
|
|
||||||
void TpUartDataLinkLayer::addFrameTxQueue(CemiFrame& frame)
|
void TpUartDataLinkLayer::addFrameTxQueue(CemiFrame& frame)
|
||||||
{
|
{
|
||||||
|
|
||||||
_tx_queue_frame_t* tx_frame = new _tx_queue_frame_t;
|
_tx_queue_frame_t* tx_frame = new _tx_queue_frame_t;
|
||||||
tx_frame->length = frame.telegramLengthtTP();
|
tx_frame->length = frame.telegramLengthtTP();
|
||||||
tx_frame->data = new uint8_t[tx_frame->length];
|
tx_frame->data = new uint8_t[tx_frame->length];
|
||||||
|
@ -27,7 +27,7 @@ class TpUartDataLinkLayer : public DataLinkLayer
|
|||||||
void loop();
|
void loop();
|
||||||
void enabled(bool value);
|
void enabled(bool value);
|
||||||
bool enabled() const;
|
bool enabled() const;
|
||||||
virtual DptMedium mediumType() const override;
|
DptMedium mediumType() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _enabled = false;
|
bool _enabled = false;
|
||||||
@ -68,6 +68,7 @@ class TpUartDataLinkLayer : public DataLinkLayer
|
|||||||
bool sendFrame(CemiFrame& frame);
|
bool sendFrame(CemiFrame& frame);
|
||||||
void frameBytesReceived(uint8_t* buffer, uint16_t length);
|
void frameBytesReceived(uint8_t* buffer, uint16_t length);
|
||||||
void dataConBytesReceived(uint8_t* buffer, uint16_t length, bool success);
|
void dataConBytesReceived(uint8_t* buffer, uint16_t length, bool success);
|
||||||
|
void enterRxWaitEOP();
|
||||||
bool resetChip();
|
bool resetChip();
|
||||||
void stopChip();
|
void stopChip();
|
||||||
|
|
||||||
|
@ -343,7 +343,6 @@ void TransportLayer::dataIndividualConfirm(AckType ack, uint16_t destination, Ho
|
|||||||
A5(destination);
|
A5(destination);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Disconnect:
|
case Disconnect:
|
||||||
|
@ -63,7 +63,6 @@ void UsbTunnelInterface::loop()
|
|||||||
handleHidReportRxQueue();
|
handleHidReportRxQueue();
|
||||||
rxHaveCompletePacket = false;
|
rxHaveCompletePacket = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* USB TX */
|
/* USB TX */
|
||||||
@ -136,7 +135,6 @@ void UsbTunnelInterface::loadNextTxFrame(uint8_t** sendBuffer, uint16_t* sendBuf
|
|||||||
}
|
}
|
||||||
println("");
|
println("");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UsbTunnelInterface::sendKnxHidReport(ProtocolIdType protId, ServiceIdType servId, uint8_t* data, uint16_t length)
|
void UsbTunnelInterface::sendKnxHidReport(ProtocolIdType protId, ServiceIdType servId, uint8_t* data, uint16_t length)
|
||||||
|
@ -15,35 +15,46 @@
|
|||||||
#define ICACHE_RAM_ATTR
|
#define ICACHE_RAM_ATTR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ICACHE_RAM_ATTR void buttonUp()
|
#ifndef PROG_BTN_PRESS_MIN_MILLIS
|
||||||
|
#define PROG_BTN_PRESS_MIN_MILLIS 50
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PROG_BTN_PRESS_MAX_MILLIS
|
||||||
|
#define PROG_BTN_PRESS_MAX_MILLIS 500
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
ICACHE_RAM_ATTR void buttonEvent()
|
||||||
{
|
{
|
||||||
static uint32_t lastpressed=0;
|
static uint32_t lastEvent=0;
|
||||||
if (millis() - lastpressed > 200){
|
uint32_t diff = millis() - lastEvent;
|
||||||
|
if (diff >= PROG_BTN_PRESS_MIN_MILLIS && diff <= PROG_BTN_PRESS_MAX_MILLIS){
|
||||||
knx.toggleProgMode();
|
knx.toggleProgMode();
|
||||||
lastpressed = millis();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastEvent = millis();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_SAMD
|
#ifdef ARDUINO_ARCH_SAMD
|
||||||
// predefined global instance for TP or RF or TP/RF coupler
|
// predefined global instance for TP or RF or TP/RF coupler
|
||||||
#if MASK_VERSION == 0x07B0
|
#if MASK_VERSION == 0x07B0
|
||||||
KnxFacade<SamdPlatform, Bau07B0> knx(buttonUp);
|
KnxFacade<SamdPlatform, Bau07B0> knx(buttonEvent);
|
||||||
#elif MASK_VERSION == 0x27B0
|
#elif MASK_VERSION == 0x27B0
|
||||||
KnxFacade<SamdPlatform, Bau27B0> knx(buttonUp);
|
KnxFacade<SamdPlatform, Bau27B0> knx(buttonEvent);
|
||||||
#elif MASK_VERSION == 0x2920
|
#elif MASK_VERSION == 0x2920
|
||||||
KnxFacade<SamdPlatform, Bau2920> knx(buttonUp);
|
KnxFacade<SamdPlatform, Bau2920> knx(buttonEvent);
|
||||||
#else
|
#else
|
||||||
#error "Mask version not supported on ARDUINO_ARCH_SAMD"
|
#error "Mask version not supported on ARDUINO_ARCH_SAMD"
|
||||||
#endif
|
#endif
|
||||||
#elif defined(ARDUINO_ARCH_RP2040)
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
// predefined global instance for TP or RF or TP/RF coupler
|
// predefined global instance for TP or RF or TP/RF coupler
|
||||||
#if MASK_VERSION == 0x07B0
|
#if MASK_VERSION == 0x07B0
|
||||||
KnxFacade<RP2040ArduinoPlatform, Bau07B0> knx(buttonUp);
|
KnxFacade<RP2040ArduinoPlatform, Bau07B0> knx(buttonEvent);
|
||||||
#elif MASK_VERSION == 0x27B0
|
#elif MASK_VERSION == 0x27B0
|
||||||
KnxFacade<RP2040ArduinoPlatform, Bau27B0> knx(buttonUp);
|
KnxFacade<RP2040ArduinoPlatform, Bau27B0> knx(buttonEvent);
|
||||||
#elif MASK_VERSION == 0x2920
|
#elif MASK_VERSION == 0x2920
|
||||||
KnxFacade<RP2040ArduinoPlatform, Bau2920> knx(buttonUp);
|
KnxFacade<RP2040ArduinoPlatform, Bau2920> knx(buttonEvent);
|
||||||
#else
|
#else
|
||||||
#error "Mask version not supported on ARDUINO_ARCH_RP2040"
|
#error "Mask version not supported on ARDUINO_ARCH_RP2040"
|
||||||
#endif
|
#endif
|
||||||
@ -51,11 +62,11 @@
|
|||||||
#elif defined(ARDUINO_ARCH_ESP8266)
|
#elif defined(ARDUINO_ARCH_ESP8266)
|
||||||
// predefined global instance for TP or IP or TP/IP coupler
|
// predefined global instance for TP or IP or TP/IP coupler
|
||||||
#if MASK_VERSION == 0x07B0
|
#if MASK_VERSION == 0x07B0
|
||||||
KnxFacade<EspPlatform, Bau07B0> knx(buttonUp);
|
KnxFacade<EspPlatform, Bau07B0> knx(buttonEvent);
|
||||||
#elif MASK_VERSION == 0x57B0
|
#elif MASK_VERSION == 0x57B0
|
||||||
KnxFacade<EspPlatform, Bau57B0> knx(buttonUp);
|
KnxFacade<EspPlatform, Bau57B0> knx(buttonEvent);
|
||||||
#elif MASK_VERSION == 0x091A
|
#elif MASK_VERSION == 0x091A
|
||||||
KnxFacade<EspPlatform, Bau091A> knx(buttonUp);
|
KnxFacade<EspPlatform, Bau091A> knx(buttonEvent);
|
||||||
#else
|
#else
|
||||||
#error "Mask version not supported on ARDUINO_ARCH_ESP8266"
|
#error "Mask version not supported on ARDUINO_ARCH_ESP8266"
|
||||||
#endif
|
#endif
|
||||||
@ -63,18 +74,18 @@
|
|||||||
#elif defined(ARDUINO_ARCH_ESP32)
|
#elif defined(ARDUINO_ARCH_ESP32)
|
||||||
// predefined global instance for TP or IP or TP/IP coupler
|
// predefined global instance for TP or IP or TP/IP coupler
|
||||||
#if MASK_VERSION == 0x07B0
|
#if MASK_VERSION == 0x07B0
|
||||||
KnxFacade<Esp32Platform, Bau07B0> knx(buttonUp);
|
KnxFacade<Esp32Platform, Bau07B0> knx(buttonEvent);
|
||||||
#elif MASK_VERSION == 0x57B0
|
#elif MASK_VERSION == 0x57B0
|
||||||
KnxFacade<Esp32Platform, Bau57B0> knx(buttonUp);
|
KnxFacade<Esp32Platform, Bau57B0> knx(buttonEvent);
|
||||||
#elif MASK_VERSION == 0x091A
|
#elif MASK_VERSION == 0x091A
|
||||||
KnxFacade<Esp32Platform, Bau091A> knx(buttonUp);
|
KnxFacade<Esp32Platform, Bau091A> knx(buttonEvent);
|
||||||
#else
|
#else
|
||||||
#error "Mask version not supported on ARDUINO_ARCH_ESP32"
|
#error "Mask version not supported on ARDUINO_ARCH_ESP32"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#elif defined(ARDUINO_ARCH_STM32)
|
#elif defined(ARDUINO_ARCH_STM32)
|
||||||
#if MASK_VERSION == 0x07B0
|
#if MASK_VERSION == 0x07B0
|
||||||
KnxFacade<Stm32Platform, Bau07B0> knx(buttonUp);
|
KnxFacade<Stm32Platform, Bau07B0> knx(buttonEvent);
|
||||||
#else
|
#else
|
||||||
#error "Mask version not supported on ARDUINO_ARCH_STM32"
|
#error "Mask version not supported on ARDUINO_ARCH_STM32"
|
||||||
#endif
|
#endif
|
||||||
|
@ -48,13 +48,20 @@
|
|||||||
#else
|
#else
|
||||||
#if !defined(LED_BUILTIN)
|
#if !defined(LED_BUILTIN)
|
||||||
#define LED_BUILTIN 5 // see GPIO_PinConfig gpioPinConfigs[]
|
#define LED_BUILTIN 5 // see GPIO_PinConfig gpioPinConfigs[]
|
||||||
#endif
|
#endif
|
||||||
#include "cc1310_platform.h"
|
#include "cc1310_platform.h"
|
||||||
#ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE
|
#ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE
|
||||||
extern void buttonUp();
|
extern void buttonUp();
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef KNX_LED
|
||||||
|
#define KNX_LED LED_BUILTIN
|
||||||
|
#endif
|
||||||
|
#ifndef KNX_BUTTON
|
||||||
|
#define KNX_BUTTON 0
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef const uint8_t* (*RestoreCallback)(const uint8_t* buffer);
|
typedef const uint8_t* (*RestoreCallback)(const uint8_t* buffer);
|
||||||
typedef uint8_t* (*SaveCallback)(uint8_t* buffer);
|
typedef uint8_t* (*SaveCallback)(uint8_t* buffer);
|
||||||
typedef void (*IsrFunctionPtr)();
|
typedef void (*IsrFunctionPtr)();
|
||||||
@ -73,6 +80,7 @@ template <class P, class B> class KnxFacade : private SaveRestore
|
|||||||
|
|
||||||
KnxFacade(B& bau) : _bau(bau)
|
KnxFacade(B& bau) : _bau(bau)
|
||||||
{
|
{
|
||||||
|
_platformPtr = static_cast<P*>(&bau.platform());
|
||||||
manufacturerId(0xfa);
|
manufacturerId(0xfa);
|
||||||
bauNumber(platform().uniqueSerialNumber());
|
bauNumber(platform().uniqueSerialNumber());
|
||||||
_bau.addSaveRestore(this);
|
_bau.addSaveRestore(this);
|
||||||
@ -176,24 +184,7 @@ template <class P, class B> class KnxFacade : private SaveRestore
|
|||||||
_progLedOnCallback = progLedOnCallback;
|
_progLedOnCallback = progLedOnCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* returns RISING if interrupt is created in a rising signal, FALLING otherwise
|
|
||||||
*/
|
|
||||||
uint32_t buttonPinInterruptOn()
|
|
||||||
{
|
|
||||||
return _buttonPinInterruptOn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets if the programming button creates a RISING or a FALLING signal.
|
|
||||||
*
|
|
||||||
* Set to RISING for GPIO--BUTTON--VDD or to FALLING for GPIO--BUTTON--GND
|
|
||||||
*/
|
|
||||||
void buttonPinInterruptOn(uint32_t value)
|
|
||||||
{
|
|
||||||
_buttonPinInterruptOn = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t buttonPin()
|
uint32_t buttonPin()
|
||||||
{
|
{
|
||||||
return _buttonPin;
|
return _buttonPin;
|
||||||
@ -280,9 +271,9 @@ template <class P, class B> class KnxFacade : private SaveRestore
|
|||||||
{
|
{
|
||||||
// Workaround for https://github.com/arduino/ArduinoCore-samd/issues/587
|
// Workaround for https://github.com/arduino/ArduinoCore-samd/issues/587
|
||||||
#if (ARDUINO_API_VERSION >= 10200)
|
#if (ARDUINO_API_VERSION >= 10200)
|
||||||
attachInterrupt(_buttonPin, _progButtonISRFuncPtr, (PinStatus)_buttonPinInterruptOn);
|
attachInterrupt(_buttonPin, _progButtonISRFuncPtr, (PinStatus)CHANGE);
|
||||||
#else
|
#else
|
||||||
attachInterrupt(_buttonPin, _progButtonISRFuncPtr, _buttonPinInterruptOn);
|
attachInterrupt(_buttonPin, _progButtonISRFuncPtr, CHANGE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,7 +391,18 @@ template <class P, class B> class KnxFacade : private SaveRestore
|
|||||||
|
|
||||||
void restart(uint16_t individualAddress)
|
void restart(uint16_t individualAddress)
|
||||||
{
|
{
|
||||||
_bau.restartRequest(individualAddress);
|
SecurityControl sc = {false, None};
|
||||||
|
_bau.restartRequest(individualAddress, sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void beforeRestartCallback(BeforeRestartCallback func)
|
||||||
|
{
|
||||||
|
_bau.beforeRestartCallback(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
BeforeRestartCallback beforeRestartCallback()
|
||||||
|
{
|
||||||
|
return _bau.beforeRestartCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -410,9 +412,8 @@ template <class P, class B> class KnxFacade : private SaveRestore
|
|||||||
ProgLedOnCallback _progLedOnCallback = 0;
|
ProgLedOnCallback _progLedOnCallback = 0;
|
||||||
ProgLedOffCallback _progLedOffCallback = 0;
|
ProgLedOffCallback _progLedOffCallback = 0;
|
||||||
uint32_t _ledPinActiveOn = LOW;
|
uint32_t _ledPinActiveOn = LOW;
|
||||||
uint32_t _ledPin = LED_BUILTIN;
|
uint32_t _ledPin = KNX_LED;
|
||||||
uint32_t _buttonPinInterruptOn = RISING;
|
uint32_t _buttonPin = KNX_BUTTON;
|
||||||
uint32_t _buttonPin = 0;
|
|
||||||
SaveCallback _saveCallback = 0;
|
SaveCallback _saveCallback = 0;
|
||||||
RestoreCallback _restoreCallback = 0;
|
RestoreCallback _restoreCallback = 0;
|
||||||
volatile bool _toggleProgMode = false;
|
volatile bool _toggleProgMode = false;
|
||||||
|
@ -1,16 +1,22 @@
|
|||||||
/*-----------------------------------------------------
|
/*-----------------------------------------------------
|
||||||
|
|
||||||
Plattform for Raspberry Pi Pico and other RP2040 boards
|
Plattform for Raspberry Pi Pico and other RP2040 boards
|
||||||
|
by SirSydom <com@sirsydom.de> 2021-2022
|
||||||
|
|
||||||
made to work with arduino-pico - "Raspberry Pi Pico Arduino core, for all RP2040 boards"
|
made to work with arduino-pico - "Raspberry Pi Pico Arduino core, for all RP2040 boards"
|
||||||
by Earl E. Philhower III https://github.com/earlephilhower/arduino-pico V1.11.0
|
by Earl E. Philhower III https://github.com/earlephilhower/arduino-pico V1.11.0
|
||||||
|
|
||||||
by SirSydom <com@sirsydom.de> 2021-2022
|
|
||||||
|
|
||||||
RTTI must be set to enabled in the board options
|
RTTI must be set to enabled in the board options
|
||||||
|
|
||||||
A maximum of 4kB emulated EEPROM is supported.
|
Uses direct flash reading/writing.
|
||||||
For more, use or own emulation (maybe with littlefs)
|
Size ist defined by KNX_FLASH_SIZE (default 4k) - must be a multiple of 4096.
|
||||||
|
Offset in Flash is defined by KNX_FLASH_OFFSET (default 1,5MiB / 0x180000) - must be a multiple of 4096.
|
||||||
|
|
||||||
|
EEPROM Emulation from arduino-pico core (max 4k) can be use by defining USE_RP2040_EEPROM_EMULATION
|
||||||
|
|
||||||
|
A RAM-buffered Flash can be use by defining USE_RP2040_LARGE_EEPROM_EMULATION
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------*/
|
----------------------------------------------------*/
|
||||||
|
|
||||||
@ -25,17 +31,37 @@ For more, use or own emulation (maybe with littlefs)
|
|||||||
#include <EEPROM.h> // EEPROM emulation in flash, part of Earl E Philhowers Pi Pico Arduino support
|
#include <EEPROM.h> // EEPROM emulation in flash, part of Earl E Philhowers Pi Pico Arduino support
|
||||||
#include <pico/unique_id.h> // from Pico SDK
|
#include <pico/unique_id.h> // from Pico SDK
|
||||||
#include <hardware/watchdog.h> // from Pico SDK
|
#include <hardware/watchdog.h> // from Pico SDK
|
||||||
|
#include <hardware/flash.h> // from Pico SDK
|
||||||
|
|
||||||
|
#define FLASHPTR ((uint8_t*)XIP_BASE + KNX_FLASH_OFFSET)
|
||||||
|
|
||||||
|
#if KNX_FLASH_SIZE%4096
|
||||||
|
#error "KNX_FLASH_SIZE must be multiple of 4096"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if KNX_FLASH_OFFSET%4096
|
||||||
|
#error "KNX_FLASH_OFFSET must be multiple of 4096"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef KNX_SERIAL
|
||||||
|
#define KNX_SERIAL Serial1
|
||||||
|
#endif
|
||||||
|
|
||||||
RP2040ArduinoPlatform::RP2040ArduinoPlatform()
|
RP2040ArduinoPlatform::RP2040ArduinoPlatform()
|
||||||
#ifndef KNX_NO_DEFAULT_UART
|
#ifndef KNX_NO_DEFAULT_UART
|
||||||
: ArduinoPlatform(&Serial1)
|
: ArduinoPlatform(&KNX_SERIAL)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
#ifndef USE_RP2040_EEPROM_EMULATION
|
||||||
|
_memoryType = Flash;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
RP2040ArduinoPlatform::RP2040ArduinoPlatform( HardwareSerial* s) : ArduinoPlatform(s)
|
RP2040ArduinoPlatform::RP2040ArduinoPlatform( HardwareSerial* s) : ArduinoPlatform(s)
|
||||||
{
|
{
|
||||||
|
#ifndef USE_RP2040_EEPROM_EMULATION
|
||||||
|
_memoryType = Flash;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void RP2040ArduinoPlatform::setupUart()
|
void RP2040ArduinoPlatform::setupUart()
|
||||||
@ -54,7 +80,14 @@ void RP2040ArduinoPlatform::setupUart()
|
|||||||
uint32_t RP2040ArduinoPlatform::uniqueSerialNumber()
|
uint32_t RP2040ArduinoPlatform::uniqueSerialNumber()
|
||||||
{
|
{
|
||||||
pico_unique_board_id_t id; // 64Bit unique serial number from the QSPI flash
|
pico_unique_board_id_t id; // 64Bit unique serial number from the QSPI flash
|
||||||
pico_get_unique_board_id(&id);
|
|
||||||
|
noInterrupts();
|
||||||
|
rp2040.idleOtherCore();
|
||||||
|
|
||||||
|
flash_get_unique_id(id.id); //pico_get_unique_board_id(&id);
|
||||||
|
|
||||||
|
rp2040.resumeOtherCore();
|
||||||
|
interrupts();
|
||||||
|
|
||||||
// use lower 4 byte and convert to unit32_t
|
// use lower 4 byte and convert to unit32_t
|
||||||
uint32_t uid = ((uint32_t)(id.id[4]) << 24) | ((uint32_t)(id.id[5]) << 16) | ((uint32_t)(id.id[6]) << 8) | (uint32_t)(id.id[7]);
|
uint32_t uid = ((uint32_t)(id.id[4]) << 24) | ((uint32_t)(id.id[5]) << 16) | ((uint32_t)(id.id[6]) << 8) | (uint32_t)(id.id[7]);
|
||||||
@ -68,6 +101,47 @@ void RP2040ArduinoPlatform::restart()
|
|||||||
watchdog_reboot(0,0,0);
|
watchdog_reboot(0,0,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_RP2040_EEPROM_EMULATION
|
||||||
|
|
||||||
|
#pragma warning "Using EEPROM Simulation"
|
||||||
|
|
||||||
|
#ifdef USE_RP2040_LARGE_EEPROM_EMULATION
|
||||||
|
|
||||||
|
uint8_t * RP2040ArduinoPlatform::getEepromBuffer(uint16_t size)
|
||||||
|
{
|
||||||
|
if(size%4096)
|
||||||
|
{
|
||||||
|
println("KNX_FLASH_SIZE must be a multiple of 4096");
|
||||||
|
fatalError();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!_rambuff_initialized)
|
||||||
|
{
|
||||||
|
memcpy(_rambuff, FLASHPTR, KNX_FLASH_SIZE);
|
||||||
|
_rambuff_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _rambuff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RP2040ArduinoPlatform::commitToEeprom()
|
||||||
|
{
|
||||||
|
noInterrupts();
|
||||||
|
rp2040.idleOtherCore();
|
||||||
|
|
||||||
|
//ToDo: write block-by-block to prevent writing of untouched blocks
|
||||||
|
if(memcmp(_rambuff, FLASHPTR, KNX_FLASH_SIZE))
|
||||||
|
{
|
||||||
|
flash_range_erase (KNX_FLASH_OFFSET, KNX_FLASH_SIZE);
|
||||||
|
flash_range_program(KNX_FLASH_OFFSET, _rambuff, KNX_FLASH_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
rp2040.resumeOtherCore();
|
||||||
|
interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
uint8_t * RP2040ArduinoPlatform::getEepromBuffer(uint16_t size)
|
uint8_t * RP2040ArduinoPlatform::getEepromBuffer(uint16_t size)
|
||||||
{
|
{
|
||||||
if(size > 4096)
|
if(size > 4096)
|
||||||
@ -91,6 +165,73 @@ void RP2040ArduinoPlatform::commitToEeprom()
|
|||||||
{
|
{
|
||||||
EEPROM.commit();
|
EEPROM.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
size_t RP2040ArduinoPlatform::flashEraseBlockSize()
|
||||||
|
{
|
||||||
|
return 16; // 16 pages x 256byte/page = 4096byte
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t RP2040ArduinoPlatform::flashPageSize()
|
||||||
|
{
|
||||||
|
return 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* RP2040ArduinoPlatform::userFlashStart()
|
||||||
|
{
|
||||||
|
return (uint8_t*)XIP_BASE + KNX_FLASH_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t RP2040ArduinoPlatform::userFlashSizeEraseBlocks()
|
||||||
|
{
|
||||||
|
if(KNX_FLASH_SIZE <= 0)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return ( (KNX_FLASH_SIZE - 1) / (flashPageSize() * flashEraseBlockSize())) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RP2040ArduinoPlatform::flashErase(uint16_t eraseBlockNum)
|
||||||
|
{
|
||||||
|
noInterrupts();
|
||||||
|
rp2040.idleOtherCore();
|
||||||
|
|
||||||
|
flash_range_erase (KNX_FLASH_OFFSET + eraseBlockNum * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize());
|
||||||
|
|
||||||
|
rp2040.resumeOtherCore();
|
||||||
|
interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RP2040ArduinoPlatform::flashWritePage(uint16_t pageNumber, uint8_t* data)
|
||||||
|
{
|
||||||
|
noInterrupts();
|
||||||
|
rp2040.idleOtherCore();
|
||||||
|
|
||||||
|
flash_range_program(KNX_FLASH_OFFSET + pageNumber * flashPageSize(), data, flashPageSize());
|
||||||
|
|
||||||
|
rp2040.resumeOtherCore();
|
||||||
|
interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RP2040ArduinoPlatform::writeBufferedEraseBlock()
|
||||||
|
{
|
||||||
|
if(_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty)
|
||||||
|
{
|
||||||
|
noInterrupts();
|
||||||
|
rp2040.idleOtherCore();
|
||||||
|
|
||||||
|
flash_range_erase (KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize());
|
||||||
|
flash_range_program(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), _eraseblockBuffer, flashPageSize() * flashEraseBlockSize());
|
||||||
|
|
||||||
|
rp2040.resumeOtherCore();
|
||||||
|
interrupts();
|
||||||
|
|
||||||
|
_bufferedEraseblockDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,6 +4,16 @@
|
|||||||
|
|
||||||
#ifdef ARDUINO_ARCH_RP2040
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
|
||||||
|
#ifndef KNX_FLASH_OFFSET
|
||||||
|
#define KNX_FLASH_OFFSET 0x180000 // 1.5MiB
|
||||||
|
#pragma warning "KNX_FLASH_OFFSET not defined, using 0x180000"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_RP2040_LARGE_EEPROM_EMULATION
|
||||||
|
#define USE_RP2040_EEPROM_EMULATION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
class RP2040ArduinoPlatform : public ArduinoPlatform
|
class RP2040ArduinoPlatform : public ArduinoPlatform
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -13,11 +23,36 @@ public:
|
|||||||
void setupUart();
|
void setupUart();
|
||||||
|
|
||||||
// unique serial number
|
// unique serial number
|
||||||
uint32_t uniqueSerialNumber() override;
|
uint32_t uniqueSerialNumber() override;
|
||||||
|
|
||||||
void restart();
|
void restart();
|
||||||
|
|
||||||
|
#ifdef USE_RP2040_EEPROM_EMULATION
|
||||||
uint8_t* getEepromBuffer(uint16_t size);
|
uint8_t* getEepromBuffer(uint16_t size);
|
||||||
void commitToEeprom();
|
void commitToEeprom();
|
||||||
|
|
||||||
|
#ifdef USE_RP2040_LARGE_EEPROM_EMULATION
|
||||||
|
uint8_t _rambuff[KNX_FLASH_SIZE];
|
||||||
|
bool _rambuff_initialized = false;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
|
||||||
|
// size of one EraseBlock in pages
|
||||||
|
virtual size_t flashEraseBlockSize();
|
||||||
|
// size of one flash page in bytes
|
||||||
|
virtual size_t flashPageSize();
|
||||||
|
// start of user flash aligned to start of an erase block
|
||||||
|
virtual uint8_t* userFlashStart();
|
||||||
|
// size of the user flash in EraseBlocks
|
||||||
|
virtual size_t userFlashSizeEraseBlocks();
|
||||||
|
//relativ to userFlashStart
|
||||||
|
virtual void flashErase(uint16_t eraseBlockNum);
|
||||||
|
//write a single page to flash (pageNumber relative to userFashStart
|
||||||
|
virtual void flashWritePage(uint16_t pageNumber, uint8_t* data);
|
||||||
|
|
||||||
|
// writes _eraseblockBuffer to flash - overrides Plattform::writeBufferedEraseBlock() for performance optimization only
|
||||||
|
void writeBufferedEraseBlock();
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,17 +4,33 @@
|
|||||||
#include <knx/bits.h>
|
#include <knx/bits.h>
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#ifdef USE_SAMD_EEPROM_EMULATION
|
||||||
#include <FlashAsEEPROM.h>
|
#include <FlashAsEEPROM.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if KNX_FLASH_SIZE % 1024
|
||||||
|
#error "KNX_FLASH_SIZE must be multiple of 1024"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef KNX_SERIAL
|
||||||
|
#define KNX_SERIAL Serial1
|
||||||
|
#endif
|
||||||
|
|
||||||
SamdPlatform::SamdPlatform()
|
SamdPlatform::SamdPlatform()
|
||||||
#ifndef KNX_NO_DEFAULT_UART
|
#ifndef KNX_NO_DEFAULT_UART
|
||||||
: ArduinoPlatform(&Serial1)
|
: ArduinoPlatform(&KNX_SERIAL)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
#ifndef USE_SAMD_EEPROM_EMULATION
|
||||||
|
init();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
SamdPlatform::SamdPlatform( HardwareSerial* s) : ArduinoPlatform(s)
|
SamdPlatform::SamdPlatform( HardwareSerial* s) : ArduinoPlatform(s)
|
||||||
{
|
{
|
||||||
|
#ifndef USE_SAMD_EEPROM_EMULATION
|
||||||
|
init();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t SamdPlatform::uniqueSerialNumber()
|
uint32_t SamdPlatform::uniqueSerialNumber()
|
||||||
@ -43,7 +59,9 @@ void SamdPlatform::restart()
|
|||||||
NVIC_SystemReset();
|
NVIC_SystemReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t * SamdPlatform::getEepromBuffer(uint16_t size)
|
#ifdef USE_SAMD_EEPROM_EMULATION
|
||||||
|
#pragma warning "Using EEPROM Simulation"
|
||||||
|
uint8_t* SamdPlatform::getEepromBuffer(uint16_t size)
|
||||||
{
|
{
|
||||||
//EEPROM.begin(size);
|
//EEPROM.begin(size);
|
||||||
if(size > EEPROM_EMULATION_SIZE)
|
if(size > EEPROM_EMULATION_SIZE)
|
||||||
@ -56,6 +74,156 @@ void SamdPlatform::commitToEeprom()
|
|||||||
{
|
{
|
||||||
EEPROM.commit();
|
EEPROM.commit();
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
extern uint32_t __etext;
|
||||||
|
extern uint32_t __data_start__;
|
||||||
|
extern uint32_t __data_end__;
|
||||||
|
|
||||||
|
static const uint32_t pageSizes[] = {8, 16, 32, 64, 128, 256, 512, 1024};
|
||||||
|
|
||||||
|
void SamdPlatform::init()
|
||||||
|
{
|
||||||
|
_memoryType = Flash;
|
||||||
|
_pageSize = pageSizes[NVMCTRL->PARAM.bit.PSZ];
|
||||||
|
_pageCnt = NVMCTRL->PARAM.bit.NVMP;
|
||||||
|
_rowSize = PAGES_PER_ROW * _pageSize;
|
||||||
|
|
||||||
|
// find end of program flash and set limit to next row
|
||||||
|
uint32_t endEddr = (uint32_t)(&__etext + (&__data_end__ - &__data_start__)); // text + data MemoryBlock
|
||||||
|
_MemoryStart = getRowAddr(_pageSize * _pageCnt - KNX_FLASH_SIZE - 1); // 23295
|
||||||
|
_MemoryEnd = getRowAddr(_pageSize * _pageCnt - 1);
|
||||||
|
// chosen flash size is not available anymore
|
||||||
|
if (_MemoryStart < endEddr) {
|
||||||
|
println("KNX_FLASH_SIZE is not available (possible too much flash use by firmware)");
|
||||||
|
fatalError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SamdPlatform::flashEraseBlockSize()
|
||||||
|
{
|
||||||
|
return PAGES_PER_ROW;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SamdPlatform::flashPageSize()
|
||||||
|
{
|
||||||
|
return _pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* SamdPlatform::userFlashStart()
|
||||||
|
{
|
||||||
|
return (uint8_t*)_MemoryStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SamdPlatform::userFlashSizeEraseBlocks()
|
||||||
|
{
|
||||||
|
if (KNX_FLASH_SIZE <= 0)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return ((KNX_FLASH_SIZE - 1) / (flashPageSize() * flashEraseBlockSize())) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SamdPlatform::flashErase(uint16_t eraseBlockNum)
|
||||||
|
{
|
||||||
|
noInterrupts();
|
||||||
|
|
||||||
|
eraseRow((void *)(_MemoryStart + eraseBlockNum * _rowSize));
|
||||||
|
// flash_range_erase(KNX_FLASH_OFFSET + eraseBlockNum * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize());
|
||||||
|
|
||||||
|
interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SamdPlatform::flashWritePage(uint16_t pageNumber, uint8_t* data)
|
||||||
|
{
|
||||||
|
noInterrupts();
|
||||||
|
|
||||||
|
write((void *)(_MemoryStart + pageNumber * _pageSize), data, _pageSize);
|
||||||
|
// flash_range_program(KNX_FLASH_OFFSET + pageNumber * flashPageSize(), data, flashPageSize());
|
||||||
|
|
||||||
|
interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SamdPlatform::writeBufferedEraseBlock()
|
||||||
|
{
|
||||||
|
if (_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty)
|
||||||
|
{
|
||||||
|
noInterrupts();
|
||||||
|
|
||||||
|
eraseRow((void *)(_MemoryStart + _bufferedEraseblockNumber * _rowSize));
|
||||||
|
write((void *)(_MemoryStart + _bufferedEraseblockNumber * _rowSize), _eraseblockBuffer, _rowSize);
|
||||||
|
// flash_range_erase(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize());
|
||||||
|
// flash_range_program(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), _eraseblockBuffer, flashPageSize() * flashEraseBlockSize());
|
||||||
|
|
||||||
|
interrupts();
|
||||||
|
|
||||||
|
_bufferedEraseblockDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SamdPlatform::getRowAddr(uint32_t flasAddr)
|
||||||
|
{
|
||||||
|
return flasAddr & ~(_rowSize - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SamdPlatform::write(const volatile void *flash_ptr, const void *data, uint32_t size)
|
||||||
|
{
|
||||||
|
// Calculate data boundaries
|
||||||
|
size = (size + 3) / 4;
|
||||||
|
volatile uint32_t *src_addr = (volatile uint32_t *)data;
|
||||||
|
volatile uint32_t *dst_addr = (volatile uint32_t *)flash_ptr;
|
||||||
|
// volatile uint32_t *dst_addr = (volatile uint32_t *)flash_ptr;
|
||||||
|
// const uint8_t *src_addr = (uint8_t *)data;
|
||||||
|
|
||||||
|
// Disable automatic page write
|
||||||
|
NVMCTRL->CTRLB.bit.MANW = 1;
|
||||||
|
|
||||||
|
// Do writes in pages
|
||||||
|
while (size)
|
||||||
|
{
|
||||||
|
// Execute "PBC" Page Buffer Clear
|
||||||
|
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC;
|
||||||
|
while (NVMCTRL->INTFLAG.bit.READY == 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill page buffer
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < (_pageSize / 4) && size; i++)
|
||||||
|
{
|
||||||
|
*dst_addr = *src_addr;
|
||||||
|
src_addr++;
|
||||||
|
dst_addr++;
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute "WP" Write Page
|
||||||
|
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP;
|
||||||
|
while (NVMCTRL->INTFLAG.bit.READY == 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SamdPlatform::erase(const volatile void *flash_ptr, uint32_t size)
|
||||||
|
{
|
||||||
|
const uint8_t *ptr = (const uint8_t *)flash_ptr;
|
||||||
|
while (size > _rowSize)
|
||||||
|
{
|
||||||
|
eraseRow(ptr);
|
||||||
|
ptr += _rowSize;
|
||||||
|
size -= _rowSize;
|
||||||
|
}
|
||||||
|
eraseRow(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SamdPlatform::eraseRow(const volatile void *flash_ptr)
|
||||||
|
{
|
||||||
|
NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr) / 2;
|
||||||
|
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER;
|
||||||
|
while (!NVMCTRL->INTFLAG.bit.READY)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#ifdef ARDUINO_ARCH_SAMD
|
#ifdef ARDUINO_ARCH_SAMD
|
||||||
|
|
||||||
|
#define PAGES_PER_ROW 4
|
||||||
|
|
||||||
class SamdPlatform : public ArduinoPlatform
|
class SamdPlatform : public ArduinoPlatform
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -14,8 +16,40 @@ public:
|
|||||||
uint32_t uniqueSerialNumber() override;
|
uint32_t uniqueSerialNumber() override;
|
||||||
|
|
||||||
void restart();
|
void restart();
|
||||||
|
#ifdef USE_SAMD_EEPROM_EMULATION
|
||||||
uint8_t* getEepromBuffer(uint16_t size);
|
uint8_t* getEepromBuffer(uint16_t size);
|
||||||
void commitToEeprom();
|
void commitToEeprom();
|
||||||
|
#else
|
||||||
|
// size of one EraseBlock in pages
|
||||||
|
virtual size_t flashEraseBlockSize();
|
||||||
|
// size of one flash page in bytes
|
||||||
|
virtual size_t flashPageSize();
|
||||||
|
// start of user flash aligned to start of an erase block
|
||||||
|
virtual uint8_t* userFlashStart();
|
||||||
|
// size of the user flash in EraseBlocks
|
||||||
|
virtual size_t userFlashSizeEraseBlocks();
|
||||||
|
// relativ to userFlashStart
|
||||||
|
virtual void flashErase(uint16_t eraseBlockNum);
|
||||||
|
// write a single page to flash (pageNumber relative to userFashStart
|
||||||
|
virtual void flashWritePage(uint16_t pageNumber, uint8_t* data);
|
||||||
|
|
||||||
|
// writes _eraseblockBuffer to flash - overrides Plattform::writeBufferedEraseBlock() for performance optimization only
|
||||||
|
void writeBufferedEraseBlock();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init();
|
||||||
|
uint32_t _MemoryEnd = 0;
|
||||||
|
uint32_t _MemoryStart = 0;
|
||||||
|
uint32_t _pageSize;
|
||||||
|
uint32_t _rowSize;
|
||||||
|
uint32_t _pageCnt;
|
||||||
|
|
||||||
|
uint32_t getRowAddr(uint32_t flasAddr);
|
||||||
|
void write(const volatile void* flash_ptr, const void* data, uint32_t size);
|
||||||
|
void erase(const volatile void* flash_ptr, uint32_t size);
|
||||||
|
void eraseRow(const volatile void* flash_ptr);
|
||||||
|
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,9 +4,13 @@
|
|||||||
#include <EEPROM.h>
|
#include <EEPROM.h>
|
||||||
#include "knx/bits.h"
|
#include "knx/bits.h"
|
||||||
|
|
||||||
|
#ifndef KNX_SERIAL
|
||||||
|
#define KNX_SERIAL Serial2
|
||||||
|
#endif
|
||||||
|
|
||||||
Stm32Platform::Stm32Platform()
|
Stm32Platform::Stm32Platform()
|
||||||
#ifndef KNX_NO_DEFAULT_UART
|
#ifndef KNX_NO_DEFAULT_UART
|
||||||
: ArduinoPlatform(&Serial2)
|
: ArduinoPlatform(&KNX_SERIAL)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -32,16 +36,21 @@ void Stm32Platform::restart()
|
|||||||
|
|
||||||
uint8_t * Stm32Platform::getEepromBuffer(uint16_t size)
|
uint8_t * Stm32Platform::getEepromBuffer(uint16_t size)
|
||||||
{
|
{
|
||||||
if (size > E2END + 1)
|
// check if the buffer already exists
|
||||||
|
if (_eepromPtr == nullptr) // we need to initialize the buffer first
|
||||||
{
|
{
|
||||||
fatalError();
|
if (size > E2END + 1)
|
||||||
|
{
|
||||||
|
fatalError();
|
||||||
|
}
|
||||||
|
|
||||||
|
_eepromSize = size;
|
||||||
|
_eepromPtr = new uint8_t[size];
|
||||||
|
eeprom_buffer_fill();
|
||||||
|
for (uint16_t i = 0; i < size; ++i)
|
||||||
|
_eepromPtr[i] = eeprom_buffered_read_byte(i);
|
||||||
}
|
}
|
||||||
_eepromSize = size;
|
|
||||||
delete [] _eepromPtr;
|
|
||||||
_eepromPtr = new uint8_t[size];
|
|
||||||
eeprom_buffer_fill();
|
|
||||||
for (uint16_t i = 0; i < size; ++i)
|
|
||||||
_eepromPtr[i] = eeprom_buffered_read_byte(i);
|
|
||||||
return _eepromPtr;
|
return _eepromPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,6 +60,11 @@ void Stm32Platform::commitToEeprom()
|
|||||||
return;
|
return;
|
||||||
for (uint16_t i = 0; i < _eepromSize; ++i)
|
for (uint16_t i = 0; i < _eepromSize; ++i)
|
||||||
eeprom_buffered_write_byte(i, _eepromPtr[i]);
|
eeprom_buffered_write_byte(i, _eepromPtr[i]);
|
||||||
|
// For some GD32 chips, the flash needs to be unlocked twice
|
||||||
|
// and the first call will fail. If the first call is
|
||||||
|
// successful, the second one (inside eeprom_buffer_flush)
|
||||||
|
// does nothing.
|
||||||
|
HAL_FLASH_Unlock();
|
||||||
eeprom_buffer_flush();
|
eeprom_buffer_flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user