mirror of
				https://github.com/thelsing/knx.git
				synced 2025-10-26 10:26:25 +01: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