First Try
This commit is contained in:
parent
efde86778b
commit
53e123dc8a
@ -3,6 +3,14 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
|
||||||
# idf_build_set_property(MINIMAL_BUILD ON)
|
add_definitions(
|
||||||
|
-Wno-unknown-pragmas
|
||||||
|
-DMASK_VERSION=0x07B0
|
||||||
|
-DKNX_NO_AUTOMATIC_GLOBAL_INSTANCE
|
||||||
|
-DKNX_FLASH_SIZE=4096
|
||||||
|
#-DKNX_NO_PRINT
|
||||||
|
#-Wno-stringop-truncation
|
||||||
|
)
|
||||||
|
|
||||||
project(knxdisplay)
|
project(knxdisplay)
|
||||||
|
|||||||
11
components/knx/CMakeLists.txt
Normal file
11
components/knx/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Define the directory containing your source files
|
||||||
|
set(SOURCE_DIR "./src")
|
||||||
|
set(SOURCE_DIR_1 "./src/knx")
|
||||||
|
|
||||||
|
# Use file(GLOB) to find all .cpp files in the 'src' directory
|
||||||
|
file(GLOB SOURCE_FILES "${SOURCE_DIR}/*.cpp")
|
||||||
|
file(GLOB SOURCE_FILES_1 "${SOURCE_DIR_1}/*.cpp")
|
||||||
|
|
||||||
|
idf_component_register(SRCS ${SOURCE_FILES} ${SOURCE_FILES_1}
|
||||||
|
INCLUDE_DIRS "./src" "./src/knx"
|
||||||
|
REQUIRES esp_netif driver esp_timer esp_wifi freertos nvs_flash esp_system)
|
||||||
315
components/knx/src/arduino_platform.cpp
Normal file
315
components/knx/src/arduino_platform.cpp
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
#ifdef ARDUINO
|
||||||
|
|
||||||
|
#include "arduino_platform.h"
|
||||||
|
#include "knx/bits.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#ifndef KNX_NO_SPI
|
||||||
|
#include <SPI.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef KNX_NO_PRINT
|
||||||
|
Stream* ArduinoPlatform::SerialDebug = &KNX_DEBUG_SERIAL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ArduinoPlatform::ArduinoPlatform() : _knxSerial(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ArduinoPlatform::ArduinoPlatform(HardwareSerial* knxSerial) : _knxSerial(knxSerial)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArduinoPlatform::fatalError()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
#ifdef KNX_LED
|
||||||
|
static const long LED_BLINK_PERIOD = 200;
|
||||||
|
|
||||||
|
if ((millis() % LED_BLINK_PERIOD) > (LED_BLINK_PERIOD / 2))
|
||||||
|
digitalWrite(KNX_LED, HIGH);
|
||||||
|
else
|
||||||
|
digitalWrite(KNX_LED, LOW);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArduinoPlatform::knxUart( HardwareSerial* serial )
|
||||||
|
{
|
||||||
|
if (_knxSerial)
|
||||||
|
closeUart();
|
||||||
|
|
||||||
|
_knxSerial = serial;
|
||||||
|
setupUart();
|
||||||
|
}
|
||||||
|
|
||||||
|
HardwareSerial* ArduinoPlatform::knxUart()
|
||||||
|
{
|
||||||
|
return _knxSerial;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArduinoPlatform::setupUart()
|
||||||
|
{
|
||||||
|
_knxSerial->begin(19200, SERIAL_8E1);
|
||||||
|
|
||||||
|
while (!_knxSerial)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ArduinoPlatform::closeUart()
|
||||||
|
{
|
||||||
|
_knxSerial->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ArduinoPlatform::uartAvailable()
|
||||||
|
{
|
||||||
|
return _knxSerial->available();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t ArduinoPlatform::writeUart(const uint8_t data)
|
||||||
|
{
|
||||||
|
//printHex("<p", &data, 1);
|
||||||
|
return _knxSerial->write(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t ArduinoPlatform::writeUart(const uint8_t* buffer, size_t size)
|
||||||
|
{
|
||||||
|
//printHex("<p", buffer, size);
|
||||||
|
return _knxSerial->write(buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ArduinoPlatform::readUart()
|
||||||
|
{
|
||||||
|
int val = _knxSerial->read();
|
||||||
|
//if(val > 0)
|
||||||
|
// printHex("p>", (uint8_t*)&val, 1);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t ArduinoPlatform::readBytesUart(uint8_t* buffer, size_t length)
|
||||||
|
{
|
||||||
|
size_t toRead = length;
|
||||||
|
uint8_t* pos = buffer;
|
||||||
|
|
||||||
|
while (toRead > 0)
|
||||||
|
{
|
||||||
|
size_t val = _knxSerial->readBytes(pos, toRead);
|
||||||
|
pos += val;
|
||||||
|
toRead -= val;
|
||||||
|
}
|
||||||
|
|
||||||
|
//printHex("p>", buffer, length);
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArduinoPlatform::flushUart()
|
||||||
|
{
|
||||||
|
return _knxSerial->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef KNX_NO_SPI
|
||||||
|
void ArduinoPlatform::setupSpi()
|
||||||
|
{
|
||||||
|
SPI.begin();
|
||||||
|
SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArduinoPlatform::closeSpi()
|
||||||
|
{
|
||||||
|
SPI.endTransaction();
|
||||||
|
SPI.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ArduinoPlatform::readWriteSpi(uint8_t* data, size_t len)
|
||||||
|
{
|
||||||
|
SPI.transfer(data, len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef KNX_NO_PRINT
|
||||||
|
void printUint64(uint64_t value, int base = DEC)
|
||||||
|
{
|
||||||
|
char buf[8 * sizeof(uint64_t) + 1];
|
||||||
|
char* str = &buf[sizeof(buf) - 1];
|
||||||
|
*str = '\0';
|
||||||
|
|
||||||
|
uint64_t n = value;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
char c = n % base;
|
||||||
|
n /= base;
|
||||||
|
|
||||||
|
*--str = c < 10 ? c + '0' : c + 'A' - 10;
|
||||||
|
} while (n > 0);
|
||||||
|
|
||||||
|
print(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(const char* s)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->print(s);
|
||||||
|
}
|
||||||
|
void print(char c)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->print(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(unsigned char num)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->print(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(unsigned char num, int base)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->print(num, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(int num)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->print(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(int num, int base)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->print(num, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(unsigned int num)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->print(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(unsigned int num, int base)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->print(num, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(long num)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->print(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(long num, int base)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->print(num, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(unsigned long num)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->print(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(unsigned long num, int base)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->print(num, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(unsigned long long num)
|
||||||
|
{
|
||||||
|
printUint64(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(unsigned long long num, int base)
|
||||||
|
{
|
||||||
|
printUint64(num, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(double num)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->print(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(const char* s)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->println(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(char c)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->println(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(unsigned char num)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->println(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(unsigned char num, int base)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->println(num, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(int num)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->println(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(int num, int base)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->println(num, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(unsigned int num)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->println(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(unsigned int num, int base)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->println(num, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(long num)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->println(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(long num, int base)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->println(num, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(unsigned long num)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->println(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(unsigned long num, int base)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->println(num, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(unsigned long long num)
|
||||||
|
{
|
||||||
|
printUint64(num);
|
||||||
|
println("");
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(unsigned long long num, int base)
|
||||||
|
{
|
||||||
|
printUint64(num, base);
|
||||||
|
println("");
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(double num)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->println(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(void)
|
||||||
|
{
|
||||||
|
ArduinoPlatform::SerialDebug->println();
|
||||||
|
}
|
||||||
|
#endif // KNX_NO_PRINT
|
||||||
|
|
||||||
|
#endif // ARDUINO
|
||||||
47
components/knx/src/arduino_platform.h
Normal file
47
components/knx/src/arduino_platform.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef ARDUINO
|
||||||
|
|
||||||
|
#include "knx/platform.h"
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
#ifndef KNX_DEBUG_SERIAL
|
||||||
|
#define KNX_DEBUG_SERIAL Serial
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class ArduinoPlatform : public Platform
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ArduinoPlatform();
|
||||||
|
ArduinoPlatform(HardwareSerial* knxSerial);
|
||||||
|
|
||||||
|
// basic stuff
|
||||||
|
void fatalError();
|
||||||
|
|
||||||
|
//uart
|
||||||
|
virtual void knxUart( HardwareSerial* serial);
|
||||||
|
virtual HardwareSerial* knxUart();
|
||||||
|
virtual void setupUart();
|
||||||
|
virtual void closeUart();
|
||||||
|
virtual int uartAvailable();
|
||||||
|
virtual size_t writeUart(const uint8_t data);
|
||||||
|
virtual size_t writeUart(const uint8_t* buffer, size_t size);
|
||||||
|
virtual int readUart();
|
||||||
|
virtual size_t readBytesUart(uint8_t* buffer, size_t length);
|
||||||
|
virtual void flushUart();
|
||||||
|
|
||||||
|
//spi
|
||||||
|
#ifndef KNX_NO_SPI
|
||||||
|
void setupSpi() override;
|
||||||
|
void closeSpi() override;
|
||||||
|
int readWriteSpi (uint8_t* data, size_t len) override;
|
||||||
|
#endif
|
||||||
|
#ifndef KNX_NO_PRINT
|
||||||
|
static Stream* SerialDebug;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
HardwareSerial* _knxSerial;
|
||||||
|
};
|
||||||
|
#endif // ARDUINO
|
||||||
587
components/knx/src/cc1310_platform.cpp
Normal file
587
components/knx/src/cc1310_platform.cpp
Normal file
@ -0,0 +1,587 @@
|
|||||||
|
#ifdef DeviceFamily_CC13X0
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include <ti/devices/DeviceFamily.h>
|
||||||
|
#include DeviceFamily_constructPath(driverlib/sys_ctrl.h)
|
||||||
|
#include <ti/drivers/GPIO.h>
|
||||||
|
|
||||||
|
#include "SEGGER_RTT.h"
|
||||||
|
|
||||||
|
#include "Board.h"
|
||||||
|
|
||||||
|
#include "knx/bits.h"
|
||||||
|
#include "cc1310_platform.h"
|
||||||
|
|
||||||
|
//#define printf(args...) (SEGGER_RTT_printf(0, args))
|
||||||
|
//#define PRINT_RTT
|
||||||
|
#define PRINT_UART
|
||||||
|
|
||||||
|
static uint8_t serialNumber[6];
|
||||||
|
// KNX_FLASH_SIZE shall be defined in CMakeLists.txt for example. It is also used in class Memory in memory.cpp
|
||||||
|
static uint8_t NVS_buffer[KNX_FLASH_SIZE];
|
||||||
|
|
||||||
|
static UART_Handle uart;
|
||||||
|
|
||||||
|
static NVS_Handle nvsHandle;
|
||||||
|
|
||||||
|
static ClockP_Handle clk0Handle;
|
||||||
|
static ClockP_Struct clk0Struct;
|
||||||
|
static volatile uint32_t msCounter = 0;
|
||||||
|
|
||||||
|
static void clk0Fxn(uintptr_t arg0)
|
||||||
|
{
|
||||||
|
msCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setupClock()
|
||||||
|
{
|
||||||
|
ClockP_Params clkParams;
|
||||||
|
ClockP_Params_init(&clkParams);
|
||||||
|
clkParams.period = 1000 / ClockP_tickPeriod;
|
||||||
|
clkParams.startFlag = true;
|
||||||
|
ClockP_construct(&clk0Struct, (ClockP_Fxn)clk0Fxn, 1000 / ClockP_tickPeriod, &clkParams);
|
||||||
|
clk0Handle = ClockP_handle(&clk0Struct);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setupGPIO()
|
||||||
|
{
|
||||||
|
/* Configure the LED and button pins */
|
||||||
|
GPIO_setConfig(Board_GPIO_LED0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
|
||||||
|
GPIO_setConfig(Board_GPIO_LED1, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
|
||||||
|
GPIO_setConfig(Board_GPIO_BUTTON0, GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING);
|
||||||
|
GPIO_setConfig(Board_GPIO_BUTTON1, GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setupUART()
|
||||||
|
{
|
||||||
|
UART_Params uartParams;
|
||||||
|
UART_Params_init(&uartParams);
|
||||||
|
uartParams.writeDataMode = UART_DATA_BINARY;
|
||||||
|
uartParams.readDataMode = UART_DATA_BINARY;
|
||||||
|
uartParams.readReturnMode = UART_RETURN_FULL;
|
||||||
|
uartParams.readEcho = UART_ECHO_OFF;
|
||||||
|
uartParams.baudRate = 115200;
|
||||||
|
uart = UART_open(Board_UART0, &uartParams);
|
||||||
|
|
||||||
|
if (uart == NULL)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setupNVS()
|
||||||
|
{
|
||||||
|
NVS_Params nvsParams;
|
||||||
|
NVS_Params_init(&nvsParams);
|
||||||
|
nvsHandle = NVS_open(Board_NVSINTERNAL, &nvsParams);
|
||||||
|
|
||||||
|
if (nvsHandle == NULL)
|
||||||
|
{
|
||||||
|
println("NVS_open() failed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NVS_Attrs attrs;
|
||||||
|
NVS_getAttrs(nvsHandle, &attrs);
|
||||||
|
print("NVS flash size: ");
|
||||||
|
println((int)attrs.regionSize);
|
||||||
|
print("NVS flash sector size: ");
|
||||||
|
println((int)attrs.sectorSize);
|
||||||
|
|
||||||
|
if (GPIO_read(Board_GPIO_BUTTON1) == 0)
|
||||||
|
{
|
||||||
|
println("Button1 is pressed. Erasing flash...");
|
||||||
|
int_fast16_t result = NVS_erase(nvsHandle, 0, attrs.regionSize);
|
||||||
|
|
||||||
|
if (result != NVS_STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
print("Error erasing NVS, result: ");
|
||||||
|
println(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
println("NVS successfully erased.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sleep(uint32_t sec)
|
||||||
|
{
|
||||||
|
ClockP_sleep(sec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usleep(uint32_t usec)
|
||||||
|
{
|
||||||
|
ClockP_usleep(usec);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t millis()
|
||||||
|
{
|
||||||
|
// we use our own ms clock because the Os tick counter has counts 10us ticks and following calculation would not wrap correctly at 32bit boundary
|
||||||
|
//return Clock_getTicks() * (uint64_t) Clock_tickPeriod / 1000; // rtos
|
||||||
|
//return ClockP_getTicks( * (uint64_t) Clock_tickPeriod / 1000); //nortos
|
||||||
|
return msCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void delay(uint32_t ms)
|
||||||
|
{
|
||||||
|
ClockP_usleep(ms * 1000);
|
||||||
|
//sleep(ms * (1000 / ClockP_tickPeriod)); //rtos
|
||||||
|
//sleepTicks(millis * 1000ULL / ClockP_tickPeriod); //nortos
|
||||||
|
}
|
||||||
|
|
||||||
|
void delayMicroseconds (unsigned int howLong)
|
||||||
|
{
|
||||||
|
ClockP_usleep(howLong);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef KNX_NO_PRINT
|
||||||
|
size_t write(uint8_t c)
|
||||||
|
{
|
||||||
|
#if defined(PRINT_UART)
|
||||||
|
uint8_t buffer[1] = {c};
|
||||||
|
return UART_write(uart, buffer, sizeof(buffer));
|
||||||
|
#elif defined (PRINT_RTT)
|
||||||
|
return SEGGER_RTT_PutChar(0, (char)c);
|
||||||
|
#else
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
size_t write(const uint8_t* buffer, size_t size)
|
||||||
|
{
|
||||||
|
size_t n = 0;
|
||||||
|
|
||||||
|
while (size--)
|
||||||
|
{
|
||||||
|
if (write(*buffer++))
|
||||||
|
{
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
size_t write(const uint8_t* buffer, size_t size)
|
||||||
|
{
|
||||||
|
#if defined(PRINT_UART)
|
||||||
|
return UART_write(uart, buffer, size);
|
||||||
|
#elif defined (PRINT_RTT)
|
||||||
|
return SEGGER_RTT_Write(0, buffer, size);
|
||||||
|
#else
|
||||||
|
return size;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t write(const char* buffer, size_t size)
|
||||||
|
{
|
||||||
|
return write((const uint8_t*)buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(const char* s)
|
||||||
|
{
|
||||||
|
if (s == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
write(s, strlen(s));
|
||||||
|
}
|
||||||
|
void print(char c)
|
||||||
|
{
|
||||||
|
write(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printUint64(uint64_t value, int base = DEC)
|
||||||
|
{
|
||||||
|
char buf[8 * sizeof(uint64_t) + 1];
|
||||||
|
char* str = &buf[sizeof(buf) - 1];
|
||||||
|
*str = '\0';
|
||||||
|
|
||||||
|
uint64_t n = value;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
char c = n % base;
|
||||||
|
n /= base;
|
||||||
|
|
||||||
|
*--str = c < 10 ? c + '0' : c + 'A' - 10;
|
||||||
|
} while (n > 0);
|
||||||
|
|
||||||
|
print(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(long long num, int base)
|
||||||
|
{
|
||||||
|
if (base == 0)
|
||||||
|
{
|
||||||
|
write(num);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (base == 10)
|
||||||
|
{
|
||||||
|
if (num < 0)
|
||||||
|
{
|
||||||
|
print('-');
|
||||||
|
num = -num;
|
||||||
|
printUint64(num, 10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printUint64(num, 10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printUint64(num, base);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(unsigned long long num, int base)
|
||||||
|
{
|
||||||
|
if (base == 0)
|
||||||
|
{
|
||||||
|
write(num);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printUint64(num, base);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(unsigned char num, int base)
|
||||||
|
{
|
||||||
|
print((unsigned long long)num, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(int num, int base)
|
||||||
|
{
|
||||||
|
print((long long)num, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(unsigned int num, int base)
|
||||||
|
{
|
||||||
|
print((unsigned long long)num, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(long num, int base)
|
||||||
|
{
|
||||||
|
print((long long)num, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(unsigned long num, int base)
|
||||||
|
{
|
||||||
|
print((unsigned long long)num, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printFloat(double number, uint8_t digits)
|
||||||
|
{
|
||||||
|
if (std::isnan(number))
|
||||||
|
{
|
||||||
|
print("nan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::isinf(number))
|
||||||
|
{
|
||||||
|
print("inf");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (number > 4294967040.0)
|
||||||
|
{
|
||||||
|
print("ovf"); // constant determined empirically
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (number < -4294967040.0)
|
||||||
|
{
|
||||||
|
print("ovf"); // constant determined empirically
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle negative numbers
|
||||||
|
if (number < 0.0)
|
||||||
|
{
|
||||||
|
print('-');
|
||||||
|
number = -number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||||
|
double rounding = 0.5;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < digits; ++i)
|
||||||
|
rounding /= 10.0;
|
||||||
|
|
||||||
|
number += rounding;
|
||||||
|
|
||||||
|
// Extract the integer part of the number and print it
|
||||||
|
unsigned long int_part = (unsigned long)number;
|
||||||
|
double remainder = number - (double)int_part;
|
||||||
|
printUint64(int_part);
|
||||||
|
|
||||||
|
// Print the decimal point, but only if there are digits beyond
|
||||||
|
if (digits > 0)
|
||||||
|
{
|
||||||
|
print('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract digits from the remainder one at a time
|
||||||
|
while (digits-- > 0)
|
||||||
|
{
|
||||||
|
remainder *= 10.0;
|
||||||
|
unsigned int toPrint = (unsigned int)(remainder);
|
||||||
|
printUint64(toPrint);
|
||||||
|
remainder -= toPrint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(double num, int digits = 2)
|
||||||
|
{
|
||||||
|
printFloat(num, digits);
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(void)
|
||||||
|
{
|
||||||
|
print("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(const char* s)
|
||||||
|
{
|
||||||
|
print(s);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
void println(char c)
|
||||||
|
{
|
||||||
|
print(c);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(unsigned char num, int base)
|
||||||
|
{
|
||||||
|
print(num, base);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(int num, int base)
|
||||||
|
{
|
||||||
|
print(num, base);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(unsigned int num, int base)
|
||||||
|
{
|
||||||
|
print(num, base);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(long num, int base)
|
||||||
|
{
|
||||||
|
print(num, base);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(unsigned long num, int base)
|
||||||
|
{
|
||||||
|
print(num, base);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(unsigned long long num, int base)
|
||||||
|
{
|
||||||
|
printUint64(num, base);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(double num, int digits = 2)
|
||||||
|
{
|
||||||
|
print(num, digits);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(double num)
|
||||||
|
{
|
||||||
|
// default: print 10 digits
|
||||||
|
println(num, 10);
|
||||||
|
}
|
||||||
|
#endif // KNX_NO_PRINT
|
||||||
|
|
||||||
|
uint32_t digitalRead(uint32_t dwPin)
|
||||||
|
{
|
||||||
|
print("ignoring digitalRead: pin: ");
|
||||||
|
print(dwPin);
|
||||||
|
println(", returning 0");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void digitalWrite(unsigned long pin, unsigned long value)
|
||||||
|
{
|
||||||
|
if (pin == Board_GPIO_LED0)
|
||||||
|
{
|
||||||
|
if (value > 0)
|
||||||
|
{
|
||||||
|
GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
print("dummy digitalWrite: pin: ");
|
||||||
|
print(pin);
|
||||||
|
print(", value: ");
|
||||||
|
println(value, HEX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pinMode(unsigned long pin, unsigned long mode)
|
||||||
|
{
|
||||||
|
print("ignoring pinMode: pin: ");
|
||||||
|
print(pin);
|
||||||
|
print(", mode: ");
|
||||||
|
println(mode, HEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*IsrFuncPtr)();
|
||||||
|
static IsrFuncPtr gpioCallback;
|
||||||
|
static void gpioButtonFxn0(uint_least8_t index)
|
||||||
|
{
|
||||||
|
gpioCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
void attachInterrupt(uint32_t pin, IsrFuncPtr callback, uint32_t mode)
|
||||||
|
{
|
||||||
|
if (pin == Board_GPIO_BUTTON0)
|
||||||
|
{
|
||||||
|
gpioCallback = callback;
|
||||||
|
/* install Button callback */
|
||||||
|
GPIO_setCallback(Board_GPIO_BUTTON0, gpioButtonFxn0);
|
||||||
|
|
||||||
|
/* Enable interrupts */
|
||||||
|
GPIO_enableInt(Board_GPIO_BUTTON0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
print("dummy attachInterrupt: pin: ");
|
||||||
|
print(pin);
|
||||||
|
print(", mode: ");
|
||||||
|
println(mode, HEX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CC1310Platform::CC1310Platform()
|
||||||
|
{
|
||||||
|
// build serialNumber from IEEE MAC Address (MAC is 8 bytes, serialNumber 6 bytes only)
|
||||||
|
*(uint32_t*)(serialNumber + 2) = HWREG(FCFG1_BASE + FCFG1_O_MAC_15_4_0) ^ HWREG(FCFG1_BASE + FCFG1_O_MAC_15_4_1); // make a 6 byte hash from 8 bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
CC1310Platform::~CC1310Platform()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CC1310Platform::init()
|
||||||
|
{
|
||||||
|
// TI Drivers init
|
||||||
|
// According to SDK docs it is safe to call them AFTER NoRTOS_Start()
|
||||||
|
// If RTOS is used and multiple thread use the same driver, then the init shall be performed before BIOS_Start()
|
||||||
|
GPIO_init();
|
||||||
|
UART_init();
|
||||||
|
NVS_init();
|
||||||
|
|
||||||
|
// Init GPIO
|
||||||
|
setupGPIO();
|
||||||
|
|
||||||
|
// Init UART
|
||||||
|
setupUART();
|
||||||
|
|
||||||
|
// tick Period on this controller 10us so we use our own millisecond clock
|
||||||
|
setupClock();
|
||||||
|
|
||||||
|
// Init flash
|
||||||
|
setupNVS();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* CC1310Platform::getEepromBuffer(uint32_t size)
|
||||||
|
{
|
||||||
|
if (size > KNX_FLASH_SIZE)
|
||||||
|
{
|
||||||
|
fatalError();
|
||||||
|
}
|
||||||
|
|
||||||
|
NVS_read(nvsHandle, 0, (void*) NVS_buffer, size);
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
if (NVS_buffer[i] != 0)
|
||||||
|
{
|
||||||
|
return NVS_buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(NVS_buffer, 0xff, size);
|
||||||
|
|
||||||
|
return NVS_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CC1310Platform::commitToEeprom()
|
||||||
|
{
|
||||||
|
println("CC1310Platform::commitToEeprom() ...");
|
||||||
|
|
||||||
|
int_fast16_t result = NVS_write(nvsHandle, 0, (void*)NVS_buffer, KNX_FLASH_SIZE, NVS_WRITE_ERASE | NVS_WRITE_POST_VERIFY);
|
||||||
|
|
||||||
|
if (result != NVS_STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
print("Error writing to NVS, result: ");
|
||||||
|
println(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
println("NVS successfully written");
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CC1310Platform::restart()
|
||||||
|
{
|
||||||
|
println("System restart in 500ms.");
|
||||||
|
delay(500);
|
||||||
|
SysCtrlSystemReset();
|
||||||
|
// Should neber be reached!
|
||||||
|
fatalError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CC1310Platform::fatalError()
|
||||||
|
{
|
||||||
|
println("A fatal error occured. Stopped.");
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
/* Turn on user LED */
|
||||||
|
GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF);
|
||||||
|
GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_ON);
|
||||||
|
delay(500);
|
||||||
|
GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON);
|
||||||
|
GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_OFF);
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DeviceFamily_CC13X0
|
||||||
27
components/knx/src/cc1310_platform.h
Normal file
27
components/knx/src/cc1310_platform.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef DeviceFamily_CC13X0
|
||||||
|
|
||||||
|
#include <ti/drivers/NVS.h>
|
||||||
|
#include <ti/drivers/UART.h>
|
||||||
|
#include <ti/drivers/dpl/ClockP.h>
|
||||||
|
|
||||||
|
#include "knx/platform.h"
|
||||||
|
|
||||||
|
class CC1310Platform : public Platform
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CC1310Platform();
|
||||||
|
virtual ~CC1310Platform();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
// basic stuff
|
||||||
|
void restart() final;
|
||||||
|
void fatalError() final;
|
||||||
|
|
||||||
|
uint8_t* getEepromBuffer(uint32_t size) final;
|
||||||
|
void commitToEeprom() final;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //DeviceFamily_CC13X0
|
||||||
443
components/knx/src/esp32_idf_platform.cpp
Normal file
443
components/knx/src/esp32_idf_platform.cpp
Normal file
@ -0,0 +1,443 @@
|
|||||||
|
#ifndef ARDUINO
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
// esp32_idf_platform.cpp
|
||||||
|
#include <esp_system.h>
|
||||||
|
#include <esp_mac.h>
|
||||||
|
#include "esp32_idf_platform.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "knx/bits.h"
|
||||||
|
#include "nvs.h"
|
||||||
|
#include <esp_timer.h>
|
||||||
|
|
||||||
|
static const char* KTAG = "KNX_LIB";
|
||||||
|
|
||||||
|
Esp32IdfPlatform::Esp32IdfPlatform(uart_port_t uart_num)
|
||||||
|
: _uart_num(uart_num)
|
||||||
|
{
|
||||||
|
// Set the memory type to use our NVS-based EEPROM emulation
|
||||||
|
_memoryType = Eeprom;
|
||||||
|
}
|
||||||
|
|
||||||
|
Esp32IdfPlatform::~Esp32IdfPlatform()
|
||||||
|
{
|
||||||
|
if (_sock != -1)
|
||||||
|
{
|
||||||
|
closeMultiCast();
|
||||||
|
}
|
||||||
|
if (_uart_installed)
|
||||||
|
{
|
||||||
|
closeUart();
|
||||||
|
}
|
||||||
|
if (_eeprom_buffer)
|
||||||
|
{
|
||||||
|
free(_eeprom_buffer);
|
||||||
|
}
|
||||||
|
if (_nvs_handle)
|
||||||
|
{
|
||||||
|
nvs_close(_nvs_handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Esp32IdfPlatform::knxUartPins(int8_t rxPin, int8_t txPin)
|
||||||
|
{
|
||||||
|
_rxPin = rxPin;
|
||||||
|
_txPin = txPin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Esp32IdfPlatform::knxUartBaudRate(uint32_t baudRate)
|
||||||
|
{
|
||||||
|
_baudRate = baudRate;
|
||||||
|
ESP_LOGI(KTAG, "UART baud rate set to %lu", _baudRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Esp32IdfPlatform::setNetif(esp_netif_t* netif)
|
||||||
|
{
|
||||||
|
_netif = netif;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Esp32IdfPlatform::fatalError()
|
||||||
|
{
|
||||||
|
ESP_LOGE(KTAG, "FATAL ERROR. System halted.");
|
||||||
|
// Loop forever to halt the system
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ESP specific uart handling with pins
|
||||||
|
void Esp32IdfPlatform::setupUart()
|
||||||
|
{
|
||||||
|
if (_uart_installed)
|
||||||
|
return;
|
||||||
|
uart_config_t uart_config;
|
||||||
|
memset(&uart_config, 0, sizeof(uart_config));
|
||||||
|
uart_config.baud_rate = _baudRate; // Use configurable baud rate
|
||||||
|
uart_config.data_bits = UART_DATA_8_BITS;
|
||||||
|
uart_config.parity = UART_PARITY_EVEN;
|
||||||
|
uart_config.stop_bits = UART_STOP_BITS_1;
|
||||||
|
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
|
||||||
|
uart_config.source_clk = UART_SCLK_DEFAULT;
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(uart_driver_install(_uart_num, 256 * 2, 0, 0, NULL, 0));
|
||||||
|
ESP_ERROR_CHECK(uart_param_config(_uart_num, &uart_config));
|
||||||
|
ESP_ERROR_CHECK(uart_set_pin(_uart_num, _txPin, _rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||||
|
_uart_installed = true;
|
||||||
|
ESP_LOGI(KTAG, "UART initialized with baud rate %lu", _baudRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Esp32IdfPlatform::closeUart()
|
||||||
|
{
|
||||||
|
if (!_uart_installed)
|
||||||
|
return;
|
||||||
|
uart_driver_delete(_uart_num);
|
||||||
|
_uart_installed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Esp32IdfPlatform::uartAvailable()
|
||||||
|
{
|
||||||
|
if (!_uart_installed)
|
||||||
|
return 0;
|
||||||
|
size_t length = 0;
|
||||||
|
ESP_ERROR_CHECK(uart_get_buffered_data_len(_uart_num, &length));
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Esp32IdfPlatform::writeUart(const uint8_t data)
|
||||||
|
{
|
||||||
|
if (!_uart_installed)
|
||||||
|
return 0;
|
||||||
|
return uart_write_bytes(_uart_num, &data, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Esp32IdfPlatform::writeUart(const uint8_t* buffer, size_t size)
|
||||||
|
{
|
||||||
|
if (!_uart_installed)
|
||||||
|
return 0;
|
||||||
|
return uart_write_bytes(_uart_num, buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Esp32IdfPlatform::readUart()
|
||||||
|
{
|
||||||
|
if (!_uart_installed)
|
||||||
|
return -1;
|
||||||
|
uint8_t data;
|
||||||
|
if (uart_read_bytes(_uart_num, &data, 1, pdMS_TO_TICKS(20)) > 0)
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Esp32IdfPlatform::readBytesUart(uint8_t* buffer, size_t length)
|
||||||
|
{
|
||||||
|
if (!_uart_installed)
|
||||||
|
return 0;
|
||||||
|
return uart_read_bytes(_uart_num, buffer, length, pdMS_TO_TICKS(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Esp32IdfPlatform::flushUart()
|
||||||
|
{
|
||||||
|
if (!_uart_installed)
|
||||||
|
return;
|
||||||
|
ESP_ERROR_CHECK(uart_flush(_uart_num));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Esp32IdfPlatform::currentIpAddress()
|
||||||
|
{
|
||||||
|
if (!_netif)
|
||||||
|
return 0;
|
||||||
|
esp_netif_ip_info_t ip_info;
|
||||||
|
esp_netif_get_ip_info(_netif, &ip_info);
|
||||||
|
return ip_info.ip.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Esp32IdfPlatform::currentSubnetMask()
|
||||||
|
{
|
||||||
|
if (!_netif)
|
||||||
|
return 0;
|
||||||
|
esp_netif_ip_info_t ip_info;
|
||||||
|
esp_netif_get_ip_info(_netif, &ip_info);
|
||||||
|
return ip_info.netmask.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Esp32IdfPlatform::currentDefaultGateway()
|
||||||
|
{
|
||||||
|
if (!_netif)
|
||||||
|
return 0;
|
||||||
|
esp_netif_ip_info_t ip_info;
|
||||||
|
esp_netif_get_ip_info(_netif, &ip_info);
|
||||||
|
return ip_info.gw.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Esp32IdfPlatform::macAddress(uint8_t* addr)
|
||||||
|
{
|
||||||
|
if (!_netif)
|
||||||
|
return;
|
||||||
|
esp_netif_get_mac(_netif, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Esp32IdfPlatform::uniqueSerialNumber()
|
||||||
|
{
|
||||||
|
uint8_t mac[6];
|
||||||
|
esp_efuse_mac_get_default(mac);
|
||||||
|
uint64_t chipid = 0;
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
chipid |= ((uint64_t)mac[i] << (i * 8));
|
||||||
|
}
|
||||||
|
uint32_t upperId = (chipid >> 32) & 0xFFFFFFFF;
|
||||||
|
uint32_t lowerId = (chipid & 0xFFFFFFFF);
|
||||||
|
return (upperId ^ lowerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Esp32IdfPlatform::restart()
|
||||||
|
{
|
||||||
|
ESP_LOGI(KTAG, "Restarting system...");
|
||||||
|
esp_restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Esp32IdfPlatform::setupMultiCast(uint32_t addr, uint16_t port)
|
||||||
|
{
|
||||||
|
_multicast_addr = addr;
|
||||||
|
_multicast_port = port;
|
||||||
|
|
||||||
|
_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||||
|
if (_sock < 0)
|
||||||
|
{
|
||||||
|
ESP_LOGE(KTAG, "Failed to create socket. Errno: %d", errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in saddr;
|
||||||
|
memset(&saddr, 0, sizeof(saddr));
|
||||||
|
saddr.sin_family = AF_INET;
|
||||||
|
saddr.sin_port = htons(port);
|
||||||
|
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
if (bind(_sock, (struct sockaddr*)&saddr, sizeof(struct sockaddr_in)) < 0)
|
||||||
|
{
|
||||||
|
ESP_LOGE(KTAG, "Failed to bind socket. Errno: %d", errno);
|
||||||
|
close(_sock);
|
||||||
|
_sock = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ip_mreq imreq;
|
||||||
|
memset(&imreq, 0, sizeof(imreq));
|
||||||
|
imreq.imr_interface.s_addr = IPADDR_ANY;
|
||||||
|
imreq.imr_multiaddr.s_addr = addr;
|
||||||
|
if (setsockopt(_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imreq, sizeof(struct ip_mreq)) < 0)
|
||||||
|
{
|
||||||
|
ESP_LOGE(KTAG, "Failed to join multicast group. Errno: %d", errno);
|
||||||
|
close(_sock);
|
||||||
|
_sock = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(KTAG, "Successfully joined multicast group on port %d", port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Esp32IdfPlatform::closeMultiCast()
|
||||||
|
{
|
||||||
|
if (_sock != -1)
|
||||||
|
{
|
||||||
|
close(_sock);
|
||||||
|
_sock = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Esp32IdfPlatform::sendBytesMultiCast(uint8_t* buffer, uint16_t len)
|
||||||
|
{
|
||||||
|
if (_sock < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
struct sockaddr_in dest_addr = {};
|
||||||
|
dest_addr.sin_family = AF_INET;
|
||||||
|
dest_addr.sin_port = htons(_multicast_port);
|
||||||
|
dest_addr.sin_addr.s_addr = _multicast_addr;
|
||||||
|
|
||||||
|
int sent_len = sendto(_sock, buffer, len, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr));
|
||||||
|
if (sent_len < 0)
|
||||||
|
{
|
||||||
|
ESP_LOGE(KTAG, "sendBytesMultiCast failed. Errno: %d", errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return sent_len == len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Esp32IdfPlatform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port)
|
||||||
|
{
|
||||||
|
if (_sock < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
socklen_t socklen = sizeof(_remote_addr);
|
||||||
|
int len = recvfrom(_sock, buffer, maxLen, 0, (struct sockaddr*)&_remote_addr, &socklen);
|
||||||
|
|
||||||
|
if (len <= 0)
|
||||||
|
{
|
||||||
|
return 0; // No data or error
|
||||||
|
}
|
||||||
|
|
||||||
|
src_addr = _remote_addr.sin_addr.s_addr;
|
||||||
|
src_port = ntohs(_remote_addr.sin_port);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Esp32IdfPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len)
|
||||||
|
{
|
||||||
|
if (_sock < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
struct sockaddr_in dest_addr;
|
||||||
|
dest_addr.sin_family = AF_INET;
|
||||||
|
|
||||||
|
if (addr == 0)
|
||||||
|
{ // If address is 0, use the address from the last received packet
|
||||||
|
dest_addr.sin_addr.s_addr = _remote_addr.sin_addr.s_addr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dest_addr.sin_addr.s_addr = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port == 0)
|
||||||
|
{ // If port is 0, use the port from the last received packet
|
||||||
|
dest_addr.sin_port = _remote_addr.sin_port;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dest_addr.sin_port = htons(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sendto(_sock, buffer, len, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr)) < 0)
|
||||||
|
{
|
||||||
|
ESP_LOGE(KTAG, "sendBytesUniCast failed. Errno: %d", errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* Esp32IdfPlatform::getEepromBuffer(uint32_t size)
|
||||||
|
{
|
||||||
|
if (_eeprom_buffer && _eeprom_size == size)
|
||||||
|
{
|
||||||
|
return _eeprom_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_eeprom_buffer)
|
||||||
|
{
|
||||||
|
free(_eeprom_buffer);
|
||||||
|
_eeprom_buffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
_eeprom_size = size;
|
||||||
|
_eeprom_buffer = (uint8_t*)malloc(size);
|
||||||
|
if (!_eeprom_buffer)
|
||||||
|
{
|
||||||
|
ESP_LOGE(KTAG, "Failed to allocate EEPROM buffer");
|
||||||
|
fatalError();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t err = nvs_flash_init();
|
||||||
|
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
|
||||||
|
{
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
|
err = nvs_flash_init();
|
||||||
|
}
|
||||||
|
ESP_ERROR_CHECK(err);
|
||||||
|
|
||||||
|
err = nvs_open(_nvs_namespace, NVS_READWRITE, &_nvs_handle);
|
||||||
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
|
ESP_LOGE(KTAG, "Error opening NVS handle: %s", esp_err_to_name(err));
|
||||||
|
free(_eeprom_buffer);
|
||||||
|
_eeprom_buffer = nullptr;
|
||||||
|
fatalError();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t required_size = size;
|
||||||
|
err = nvs_get_blob(_nvs_handle, _nvs_key, _eeprom_buffer, &required_size);
|
||||||
|
if (err != ESP_OK || required_size != size)
|
||||||
|
{
|
||||||
|
if (err == ESP_ERR_NVS_NOT_FOUND)
|
||||||
|
{
|
||||||
|
ESP_LOGI(KTAG, "No previous EEPROM data found in NVS. Initializing fresh buffer.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ESP_LOGW(KTAG, "NVS get blob failed (%s) or size mismatch. Initializing fresh buffer.", esp_err_to_name(err));
|
||||||
|
}
|
||||||
|
memset(_eeprom_buffer, 0xFF, size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ESP_LOGI(KTAG, "Successfully loaded %d bytes from NVS into EEPROM buffer.", required_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _eeprom_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Esp32IdfPlatform::commitToEeprom()
|
||||||
|
{
|
||||||
|
if (!_eeprom_buffer || !_nvs_handle)
|
||||||
|
{
|
||||||
|
ESP_LOGE(KTAG, "EEPROM not initialized, cannot commit.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t err = nvs_set_blob(_nvs_handle, _nvs_key, _eeprom_buffer, _eeprom_size);
|
||||||
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
|
ESP_LOGE(KTAG, "Failed to set NVS blob: %s", esp_err_to_name(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = nvs_commit(_nvs_handle);
|
||||||
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
|
ESP_LOGE(KTAG, "Failed to commit NVS: %s", esp_err_to_name(err));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ESP_LOGI(KTAG, "Committed %" PRIu32 " bytes to NVS.", _eeprom_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t millis()
|
||||||
|
{
|
||||||
|
// esp_timer_get_time() returns microseconds, so we divide by 1000 for milliseconds.
|
||||||
|
// Cast to uint32_t to match the Arduino function signature.
|
||||||
|
return (uint32_t)(esp_timer_get_time() / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal wrapper function to bridge Arduino-style ISR to ESP-IDF
|
||||||
|
static void IRAM_ATTR isr_wrapper(void* arg)
|
||||||
|
{
|
||||||
|
IsrFuncPtr fn = (IsrFuncPtr)arg;
|
||||||
|
fn(); // call the original ISR
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement attachInterrupt arduino like in ESP IDF
|
||||||
|
void attachInterrupt(uint32_t pin, IsrFuncPtr callback, uint32_t mode)
|
||||||
|
{
|
||||||
|
gpio_config_t io_conf = {
|
||||||
|
.pin_bit_mask = (1ULL << pin),
|
||||||
|
.mode = GPIO_MODE_INPUT,
|
||||||
|
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||||
|
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||||
|
.intr_type = (gpio_int_type_t)mode
|
||||||
|
};
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(gpio_config(&io_conf));
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(gpio_install_isr_service(0));
|
||||||
|
// Add ISR using the wrapper and pass original function as argument
|
||||||
|
ESP_ERROR_CHECK(gpio_isr_handler_add((gpio_num_t)pin, isr_wrapper, (void*)callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ESP_PLATFORM
|
||||||
|
#endif // !ARDUINO
|
||||||
89
components/knx/src/esp32_idf_platform.h
Normal file
89
components/knx/src/esp32_idf_platform.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#ifndef ARDUINO
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
// esp_idf_platform.h
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "driver/uart.h"
|
||||||
|
#include "esp_netif.h"
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include "lwip/sockets.h"
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
#include "knx/platform.h"// Include the provided base class
|
||||||
|
|
||||||
|
class Esp32IdfPlatform : public Platform
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Esp32IdfPlatform(uart_port_t uart_num = UART_NUM_1);
|
||||||
|
~Esp32IdfPlatform();
|
||||||
|
|
||||||
|
// uart
|
||||||
|
void knxUartPins(int8_t rxPin, int8_t txPin);
|
||||||
|
void knxUartBaudRate(uint32_t baudRate); // Add baud rate configuration
|
||||||
|
|
||||||
|
// Call this after WiFi/Ethernet has started and received an IP.
|
||||||
|
void setNetif(esp_netif_t* netif);
|
||||||
|
|
||||||
|
// --- Overridden Virtual Functions ---
|
||||||
|
|
||||||
|
// ip stuff
|
||||||
|
uint32_t currentIpAddress() override;
|
||||||
|
uint32_t currentSubnetMask() override;
|
||||||
|
uint32_t currentDefaultGateway() override;
|
||||||
|
void macAddress(uint8_t* addr) override;
|
||||||
|
|
||||||
|
// unique serial number
|
||||||
|
uint32_t uniqueSerialNumber() override;
|
||||||
|
|
||||||
|
// basic stuff (pure virtual in base)
|
||||||
|
void restart() override;
|
||||||
|
void fatalError() override;
|
||||||
|
|
||||||
|
// multicast
|
||||||
|
void setupMultiCast(uint32_t addr, uint16_t port) override;
|
||||||
|
void closeMultiCast() override;
|
||||||
|
bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override;
|
||||||
|
int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port) override;
|
||||||
|
|
||||||
|
// unicast
|
||||||
|
bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override;
|
||||||
|
|
||||||
|
// UART
|
||||||
|
void setupUart() override;
|
||||||
|
void closeUart() override;
|
||||||
|
int uartAvailable() override;
|
||||||
|
size_t writeUart(const uint8_t data) override;
|
||||||
|
size_t writeUart(const uint8_t* buffer, size_t size) override;
|
||||||
|
int readUart() override;
|
||||||
|
size_t readBytesUart(uint8_t* buffer, size_t length) override;
|
||||||
|
void flushUart() override;
|
||||||
|
|
||||||
|
// Memory (EEPROM emulation via NVS)
|
||||||
|
// We override these two functions to provide the low-level storage mechanism.
|
||||||
|
// The base Platform class will use them when _memoryType is Eeprom.
|
||||||
|
uint8_t* getEepromBuffer(uint32_t size) override;
|
||||||
|
void commitToEeprom() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Network
|
||||||
|
esp_netif_t* _netif = nullptr;
|
||||||
|
int _sock = -1;
|
||||||
|
struct sockaddr_in _remote_addr;
|
||||||
|
uint32_t _multicast_addr = 0;
|
||||||
|
uint16_t _multicast_port = 0;
|
||||||
|
|
||||||
|
// UART
|
||||||
|
uart_port_t _uart_num;
|
||||||
|
int8_t _rxPin = -1;
|
||||||
|
int8_t _txPin = -1;
|
||||||
|
uint32_t _baudRate = 19200; // Default baud rate, can be changed
|
||||||
|
bool _uart_installed = false;
|
||||||
|
|
||||||
|
// NVS (for EEPROM emulation)
|
||||||
|
nvs_handle_t _nvs_handle;
|
||||||
|
uint8_t* _eeprom_buffer = nullptr;
|
||||||
|
uint32_t _eeprom_size = 0;
|
||||||
|
const char* _nvs_namespace = "eeprom";
|
||||||
|
const char* _nvs_key = "eeprom";
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
184
components/knx/src/esp32_platform.cpp
Normal file
184
components/knx/src/esp32_platform.cpp
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
#include "esp32_platform.h"
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <EEPROM.h>
|
||||||
|
|
||||||
|
#include "knx/bits.h"
|
||||||
|
|
||||||
|
#ifndef KNX_SERIAL
|
||||||
|
#define KNX_SERIAL Serial1
|
||||||
|
#pragma warn "KNX_SERIAL not defined, using Serial1"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef KNX_IP_LAN
|
||||||
|
#include "ETH.h"
|
||||||
|
#define KNX_NETIF ETH
|
||||||
|
#else // KNX_IP_WIFI
|
||||||
|
#include <WiFi.h>
|
||||||
|
#define KNX_NETIF WiFi
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Esp32Platform::Esp32Platform()
|
||||||
|
#ifndef KNX_NO_DEFAULT_UART
|
||||||
|
: ArduinoPlatform(&KNX_SERIAL)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#ifdef KNX_UART_RX_PIN
|
||||||
|
_rxPin = KNX_UART_RX_PIN;
|
||||||
|
#endif
|
||||||
|
#ifdef KNX_UART_TX_PIN
|
||||||
|
_txPin = KNX_UART_TX_PIN;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Esp32Platform::Esp32Platform(HardwareSerial* s) : ArduinoPlatform(s)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Esp32Platform::knxUartPins(int8_t rxPin, int8_t txPin)
|
||||||
|
{
|
||||||
|
_rxPin = rxPin;
|
||||||
|
_txPin = txPin;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ESP specific uart handling with pins
|
||||||
|
void Esp32Platform::setupUart()
|
||||||
|
{
|
||||||
|
_knxSerial->begin(19200, SERIAL_8E1, _rxPin, _txPin);
|
||||||
|
|
||||||
|
while (!_knxSerial)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Esp32Platform::currentIpAddress()
|
||||||
|
{
|
||||||
|
return KNX_NETIF.localIP();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Esp32Platform::currentSubnetMask()
|
||||||
|
{
|
||||||
|
return KNX_NETIF.subnetMask();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Esp32Platform::currentDefaultGateway()
|
||||||
|
{
|
||||||
|
return KNX_NETIF.gatewayIP();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Esp32Platform::macAddress(uint8_t* addr)
|
||||||
|
{
|
||||||
|
KNX_NETIF.macAddress(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Esp32Platform::uniqueSerialNumber()
|
||||||
|
{
|
||||||
|
uint64_t chipid = ESP.getEfuseMac();
|
||||||
|
uint32_t upperId = (chipid >> 32) & 0xFFFFFFFF;
|
||||||
|
uint32_t lowerId = (chipid & 0xFFFFFFFF);
|
||||||
|
return (upperId ^ lowerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Esp32Platform::restart()
|
||||||
|
{
|
||||||
|
println("restart");
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Esp32Platform::setupMultiCast(uint32_t addr, uint16_t port)
|
||||||
|
{
|
||||||
|
IPAddress mcastaddr(htonl(addr));
|
||||||
|
|
||||||
|
KNX_DEBUG_SERIAL.printf("setup multicast addr: %s port: %d ip: %s\n", mcastaddr.toString().c_str(), port,
|
||||||
|
KNX_NETIF.localIP().toString().c_str());
|
||||||
|
uint8_t result = _udp.beginMulticast(mcastaddr, port);
|
||||||
|
KNX_DEBUG_SERIAL.printf("multicast setup result %d\n", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Esp32Platform::closeMultiCast()
|
||||||
|
{
|
||||||
|
_udp.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Esp32Platform::sendBytesMultiCast(uint8_t* buffer, uint16_t len)
|
||||||
|
{
|
||||||
|
//printHex("<- ",buffer, len);
|
||||||
|
_udp.beginMulticastPacket();
|
||||||
|
_udp.write(buffer, len);
|
||||||
|
_udp.endPacket();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Esp32Platform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port)
|
||||||
|
{
|
||||||
|
int len = _udp.parsePacket();
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (len > maxLen)
|
||||||
|
{
|
||||||
|
println("Unexpected UDP data packet length - drop packet");
|
||||||
|
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
_udp.read();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_udp.read(buffer, len);
|
||||||
|
_remoteIP = _udp.remoteIP();
|
||||||
|
_remotePort = _udp.remotePort();
|
||||||
|
src_addr = htonl(_remoteIP);
|
||||||
|
src_port = _remotePort;
|
||||||
|
|
||||||
|
// print("Remote IP: ");
|
||||||
|
// print(_udp.remoteIP().toString().c_str());
|
||||||
|
// printHex("-> ", buffer, len);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Esp32Platform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len)
|
||||||
|
{
|
||||||
|
IPAddress ucastaddr(htonl(addr));
|
||||||
|
|
||||||
|
if (!addr)
|
||||||
|
ucastaddr = _remoteIP;
|
||||||
|
|
||||||
|
if (!port)
|
||||||
|
port = _remotePort;
|
||||||
|
|
||||||
|
if (_udp.beginPacket(ucastaddr, port) == 1)
|
||||||
|
{
|
||||||
|
_udp.write(buffer, len);
|
||||||
|
|
||||||
|
if (_udp.endPacket() == 0)
|
||||||
|
println("sendBytesUniCast endPacket fail");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
println("sendBytesUniCast beginPacket fail");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* Esp32Platform::getEepromBuffer(uint32_t size)
|
||||||
|
{
|
||||||
|
uint8_t* eepromptr = EEPROM.getDataPtr();
|
||||||
|
|
||||||
|
if (eepromptr == nullptr)
|
||||||
|
{
|
||||||
|
EEPROM.begin(size);
|
||||||
|
eepromptr = EEPROM.getDataPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
return eepromptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Esp32Platform::commitToEeprom()
|
||||||
|
{
|
||||||
|
EEPROM.getDataPtr(); // trigger dirty flag in EEPROM lib to make sure data will be written to flash
|
||||||
|
EEPROM.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
54
components/knx/src/esp32_platform.h
Normal file
54
components/knx/src/esp32_platform.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
#include "arduino_platform.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <WiFiUdp.h>
|
||||||
|
|
||||||
|
class Esp32Platform : public ArduinoPlatform
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Esp32Platform();
|
||||||
|
Esp32Platform(HardwareSerial* s);
|
||||||
|
|
||||||
|
// uart
|
||||||
|
void knxUartPins(int8_t rxPin, int8_t txPin);
|
||||||
|
void setupUart() override;
|
||||||
|
|
||||||
|
// ip stuff
|
||||||
|
uint32_t currentIpAddress() override;
|
||||||
|
uint32_t currentSubnetMask() override;
|
||||||
|
uint32_t currentDefaultGateway() override;
|
||||||
|
void macAddress(uint8_t* addr) override;
|
||||||
|
|
||||||
|
// unique serial number
|
||||||
|
uint32_t uniqueSerialNumber() override;
|
||||||
|
|
||||||
|
// basic stuff
|
||||||
|
void restart();
|
||||||
|
|
||||||
|
//multicast
|
||||||
|
void setupMultiCast(uint32_t addr, uint16_t port) override;
|
||||||
|
void closeMultiCast() override;
|
||||||
|
bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override;
|
||||||
|
int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port) override;
|
||||||
|
|
||||||
|
//unicast
|
||||||
|
bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override;
|
||||||
|
|
||||||
|
//memory
|
||||||
|
uint8_t* getEepromBuffer(uint32_t size);
|
||||||
|
void commitToEeprom();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
IPAddress _remoteIP;
|
||||||
|
protected:
|
||||||
|
uint16_t _remotePort;
|
||||||
|
|
||||||
|
private:
|
||||||
|
WiFiUDP _udp;
|
||||||
|
int8_t _rxPin = -1;
|
||||||
|
int8_t _txPin = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
135
components/knx/src/esp_platform.cpp
Normal file
135
components/knx/src/esp_platform.cpp
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
#include "esp_platform.h"
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
|
#include <user_interface.h>
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <EEPROM.h>
|
||||||
|
|
||||||
|
#include "knx/bits.h"
|
||||||
|
|
||||||
|
#ifndef KNX_SERIAL
|
||||||
|
#define KNX_SERIAL Serial
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EspPlatform::EspPlatform()
|
||||||
|
#ifndef KNX_NO_DEFAULT_UART
|
||||||
|
: ArduinoPlatform(&KNX_SERIAL)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
EspPlatform::EspPlatform( HardwareSerial* s) : ArduinoPlatform(s)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t EspPlatform::currentIpAddress()
|
||||||
|
{
|
||||||
|
return WiFi.localIP();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t EspPlatform::currentSubnetMask()
|
||||||
|
{
|
||||||
|
return WiFi.subnetMask();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t EspPlatform::currentDefaultGateway()
|
||||||
|
{
|
||||||
|
return WiFi.gatewayIP();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EspPlatform::macAddress(uint8_t* addr)
|
||||||
|
{
|
||||||
|
wifi_get_macaddr(STATION_IF, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t EspPlatform::uniqueSerialNumber()
|
||||||
|
{
|
||||||
|
return ESP.getChipId();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EspPlatform::restart()
|
||||||
|
{
|
||||||
|
println("restart");
|
||||||
|
ESP.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EspPlatform::setupMultiCast(uint32_t addr, uint16_t port)
|
||||||
|
{
|
||||||
|
_multicastAddr = htonl(addr);
|
||||||
|
_multicastPort = port;
|
||||||
|
IPAddress mcastaddr(_multicastAddr);
|
||||||
|
|
||||||
|
KNX_DEBUG_SERIAL.printf("setup multicast addr: %s port: %d ip: %s\n", mcastaddr.toString().c_str(), port,
|
||||||
|
WiFi.localIP().toString().c_str());
|
||||||
|
uint8 result = _udp.beginMulticast(WiFi.localIP(), mcastaddr, port);
|
||||||
|
KNX_DEBUG_SERIAL.printf("multicast setup result %d\n", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EspPlatform::closeMultiCast()
|
||||||
|
{
|
||||||
|
_udp.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EspPlatform::sendBytesMultiCast(uint8_t* buffer, uint16_t len)
|
||||||
|
{
|
||||||
|
//printHex("<- ",buffer, len);
|
||||||
|
_udp.beginPacketMulticast(_multicastAddr, _multicastPort, WiFi.localIP());
|
||||||
|
_udp.write(buffer, len);
|
||||||
|
_udp.endPacket();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int EspPlatform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen)
|
||||||
|
{
|
||||||
|
int len = _udp.parsePacket();
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (len > maxLen)
|
||||||
|
{
|
||||||
|
KNX_DEBUG_SERIAL.printf("udp buffer to small. was %d, needed %d\n", maxLen, len);
|
||||||
|
fatalError();
|
||||||
|
}
|
||||||
|
|
||||||
|
_udp.read(buffer, len);
|
||||||
|
//printHex("-> ", buffer, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EspPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len)
|
||||||
|
{
|
||||||
|
IPAddress ucastaddr(htonl(addr));
|
||||||
|
println("sendBytesUniCast endPacket fail");
|
||||||
|
|
||||||
|
if (_udp.beginPacket(ucastaddr, port) == 1)
|
||||||
|
{
|
||||||
|
_udp.write(buffer, len);
|
||||||
|
|
||||||
|
if (_udp.endPacket() == 0)
|
||||||
|
println("sendBytesUniCast endPacket fail");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
println("sendBytesUniCast beginPacket fail");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* EspPlatform::getEepromBuffer(uint32_t size)
|
||||||
|
{
|
||||||
|
uint8_t* eepromptr = EEPROM.getDataPtr();
|
||||||
|
|
||||||
|
if (eepromptr == nullptr)
|
||||||
|
{
|
||||||
|
EEPROM.begin(size);
|
||||||
|
eepromptr = EEPROM.getDataPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
return eepromptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EspPlatform::commitToEeprom()
|
||||||
|
{
|
||||||
|
EEPROM.commit();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
43
components/knx/src/esp_platform.h
Normal file
43
components/knx/src/esp_platform.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
|
#include "arduino_platform.h"
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <WiFiUdp.h>
|
||||||
|
|
||||||
|
|
||||||
|
class EspPlatform : public ArduinoPlatform
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EspPlatform();
|
||||||
|
EspPlatform(HardwareSerial* s);
|
||||||
|
|
||||||
|
// ip stuff
|
||||||
|
uint32_t currentIpAddress() override;
|
||||||
|
uint32_t currentSubnetMask() override;
|
||||||
|
uint32_t currentDefaultGateway() override;
|
||||||
|
void macAddress(uint8_t* addr) override;
|
||||||
|
|
||||||
|
// unique serial number
|
||||||
|
uint32_t uniqueSerialNumber() override;
|
||||||
|
|
||||||
|
// basic stuff
|
||||||
|
void restart();
|
||||||
|
|
||||||
|
//multicast
|
||||||
|
void setupMultiCast(uint32_t addr, uint16_t port) override;
|
||||||
|
void closeMultiCast() override;
|
||||||
|
bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override;
|
||||||
|
int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) override;
|
||||||
|
|
||||||
|
//unicast
|
||||||
|
bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override;
|
||||||
|
|
||||||
|
//memory
|
||||||
|
uint8_t* getEepromBuffer(uint32_t size);
|
||||||
|
void commitToEeprom();
|
||||||
|
private:
|
||||||
|
WiFiUDP _udp;
|
||||||
|
uint32_t _multicastAddr;
|
||||||
|
uint16_t _multicastPort;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
248
components/knx/src/knx.h
Normal file
248
components/knx/src/knx.h
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
#pragma once
|
||||||
|
/** \page Classdiagramm KNX device
|
||||||
|
* This diagramm shows the most important classes of a normal KNX device.
|
||||||
|
|
||||||
|
@startuml
|
||||||
|
skinparam monochrome true
|
||||||
|
skinparam componentStyle uml2
|
||||||
|
|
||||||
|
package "knx" {
|
||||||
|
class BusAccessUnit [[class_bus_access_unit.html]]
|
||||||
|
class DeviceObject [[class_device_object.html]]
|
||||||
|
class BauSystemBDevice [[class_bau_system_b.html]]
|
||||||
|
BusAccessUnit<|--BauSystemB
|
||||||
|
BauSystemB<|--BauSystemBDevice
|
||||||
|
class ApplicationProgramObject [[class_application_program_object.html]]
|
||||||
|
BauSystemB*--ApplicationProgramObject
|
||||||
|
DeviceObject--*BauSystemB
|
||||||
|
class AddressTableObject [[class_address_table_object.html]]
|
||||||
|
BauSystemBDevice*--AddressTableObject
|
||||||
|
class AssociationTableObject [[class_association_table_object.html]]
|
||||||
|
BauSystemBDevice*--AssociationTableObject
|
||||||
|
class GroupObjectTableObject [[class_group_object_table_object.html]]
|
||||||
|
BauSystemBDevice*--GroupObjectTableObject
|
||||||
|
class GroupObject [[class_group_object.html]]
|
||||||
|
GroupObject<--GroupObjectTableObject
|
||||||
|
GroupObjectTableObject<--GroupObject
|
||||||
|
class ApplicationLayer [[class_application_layer.html]]
|
||||||
|
|
||||||
|
package knx-data-secure
|
||||||
|
{
|
||||||
|
class SecureApplicationLayer [[class_secure_application_layer.html]]
|
||||||
|
class SecurityInterfaceObject [[class_security_interface_object.html]]
|
||||||
|
SecureApplicationLayer-->SecurityInterfaceObject
|
||||||
|
SecurityInterfaceObject-->SecureApplicationLayer
|
||||||
|
BauSystemBDevice*--"SecurityInterfaceObject"
|
||||||
|
BauSystemBDevice*--"SecureApplicationLayer"
|
||||||
|
}
|
||||||
|
BauSystemBDevice*--"ApplicationLayer"
|
||||||
|
ApplicationLayer<|--SecureApplicationLayer
|
||||||
|
SecureApplicationLayer--*BauSystemBDevice
|
||||||
|
class TransportLayer [[class_transport_layer.html]]
|
||||||
|
TransportLayer--*BauSystemBDevice
|
||||||
|
class NetworkLayerDevice [[class_network_layer.html]]
|
||||||
|
NetworkLayerDevice--*BauSystemBDevice
|
||||||
|
class NetworkLayerEntity [[class_network_layer_entity.html]]
|
||||||
|
NetworkLayerEntity--*NetworkLayerDevice
|
||||||
|
class DataLinkLayer [[class_data_link_layer.html]]
|
||||||
|
ApplicationLayer-->SecureApplicationLayer
|
||||||
|
SecureApplicationLayer-->ApplicationLayer
|
||||||
|
ApplicationLayer-->BusAccessUnit
|
||||||
|
ApplicationLayer-->TransportLayer
|
||||||
|
SecureApplicationLayer-->TransportLayer
|
||||||
|
TransportLayer-->ApplicationLayer
|
||||||
|
TransportLayer-->SecureApplicationLayer
|
||||||
|
TransportLayer-->NetworkLayerDevice
|
||||||
|
NetworkLayerDevice-->TransportLayer
|
||||||
|
NetworkLayerEntity-->DataLinkLayer
|
||||||
|
DataLinkLayer-->NetworkLayerEntity
|
||||||
|
TransportLayer-->AddressTableObject
|
||||||
|
SecureApplicationLayer-->AddressTableObject
|
||||||
|
SecureApplicationLayer-->DeviceObject
|
||||||
|
DataLinkLayer-->DeviceObject
|
||||||
|
ApplicationLayer-->AssociationTableObject
|
||||||
|
class Dpt [[class_dpt.html]]
|
||||||
|
GroupObject->Dpt
|
||||||
|
|
||||||
|
package knx-ip
|
||||||
|
{
|
||||||
|
class IpDataLinkLayer [[class_ip_data_link_layer.html]]
|
||||||
|
IpDataLinkLayer--|>DataLinkLayer
|
||||||
|
class Bau57B0 [[class_bau57_b0.html]]
|
||||||
|
Bau57B0--|>BauSystemBDevice
|
||||||
|
Bau57B0*--IpDataLinkLayer
|
||||||
|
class IpParameterObject [[class_ip_parameter_object.html]]
|
||||||
|
IpParameterObject-->DeviceObject
|
||||||
|
Bau57B0*--IpParameterObject
|
||||||
|
IpDataLinkLayer-->IpParameterObject
|
||||||
|
}
|
||||||
|
package knx-tp
|
||||||
|
{
|
||||||
|
class TpUartDataLinkLayer [[class_tp_uart_data_link_layer.html]]
|
||||||
|
TpUartDataLinkLayer--|>DataLinkLayer
|
||||||
|
class Bau07B0 [[class_bau07_b0.html]]
|
||||||
|
Bau07B0*--TpUartDataLinkLayer
|
||||||
|
Bau07B0--|>BauSystemBDevice
|
||||||
|
}
|
||||||
|
package knx-rf
|
||||||
|
{
|
||||||
|
class RfDataLinkLayer [[class_rf_data_link_layer.html]]
|
||||||
|
RfDataLinkLayer--|>DataLinkLayer
|
||||||
|
class Bau27B0 [[class_bau27_b0.html]]
|
||||||
|
Bau27B0*--"RfDataLinkLayer"
|
||||||
|
Bau27B0--|>BauSystemBDevice
|
||||||
|
class RfMediumObject [[class_rf_medium_object.html]]
|
||||||
|
Bau27B0*--"RfMediumObject"
|
||||||
|
class RfPhysicalLayer [[class_rf_physical_layer.html]]
|
||||||
|
"RfDataLinkLayer"*--"RfPhysicalLayer"
|
||||||
|
}
|
||||||
|
package knx-cemi-server
|
||||||
|
{
|
||||||
|
class CemiServer [[class_cemi_server.html]]
|
||||||
|
class CemiServerObject [[class_cemi_server_object.html]]
|
||||||
|
class UsbTunnelInterface [[class_usb_tunnel_inerface.html]]
|
||||||
|
CemiServer*--"UsbTunnelInterface"
|
||||||
|
Bau57B0*--"CemiServer"
|
||||||
|
Bau57B0*--"CemiServerObject"
|
||||||
|
Bau27B0*--"CemiServer"
|
||||||
|
Bau27B0*--"CemiServerObject"
|
||||||
|
Bau07B0*--"CemiServer"
|
||||||
|
Bau07B0*--"CemiServerObject"
|
||||||
|
}
|
||||||
|
CemiServer-->DataLinkLayer
|
||||||
|
DataLinkLayer-->CemiServer
|
||||||
|
}
|
||||||
|
|
||||||
|
package platform
|
||||||
|
{
|
||||||
|
class Platform [[class_platform.html]]
|
||||||
|
class ArduinoPlatform [[class_arduino_platform.html]]
|
||||||
|
class SamdPlatform [[class_samd_platform.html]]
|
||||||
|
Platform<|--ArduinoPlatform
|
||||||
|
ArduinoPlatform<|--SamdPlatform
|
||||||
|
class EspPlatform [[class_esp_platform.html]]
|
||||||
|
ArduinoPlatform<|--EspPlatform
|
||||||
|
class Esp32Platform [[class_esp32_platform.html]]
|
||||||
|
ArduinoPlatform<|--Esp32Platform
|
||||||
|
class Stm32Platform [[class_stm32_platform.html]]
|
||||||
|
ArduinoPlatform<|--Stm32Platform
|
||||||
|
class LinuxPlatform [[class_linux_platform.html]]
|
||||||
|
LinuxPlatform--|>Platform
|
||||||
|
class CC1310Platform [[class_cc1310_platform.html]]
|
||||||
|
CC1310Platform--|>Platform
|
||||||
|
class RP2040ArduinoPlatform [[class_rp2040_arduino_platform.html]]
|
||||||
|
RP2040ArduinoPlatform--|>ArduinoPlatform
|
||||||
|
}
|
||||||
|
|
||||||
|
package frontend
|
||||||
|
{
|
||||||
|
class KnxFacade [[class_knx_facade.html]]
|
||||||
|
BauSystemBDevice<--KnxFacade
|
||||||
|
}
|
||||||
|
knx-->Platform
|
||||||
|
@enduml
|
||||||
|
|
||||||
|
* \page Classdiagramm KNX coupler
|
||||||
|
* This diagramm shows the most important classes of a KNX coupler.
|
||||||
|
@startuml
|
||||||
|
|
||||||
|
skinparam monochrome true
|
||||||
|
skinparam componentStyle uml2
|
||||||
|
|
||||||
|
package "knx" {
|
||||||
|
class BusAccessUnit [[class_bus_access_unit.html]]
|
||||||
|
class DeviceObject [[class_device_object.html]]
|
||||||
|
class BauSystemBCoupler [[class_bau_system_b.html]]
|
||||||
|
BusAccessUnit<|--BauSystemB
|
||||||
|
BauSystemB<|--BauSystemBCoupler
|
||||||
|
class ApplicationProgramObject [[class_application_program_object.html]]
|
||||||
|
BauSystemB*--ApplicationProgramObject
|
||||||
|
DeviceObject--*BauSystemB
|
||||||
|
class ApplicationLayer [[class_application_layer.html]]
|
||||||
|
|
||||||
|
package knx-data-secure
|
||||||
|
{
|
||||||
|
class SecureApplicationLayer [[class_secure_application_layer.html]]
|
||||||
|
class SecurityInterfaceObject [[class_security_interface_object.html]]
|
||||||
|
SecureApplicationLayer-->SecurityInterfaceObject
|
||||||
|
SecurityInterfaceObject-->SecureApplicationLayer
|
||||||
|
BauSystemBCoupler*--"SecurityInterfaceObject"
|
||||||
|
BauSystemBCoupler*--"SecureApplicationLayer"
|
||||||
|
}
|
||||||
|
BauSystemBCoupler*--"ApplicationLayer"
|
||||||
|
ApplicationLayer<|--SecureApplicationLayer
|
||||||
|
SecureApplicationLayer--*BauSystemBCoupler
|
||||||
|
class TransportLayer [[class_transport_layer.html]]
|
||||||
|
TransportLayer--*BauSystemBCoupler
|
||||||
|
class NetworkLayerEntity [[class_network_layer_entity.html]]
|
||||||
|
class NetworkLayerCoupler [[class_network_layer.html]]
|
||||||
|
{
|
||||||
|
NetworkLayerEntity[] _networkLayerEntities
|
||||||
|
}
|
||||||
|
NetworkLayerCoupler*--"NetworkLayerEntity"
|
||||||
|
NetworkLayerCoupler--*BauSystemBCoupler
|
||||||
|
class DataLinkLayer [[class_data_link_layer.html]]
|
||||||
|
ApplicationLayer-->SecureApplicationLayer
|
||||||
|
SecureApplicationLayer-->ApplicationLayer
|
||||||
|
ApplicationLayer-->BusAccessUnit
|
||||||
|
ApplicationLayer-->TransportLayer
|
||||||
|
SecureApplicationLayer-->TransportLayer
|
||||||
|
TransportLayer-->ApplicationLayer
|
||||||
|
TransportLayer-->SecureApplicationLayer
|
||||||
|
TransportLayer-->NetworkLayerCoupler
|
||||||
|
NetworkLayerCoupler-->TransportLayer
|
||||||
|
NetworkLayerEntity-->DataLinkLayer
|
||||||
|
DataLinkLayer-->NetworkLayerEntity
|
||||||
|
SecureApplicationLayer-->DeviceObject
|
||||||
|
DataLinkLayer-->DeviceObject
|
||||||
|
|
||||||
|
package knx-ip-tp
|
||||||
|
{
|
||||||
|
class IpDataLinkLayer [[class_ip_data_link_layer.html]]
|
||||||
|
IpDataLinkLayer--|>DataLinkLayer
|
||||||
|
class TpUartDataLinkLayer [[class_tp_uart_data_link_layer.html]]
|
||||||
|
TpUartDataLinkLayer--|>DataLinkLayer
|
||||||
|
class Bau091A [[class_bau09_1a.html]]
|
||||||
|
Bau091A--|>BauSystemBCoupler
|
||||||
|
Bau091A*--IpDataLinkLayer
|
||||||
|
Bau091A*--TpUartDataLinkLayer
|
||||||
|
class RouterObject [[class_router_object.html]]
|
||||||
|
class IpParameterObject [[class_ip_parameter_object.html]]
|
||||||
|
IpParameterObject-->DeviceObject
|
||||||
|
Bau091A*--"RouterObject"
|
||||||
|
Bau091A*--IpParameterObject
|
||||||
|
IpDataLinkLayer-->IpParameterObject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
package platform
|
||||||
|
{
|
||||||
|
class Platform [[class_platform.html]]
|
||||||
|
class ArduinoPlatform [[class_arduino_platform.html]]
|
||||||
|
class SamdPlatform [[class_samd_platform.html]]
|
||||||
|
Platform<|--ArduinoPlatform
|
||||||
|
ArduinoPlatform<|--SamdPlatform
|
||||||
|
class EspPlatform [[class_esp_platform.html]]
|
||||||
|
ArduinoPlatform<|--EspPlatform
|
||||||
|
class Esp32Platform [[class_esp32_platform.html]]
|
||||||
|
ArduinoPlatform<|--Esp32Platform
|
||||||
|
class Stm32Platform [[class_stm32_platform.html]]
|
||||||
|
ArduinoPlatform<|--Stm32Platform
|
||||||
|
class LinuxPlatform [[class_linux_platform.html]]
|
||||||
|
LinuxPlatform--|>Platform
|
||||||
|
class CC1310Platform [[class_cc1310_platform.html]]
|
||||||
|
CC1310Platform--|>Platform
|
||||||
|
class RP2040ArduinoPlatform [[class_rp2040_arduino_platform.html]]
|
||||||
|
RP2040ArduinoPlatform--|>ArduinoPlatform
|
||||||
|
}
|
||||||
|
|
||||||
|
package frontend
|
||||||
|
{
|
||||||
|
class KnxFacade [[class_knx_facade.html]]
|
||||||
|
BauSystemBCoupler<--KnxFacade
|
||||||
|
}
|
||||||
|
knx-->Platform
|
||||||
|
@enduml
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "knx_facade.h"
|
||||||
96
components/knx/src/knx/address_table_object.cpp
Normal file
96
components/knx/src/knx/address_table_object.cpp
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "address_table_object.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include "data_property.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
AddressTableObject::AddressTableObject(Memory& memory)
|
||||||
|
: TableObject(memory)
|
||||||
|
{
|
||||||
|
Property* properties[] =
|
||||||
|
{
|
||||||
|
new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_ADDR_TABLE)
|
||||||
|
};
|
||||||
|
|
||||||
|
TableObject::initializeProperties(sizeof(properties), properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t AddressTableObject::entryCount()
|
||||||
|
{
|
||||||
|
// after programming without GA the module hangs
|
||||||
|
if (loadState() != LS_LOADED || _groupAddresses[0] == 0xFFFF)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return ntohs(_groupAddresses[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t AddressTableObject::getGroupAddress(uint16_t tsap)
|
||||||
|
{
|
||||||
|
if (loadState() != LS_LOADED || tsap > entryCount() )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return ntohs(_groupAddresses[tsap]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t AddressTableObject::getTsap(uint16_t addr)
|
||||||
|
{
|
||||||
|
uint16_t size = entryCount();
|
||||||
|
#ifdef USE_BINSEARCH
|
||||||
|
|
||||||
|
uint16_t low, high, i;
|
||||||
|
low = 1;
|
||||||
|
high = size;
|
||||||
|
|
||||||
|
while (low <= high)
|
||||||
|
{
|
||||||
|
i = (low + high) / 2;
|
||||||
|
uint16_t ga = ntohs(_groupAddresses[i]);
|
||||||
|
|
||||||
|
if (ga == addr)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
if (addr < ga)
|
||||||
|
high = i - 1;
|
||||||
|
else
|
||||||
|
low = i + 1 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
for (uint16_t i = 1; i <= size; i++)
|
||||||
|
if (ntohs(_groupAddresses[i]) == addr)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma region SaveRestore
|
||||||
|
|
||||||
|
const uint8_t* AddressTableObject::restore(const uint8_t* buffer)
|
||||||
|
{
|
||||||
|
buffer = TableObject::restore(buffer);
|
||||||
|
|
||||||
|
_groupAddresses = (uint16_t*)data();
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
bool AddressTableObject::contains(uint16_t addr)
|
||||||
|
{
|
||||||
|
return (getTsap(addr) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressTableObject::beforeStateChange(LoadState& newState)
|
||||||
|
{
|
||||||
|
TableObject::beforeStateChange(newState);
|
||||||
|
|
||||||
|
if (newState != LS_LOADED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_groupAddresses = (uint16_t*)data();
|
||||||
|
}
|
||||||
57
components/knx/src/knx/address_table_object.h
Normal file
57
components/knx/src/knx/address_table_object.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "table_object.h"
|
||||||
|
/**
|
||||||
|
* This class represents the group address table. It provides a mapping between transport layer
|
||||||
|
* service access points (TSAP) and group addresses. The TSAP can be imagined as an index to the array
|
||||||
|
* of group addresses.
|
||||||
|
*
|
||||||
|
* See section 4.10 of @cite knx:3/5/1 for further details.
|
||||||
|
* It implements realisation type 7 (see section 4.10.7 of @cite knx:3/5/1).
|
||||||
|
*/
|
||||||
|
class AddressTableObject : public TableObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* The constructor.
|
||||||
|
*
|
||||||
|
* @param memory This parameter is only passed to the constructor of TableObject and is not used by this class.
|
||||||
|
*/
|
||||||
|
AddressTableObject(Memory& memory);
|
||||||
|
const uint8_t* restore(const uint8_t* buffer) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the number of group addresses of the object.
|
||||||
|
*/
|
||||||
|
uint16_t entryCount();
|
||||||
|
/**
|
||||||
|
* Get the group address mapped to a TSAP.
|
||||||
|
*
|
||||||
|
* @param tsap The TSAP of which to get the group address for.
|
||||||
|
*
|
||||||
|
* @return the groupAddress if found or zero if no group address was found.
|
||||||
|
*/
|
||||||
|
uint16_t getGroupAddress(uint16_t tsap);
|
||||||
|
/**
|
||||||
|
* Get the TSAP mapped to a group address.
|
||||||
|
*
|
||||||
|
* @param groupAddress the group address of which to get the TSAP for.
|
||||||
|
*
|
||||||
|
* @return the TSAP if found or zero if no tsap was found.
|
||||||
|
*/
|
||||||
|
uint16_t getTsap(uint16_t groupAddress);
|
||||||
|
/**
|
||||||
|
* Check if the address table contains a group address.
|
||||||
|
*
|
||||||
|
* @param groupAddress the group address to check
|
||||||
|
*
|
||||||
|
* @return true if the address table contains the group address, false otherwise
|
||||||
|
*/
|
||||||
|
bool contains(uint16_t groupAddress);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void beforeStateChange(LoadState& newState) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t* _groupAddresses = 0;
|
||||||
|
};
|
||||||
606
components/knx/src/knx/aes.c
Normal file
606
components/knx/src/knx/aes.c
Normal file
@ -0,0 +1,606 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
This is an implementation of the AES algorithm, specifically ECB, CTR and CBC mode.
|
||||||
|
Block size can be chosen in aes.h - available choices are AES128, AES192, AES256.
|
||||||
|
|
||||||
|
The implementation is verified against the test vectors in:
|
||||||
|
National Institute of Standards and Technology Special Publication 800-38A 2001 ED
|
||||||
|
|
||||||
|
ECB-AES128
|
||||||
|
----------
|
||||||
|
|
||||||
|
plain-text:
|
||||||
|
6bc1bee22e409f96e93d7e117393172a
|
||||||
|
ae2d8a571e03ac9c9eb76fac45af8e51
|
||||||
|
30c81c46a35ce411e5fbc1191a0a52ef
|
||||||
|
f69f2445df4f9b17ad2b417be66c3710
|
||||||
|
|
||||||
|
key:
|
||||||
|
2b7e151628aed2a6abf7158809cf4f3c
|
||||||
|
|
||||||
|
resulting cipher
|
||||||
|
3ad77bb40d7a3660a89ecaf32466ef97
|
||||||
|
f5d3d58503b9699de785895a96fdbaaf
|
||||||
|
43b1cd7f598ece23881b00e3ed030688
|
||||||
|
7b0c785e27e8ad3f8223207104725dd4
|
||||||
|
|
||||||
|
|
||||||
|
NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0)
|
||||||
|
You should pad the end of the string with zeros if this is not the case.
|
||||||
|
For AES192/256 the key size is proportionally larger.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Includes: */
|
||||||
|
/*****************************************************************************/
|
||||||
|
#include <string.h> // CBC mode, for memset
|
||||||
|
#include "aes.h"
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Defines: */
|
||||||
|
/*****************************************************************************/
|
||||||
|
// The number of columns comprising a state in AES. This is a constant in AES. Value=4
|
||||||
|
#define Nb 4
|
||||||
|
|
||||||
|
#if defined(AES256) && (AES256 == 1)
|
||||||
|
#define Nk 8
|
||||||
|
#define Nr 14
|
||||||
|
#elif defined(AES192) && (AES192 == 1)
|
||||||
|
#define Nk 6
|
||||||
|
#define Nr 12
|
||||||
|
#else
|
||||||
|
#define Nk 4 // The number of 32 bit words in a key.
|
||||||
|
#define Nr 10 // The number of rounds in AES Cipher.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// jcallan@github points out that declaring Multiply as a function
|
||||||
|
// reduces code size considerably with the Keil ARM compiler.
|
||||||
|
// See this link for more information: https://github.com/kokke/tiny-AES-C/pull/3
|
||||||
|
#ifndef MULTIPLY_AS_A_FUNCTION
|
||||||
|
#define MULTIPLY_AS_A_FUNCTION 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Private variables: */
|
||||||
|
/*****************************************************************************/
|
||||||
|
// state - array holding the intermediate results during decryption.
|
||||||
|
typedef uint8_t state_t[4][4];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM
|
||||||
|
// The numbers below can be computed dynamically trading ROM for RAM -
|
||||||
|
// This can be useful in (embedded) bootloader applications, where ROM is often limited.
|
||||||
|
static const uint8_t sbox[256] =
|
||||||
|
{
|
||||||
|
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||||
|
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||||
|
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||||
|
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||||
|
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||||
|
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||||
|
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||||
|
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||||
|
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||||
|
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||||
|
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||||
|
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||||
|
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||||
|
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||||
|
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||||
|
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||||
|
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t rsbox[256] =
|
||||||
|
{
|
||||||
|
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||||
|
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||||
|
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||||
|
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||||
|
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||||
|
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||||
|
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||||
|
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||||
|
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||||
|
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||||
|
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||||
|
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||||
|
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||||
|
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||||
|
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||||
|
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
||||||
|
};
|
||||||
|
|
||||||
|
// The round constant word array, Rcon[i], contains the values given by
|
||||||
|
// x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8)
|
||||||
|
static const uint8_t Rcon[11] =
|
||||||
|
{
|
||||||
|
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12),
|
||||||
|
* that you can remove most of the elements in the Rcon array, because they are unused.
|
||||||
|
*
|
||||||
|
* From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon
|
||||||
|
*
|
||||||
|
* "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed),
|
||||||
|
* up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm."
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Private functions: */
|
||||||
|
/*****************************************************************************/
|
||||||
|
/*
|
||||||
|
static uint8_t getSBoxValue(uint8_t num)
|
||||||
|
{
|
||||||
|
return sbox[num];
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#define getSBoxValue(num) (sbox[(num)])
|
||||||
|
/*
|
||||||
|
static uint8_t getSBoxInvert(uint8_t num)
|
||||||
|
{
|
||||||
|
return rsbox[num];
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#define getSBoxInvert(num) (rsbox[(num)])
|
||||||
|
|
||||||
|
// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states.
|
||||||
|
static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
|
||||||
|
{
|
||||||
|
unsigned i, j, k;
|
||||||
|
uint8_t tempa[4]; // Used for the column/row operations
|
||||||
|
|
||||||
|
// The first round key is the key itself.
|
||||||
|
for (i = 0; i < Nk; ++i)
|
||||||
|
{
|
||||||
|
RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
|
||||||
|
RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
|
||||||
|
RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
|
||||||
|
RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
// All other round keys are found from the previous round keys.
|
||||||
|
for (i = Nk; i < Nb * (Nr + 1); ++i)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
k = (i - 1) * 4;
|
||||||
|
tempa[0] = RoundKey[k + 0];
|
||||||
|
tempa[1] = RoundKey[k + 1];
|
||||||
|
tempa[2] = RoundKey[k + 2];
|
||||||
|
tempa[3] = RoundKey[k + 3];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i % Nk == 0)
|
||||||
|
{
|
||||||
|
// This function shifts the 4 bytes in a word to the left once.
|
||||||
|
// [a0,a1,a2,a3] becomes [a1,a2,a3,a0]
|
||||||
|
|
||||||
|
// Function RotWord()
|
||||||
|
{
|
||||||
|
const uint8_t u8tmp = tempa[0];
|
||||||
|
tempa[0] = tempa[1];
|
||||||
|
tempa[1] = tempa[2];
|
||||||
|
tempa[2] = tempa[3];
|
||||||
|
tempa[3] = u8tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubWord() is a function that takes a four-byte input word and
|
||||||
|
// applies the S-box to each of the four bytes to produce an output word.
|
||||||
|
|
||||||
|
// Function Subword()
|
||||||
|
{
|
||||||
|
tempa[0] = getSBoxValue(tempa[0]);
|
||||||
|
tempa[1] = getSBoxValue(tempa[1]);
|
||||||
|
tempa[2] = getSBoxValue(tempa[2]);
|
||||||
|
tempa[3] = getSBoxValue(tempa[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
tempa[0] = tempa[0] ^ Rcon[i / Nk];
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(AES256) && (AES256 == 1)
|
||||||
|
|
||||||
|
if (i % Nk == 4)
|
||||||
|
{
|
||||||
|
// Function Subword()
|
||||||
|
{
|
||||||
|
tempa[0] = getSBoxValue(tempa[0]);
|
||||||
|
tempa[1] = getSBoxValue(tempa[1]);
|
||||||
|
tempa[2] = getSBoxValue(tempa[2]);
|
||||||
|
tempa[3] = getSBoxValue(tempa[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
j = i * 4;
|
||||||
|
k = (i - Nk) * 4;
|
||||||
|
RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
|
||||||
|
RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
|
||||||
|
RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
|
||||||
|
RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key)
|
||||||
|
{
|
||||||
|
KeyExpansion(ctx->RoundKey, key);
|
||||||
|
}
|
||||||
|
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
|
||||||
|
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv)
|
||||||
|
{
|
||||||
|
KeyExpansion(ctx->RoundKey, key);
|
||||||
|
memcpy (ctx->Iv, iv, AES_BLOCKLEN);
|
||||||
|
}
|
||||||
|
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv)
|
||||||
|
{
|
||||||
|
memcpy (ctx->Iv, iv, AES_BLOCKLEN);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// This function adds the round key to state.
|
||||||
|
// The round key is added to the state by an XOR function.
|
||||||
|
static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey)
|
||||||
|
{
|
||||||
|
uint8_t i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 4; ++j)
|
||||||
|
{
|
||||||
|
(*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The SubBytes Function Substitutes the values in the
|
||||||
|
// state matrix with values in an S-box.
|
||||||
|
static void SubBytes(state_t* state)
|
||||||
|
{
|
||||||
|
uint8_t i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 4; ++j)
|
||||||
|
{
|
||||||
|
(*state)[j][i] = getSBoxValue((*state)[j][i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The ShiftRows() function shifts the rows in the state to the left.
|
||||||
|
// Each row is shifted with different offset.
|
||||||
|
// Offset = Row number. So the first row is not shifted.
|
||||||
|
static void ShiftRows(state_t* state)
|
||||||
|
{
|
||||||
|
uint8_t temp;
|
||||||
|
|
||||||
|
// Rotate first row 1 columns to left
|
||||||
|
temp = (*state)[0][1];
|
||||||
|
(*state)[0][1] = (*state)[1][1];
|
||||||
|
(*state)[1][1] = (*state)[2][1];
|
||||||
|
(*state)[2][1] = (*state)[3][1];
|
||||||
|
(*state)[3][1] = temp;
|
||||||
|
|
||||||
|
// Rotate second row 2 columns to left
|
||||||
|
temp = (*state)[0][2];
|
||||||
|
(*state)[0][2] = (*state)[2][2];
|
||||||
|
(*state)[2][2] = temp;
|
||||||
|
|
||||||
|
temp = (*state)[1][2];
|
||||||
|
(*state)[1][2] = (*state)[3][2];
|
||||||
|
(*state)[3][2] = temp;
|
||||||
|
|
||||||
|
// Rotate third row 3 columns to left
|
||||||
|
temp = (*state)[0][3];
|
||||||
|
(*state)[0][3] = (*state)[3][3];
|
||||||
|
(*state)[3][3] = (*state)[2][3];
|
||||||
|
(*state)[2][3] = (*state)[1][3];
|
||||||
|
(*state)[1][3] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t xtime(uint8_t x)
|
||||||
|
{
|
||||||
|
return ((x << 1) ^ (((x >> 7) & 1) * 0x1b));
|
||||||
|
}
|
||||||
|
|
||||||
|
// MixColumns function mixes the columns of the state matrix
|
||||||
|
static void MixColumns(state_t* state)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
uint8_t Tmp, Tm, t;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
t = (*state)[i][0];
|
||||||
|
Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ;
|
||||||
|
Tm = (*state)[i][0] ^ (*state)[i][1] ;
|
||||||
|
Tm = xtime(Tm);
|
||||||
|
(*state)[i][0] ^= Tm ^ Tmp ;
|
||||||
|
Tm = (*state)[i][1] ^ (*state)[i][2] ;
|
||||||
|
Tm = xtime(Tm);
|
||||||
|
(*state)[i][1] ^= Tm ^ Tmp ;
|
||||||
|
Tm = (*state)[i][2] ^ (*state)[i][3] ;
|
||||||
|
Tm = xtime(Tm);
|
||||||
|
(*state)[i][2] ^= Tm ^ Tmp ;
|
||||||
|
Tm = (*state)[i][3] ^ t ;
|
||||||
|
Tm = xtime(Tm);
|
||||||
|
(*state)[i][3] ^= Tm ^ Tmp ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply is used to multiply numbers in the field GF(2^8)
|
||||||
|
// Note: The last call to xtime() is unneeded, but often ends up generating a smaller binary
|
||||||
|
// The compiler seems to be able to vectorize the operation better this way.
|
||||||
|
// See https://github.com/kokke/tiny-AES-c/pull/34
|
||||||
|
#if MULTIPLY_AS_A_FUNCTION
|
||||||
|
static uint8_t Multiply(uint8_t x, uint8_t y)
|
||||||
|
{
|
||||||
|
return (((y & 1) * x) ^
|
||||||
|
((y >> 1 & 1) * xtime(x)) ^
|
||||||
|
((y >> 2 & 1) * xtime(xtime(x))) ^
|
||||||
|
((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^
|
||||||
|
((y >> 4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define Multiply(x, y) \
|
||||||
|
( ((y & 1) * x) ^ \
|
||||||
|
((y>>1 & 1) * xtime(x)) ^ \
|
||||||
|
((y>>2 & 1) * xtime(xtime(x))) ^ \
|
||||||
|
((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \
|
||||||
|
((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
|
||||||
|
// MixColumns function mixes the columns of the state matrix.
|
||||||
|
// The method used to multiply may be difficult to understand for the inexperienced.
|
||||||
|
// Please use the references to gain more information.
|
||||||
|
static void InvMixColumns(state_t* state)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint8_t a, b, c, d;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
a = (*state)[i][0];
|
||||||
|
b = (*state)[i][1];
|
||||||
|
c = (*state)[i][2];
|
||||||
|
d = (*state)[i][3];
|
||||||
|
|
||||||
|
(*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
|
||||||
|
(*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
|
||||||
|
(*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
|
||||||
|
(*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The SubBytes Function Substitutes the values in the
|
||||||
|
// state matrix with values in an S-box.
|
||||||
|
static void InvSubBytes(state_t* state)
|
||||||
|
{
|
||||||
|
uint8_t i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 4; ++j)
|
||||||
|
{
|
||||||
|
(*state)[j][i] = getSBoxInvert((*state)[j][i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InvShiftRows(state_t* state)
|
||||||
|
{
|
||||||
|
uint8_t temp;
|
||||||
|
|
||||||
|
// Rotate first row 1 columns to right
|
||||||
|
temp = (*state)[3][1];
|
||||||
|
(*state)[3][1] = (*state)[2][1];
|
||||||
|
(*state)[2][1] = (*state)[1][1];
|
||||||
|
(*state)[1][1] = (*state)[0][1];
|
||||||
|
(*state)[0][1] = temp;
|
||||||
|
|
||||||
|
// Rotate second row 2 columns to right
|
||||||
|
temp = (*state)[0][2];
|
||||||
|
(*state)[0][2] = (*state)[2][2];
|
||||||
|
(*state)[2][2] = temp;
|
||||||
|
|
||||||
|
temp = (*state)[1][2];
|
||||||
|
(*state)[1][2] = (*state)[3][2];
|
||||||
|
(*state)[3][2] = temp;
|
||||||
|
|
||||||
|
// Rotate third row 3 columns to right
|
||||||
|
temp = (*state)[0][3];
|
||||||
|
(*state)[0][3] = (*state)[1][3];
|
||||||
|
(*state)[1][3] = (*state)[2][3];
|
||||||
|
(*state)[2][3] = (*state)[3][3];
|
||||||
|
(*state)[3][3] = temp;
|
||||||
|
}
|
||||||
|
#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
|
||||||
|
|
||||||
|
// Cipher is the main function that encrypts the PlainText.
|
||||||
|
static void Cipher(state_t* state, const uint8_t* RoundKey)
|
||||||
|
{
|
||||||
|
uint8_t round = 0;
|
||||||
|
|
||||||
|
// Add the First round key to the state before starting the rounds.
|
||||||
|
AddRoundKey(0, state, RoundKey);
|
||||||
|
|
||||||
|
// There will be Nr rounds.
|
||||||
|
// The first Nr-1 rounds are identical.
|
||||||
|
// These Nr rounds are executed in the loop below.
|
||||||
|
// Last one without MixColumns()
|
||||||
|
for (round = 1; ; ++round)
|
||||||
|
{
|
||||||
|
SubBytes(state);
|
||||||
|
ShiftRows(state);
|
||||||
|
|
||||||
|
if (round == Nr)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
MixColumns(state);
|
||||||
|
AddRoundKey(round, state, RoundKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add round key to last round
|
||||||
|
AddRoundKey(Nr, state, RoundKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
|
||||||
|
static void InvCipher(state_t* state, const uint8_t* RoundKey)
|
||||||
|
{
|
||||||
|
uint8_t round = 0;
|
||||||
|
|
||||||
|
// Add the First round key to the state before starting the rounds.
|
||||||
|
AddRoundKey(Nr, state, RoundKey);
|
||||||
|
|
||||||
|
// There will be Nr rounds.
|
||||||
|
// The first Nr-1 rounds are identical.
|
||||||
|
// These Nr rounds are executed in the loop below.
|
||||||
|
// Last one without InvMixColumn()
|
||||||
|
for (round = (Nr - 1); ; --round)
|
||||||
|
{
|
||||||
|
InvShiftRows(state);
|
||||||
|
InvSubBytes(state);
|
||||||
|
AddRoundKey(round, state, RoundKey);
|
||||||
|
|
||||||
|
if (round == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
InvMixColumns(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Public functions: */
|
||||||
|
/*****************************************************************************/
|
||||||
|
#if defined(ECB) && (ECB == 1)
|
||||||
|
|
||||||
|
|
||||||
|
void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf)
|
||||||
|
{
|
||||||
|
// The next function call encrypts the PlainText with the Key using AES algorithm.
|
||||||
|
Cipher((state_t*)buf, ctx->RoundKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf)
|
||||||
|
{
|
||||||
|
// The next function call decrypts the PlainText with the Key using AES algorithm.
|
||||||
|
InvCipher((state_t*)buf, ctx->RoundKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // #if defined(ECB) && (ECB == 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(CBC) && (CBC == 1)
|
||||||
|
|
||||||
|
|
||||||
|
static void XorWithIv(uint8_t* buf, const uint8_t* Iv)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size
|
||||||
|
{
|
||||||
|
buf[i] ^= Iv[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length)
|
||||||
|
{
|
||||||
|
uintptr_t i;
|
||||||
|
uint8_t* Iv = ctx->Iv;
|
||||||
|
|
||||||
|
for (i = 0; i < length; i += AES_BLOCKLEN)
|
||||||
|
{
|
||||||
|
XorWithIv(buf, Iv);
|
||||||
|
Cipher((state_t*)buf, ctx->RoundKey);
|
||||||
|
Iv = buf;
|
||||||
|
buf += AES_BLOCKLEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store Iv in ctx for next call */
|
||||||
|
memcpy(ctx->Iv, Iv, AES_BLOCKLEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length)
|
||||||
|
{
|
||||||
|
uintptr_t i;
|
||||||
|
uint8_t storeNextIv[AES_BLOCKLEN];
|
||||||
|
|
||||||
|
for (i = 0; i < length; i += AES_BLOCKLEN)
|
||||||
|
{
|
||||||
|
memcpy(storeNextIv, buf, AES_BLOCKLEN);
|
||||||
|
InvCipher((state_t*)buf, ctx->RoundKey);
|
||||||
|
XorWithIv(buf, ctx->Iv);
|
||||||
|
memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN);
|
||||||
|
buf += AES_BLOCKLEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // #if defined(CBC) && (CBC == 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(CTR) && (CTR == 1)
|
||||||
|
|
||||||
|
/* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */
|
||||||
|
void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length)
|
||||||
|
{
|
||||||
|
uint8_t buffer[AES_BLOCKLEN];
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
int bi;
|
||||||
|
|
||||||
|
for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi)
|
||||||
|
{
|
||||||
|
if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */
|
||||||
|
{
|
||||||
|
|
||||||
|
memcpy(buffer, ctx->Iv, AES_BLOCKLEN);
|
||||||
|
Cipher((state_t*)buffer, ctx->RoundKey);
|
||||||
|
|
||||||
|
/* Increment Iv and handle overflow */
|
||||||
|
for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi)
|
||||||
|
{
|
||||||
|
/* inc will overflow */
|
||||||
|
if (ctx->Iv[bi] == 255)
|
||||||
|
{
|
||||||
|
ctx->Iv[bi] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->Iv[bi] += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bi = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[i] = (buf[i] ^ buffer[bi]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // #if defined(CTR) && (CTR == 1)
|
||||||
|
|
||||||
90
components/knx/src/knx/aes.h
Normal file
90
components/knx/src/knx/aes.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#ifndef _AES_H_
|
||||||
|
#define _AES_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// #define the macros below to 1/0 to enable/disable the mode of operation.
|
||||||
|
//
|
||||||
|
// CBC enables AES encryption in CBC-mode of operation.
|
||||||
|
// CTR enables encryption in counter-mode.
|
||||||
|
// ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously.
|
||||||
|
|
||||||
|
// The #ifndef-guard allows it to be configured before #include'ing or at compile time.
|
||||||
|
#ifndef CBC
|
||||||
|
#define CBC 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ECB
|
||||||
|
#define ECB 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CTR
|
||||||
|
#define CTR 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define AES128 1
|
||||||
|
//#define AES192 1
|
||||||
|
//#define AES256 1
|
||||||
|
|
||||||
|
#define AES_BLOCKLEN 16 // Block length in bytes - AES is 128b block only
|
||||||
|
|
||||||
|
#if defined(AES256) && (AES256 == 1)
|
||||||
|
#define AES_KEYLEN 32
|
||||||
|
#define AES_keyExpSize 240
|
||||||
|
#elif defined(AES192) && (AES192 == 1)
|
||||||
|
#define AES_KEYLEN 24
|
||||||
|
#define AES_keyExpSize 208
|
||||||
|
#else
|
||||||
|
#define AES_KEYLEN 16 // Key length in bytes
|
||||||
|
#define AES_keyExpSize 176
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct AES_ctx
|
||||||
|
{
|
||||||
|
uint8_t RoundKey[AES_keyExpSize];
|
||||||
|
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
|
||||||
|
uint8_t Iv[AES_BLOCKLEN];
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
|
||||||
|
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
|
||||||
|
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
|
||||||
|
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ECB) && (ECB == 1)
|
||||||
|
// buffer size is exactly AES_BLOCKLEN bytes;
|
||||||
|
// you need only AES_init_ctx as IV is not used in ECB
|
||||||
|
// NB: ECB is considered insecure for most uses
|
||||||
|
void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf);
|
||||||
|
void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf);
|
||||||
|
|
||||||
|
#endif // #if defined(ECB) && (ECB == !)
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(CBC) && (CBC == 1)
|
||||||
|
// buffer size MUST be mutile of AES_BLOCKLEN;
|
||||||
|
// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
|
||||||
|
// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv()
|
||||||
|
// no IV should ever be reused with the same key
|
||||||
|
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
|
||||||
|
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
|
||||||
|
|
||||||
|
#endif // #if defined(CBC) && (CBC == 1)
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(CTR) && (CTR == 1)
|
||||||
|
|
||||||
|
// Same function for encrypting as for decrypting.
|
||||||
|
// IV is incremented for every block, and used after encryption as XOR-compliment for output
|
||||||
|
// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
|
||||||
|
// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv()
|
||||||
|
// no IV should ever be reused with the same key
|
||||||
|
void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
|
||||||
|
|
||||||
|
#endif // #if defined(CTR) && (CTR == 1)
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _AES_H_
|
||||||
12
components/knx/src/knx/aes.hpp
Normal file
12
components/knx/src/knx/aes.hpp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef _AES_HPP_
|
||||||
|
#define _AES_HPP_
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
#error Do not include the hpp header in a c project!
|
||||||
|
#endif //__cplusplus
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "aes.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //_AES_HPP_
|
||||||
59
components/knx/src/knx/apdu.cpp
Normal file
59
components/knx/src/knx/apdu.cpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#include "apdu.h"
|
||||||
|
#include "cemi_frame.h"
|
||||||
|
#include "bits.h"
|
||||||
|
|
||||||
|
APDU::APDU(uint8_t* data, CemiFrame& frame): _data(data), _frame(frame)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ApduType APDU::type()
|
||||||
|
{
|
||||||
|
uint16_t apci;
|
||||||
|
apci = getWord(_data);
|
||||||
|
popWord(apci, _data);
|
||||||
|
apci &= 0x3ff;
|
||||||
|
|
||||||
|
if ((apci >> 6) < 11 && (apci >> 6) != 7) //short apci
|
||||||
|
apci &= 0x3c0;
|
||||||
|
|
||||||
|
return (ApduType)apci;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APDU::type(ApduType atype)
|
||||||
|
{
|
||||||
|
// ApduType is in big endian so convert to host first, pushWord converts back
|
||||||
|
pushWord((uint16_t)atype, _data);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* APDU::data()
|
||||||
|
{
|
||||||
|
return _data + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CemiFrame& APDU::frame()
|
||||||
|
{
|
||||||
|
return _frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t APDU::length() const
|
||||||
|
{
|
||||||
|
return _frame.npdu().octetCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
void APDU::printPDU()
|
||||||
|
{
|
||||||
|
print("APDU: ");
|
||||||
|
print(type(), HEX);
|
||||||
|
print(" ");
|
||||||
|
print(_data[0] & 0x3, HEX);
|
||||||
|
|
||||||
|
for (uint8_t i = 1; i < length() + 1; ++i)
|
||||||
|
{
|
||||||
|
if (i)
|
||||||
|
print(" ");
|
||||||
|
|
||||||
|
print(_data[i], HEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
println();
|
||||||
|
}
|
||||||
53
components/knx/src/knx/apdu.h
Normal file
53
components/knx/src/knx/apdu.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "knx_types.h"
|
||||||
|
|
||||||
|
class CemiFrame;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents an Application Protocol Data Unit. It is part of a CemiFrame.
|
||||||
|
*/
|
||||||
|
class APDU
|
||||||
|
{
|
||||||
|
friend class CemiFrame;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Get the type of the APDU.
|
||||||
|
*/
|
||||||
|
ApduType type();
|
||||||
|
/**
|
||||||
|
* Set the type of the APDU.
|
||||||
|
*/
|
||||||
|
void type(ApduType atype);
|
||||||
|
/**
|
||||||
|
* Get a pointer to the data.
|
||||||
|
*/
|
||||||
|
uint8_t* data();
|
||||||
|
/**
|
||||||
|
* Get the CemiFrame this APDU is part of.
|
||||||
|
*/
|
||||||
|
CemiFrame& frame();
|
||||||
|
/**
|
||||||
|
* Get the length of the APDU. (This is actually the octet count of the NPDU.)
|
||||||
|
*/
|
||||||
|
uint8_t length() const;
|
||||||
|
/**
|
||||||
|
* Print the contents of the APDU to console.
|
||||||
|
*/
|
||||||
|
void printPDU();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* The constructor.
|
||||||
|
* @param data The data of the APDU. Encoding depends on the ::ApduType. The class doesn't
|
||||||
|
* take possession of this pointer.
|
||||||
|
* @param frame The CemiFrame this APDU is part of.
|
||||||
|
*/
|
||||||
|
APDU(uint8_t* data, CemiFrame& frame);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t* _data = 0;
|
||||||
|
CemiFrame& _frame;
|
||||||
|
};
|
||||||
1546
components/knx/src/knx/application_layer.cpp
Normal file
1546
components/knx/src/knx/application_layer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
228
components/knx/src/knx/application_layer.h
Normal file
228
components/knx/src/knx/application_layer.h
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "knx_types.h"
|
||||||
|
#include "apdu.h"
|
||||||
|
|
||||||
|
class AssociationTableObject;
|
||||||
|
class BusAccessUnit;
|
||||||
|
class TransportLayer;
|
||||||
|
/**
|
||||||
|
* This is an implementation of the application layer as specified in @cite knx:3/5/1.
|
||||||
|
* It provides methods for the BusAccessUnit to do different things and translates this
|
||||||
|
* call to an APDU and calls the correct method of the TransportLayer.
|
||||||
|
* It also takes calls from TransportLayer, decodes the submitted APDU and calls the corresponding
|
||||||
|
* methods of the BusAccessUnit class.
|
||||||
|
*/
|
||||||
|
class ApplicationLayer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* The constructor.
|
||||||
|
* @param assocTable The AssociationTable is used to translate between asap (i.e. group objects) and group addresses.
|
||||||
|
* @param bau methods are called here depending of the content of the APDU
|
||||||
|
*/
|
||||||
|
ApplicationLayer(BusAccessUnit& bau);
|
||||||
|
/**
|
||||||
|
* Assigns the TransportLayer to which encoded APDU are submitted to.
|
||||||
|
*/
|
||||||
|
void transportLayer(TransportLayer& layer);
|
||||||
|
|
||||||
|
void associationTableObject(AssociationTableObject& assocTable);
|
||||||
|
|
||||||
|
// from transport layer
|
||||||
|
// Note: without data secure feature, the application layer is just used with SecurityControl.dataSecurity = None
|
||||||
|
// hooks that can be implemented by derived class (e.g. SecureApplicationLayer)
|
||||||
|
|
||||||
|
#pragma region Transport - Layer - Callbacks
|
||||||
|
/**
|
||||||
|
* Somebody send us an APDU via multicast communication. See 3.2 of @cite knx:3/3/4.
|
||||||
|
* See also ApplicationLayer::dataGroupConfirm and TransportLayer::dataGroupRequest.
|
||||||
|
* This method is called by the TransportLayer.
|
||||||
|
*
|
||||||
|
* @param tsap used the find the correct GroupObject with the help of the AssociationTableObject.
|
||||||
|
* See 3.1.1 of @cite knx:3/3/7
|
||||||
|
*
|
||||||
|
* @param apdu The submitted APDU.
|
||||||
|
*
|
||||||
|
* @param priority The ::Priority of the received request.
|
||||||
|
*
|
||||||
|
* @param hopType Should routing be endless or should the NetworkLayer::hopCount be used? See also ::HopCountType.
|
||||||
|
*/
|
||||||
|
virtual void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu);
|
||||||
|
/**
|
||||||
|
* Report the status of an APDU that we sent via multicast communication back to us. See 3.2 of @cite knx:3/3/4.
|
||||||
|
* See also ApplicationLayer::dataGroupConfirm and TransportLayer::dataGroupRequest. This method is called by
|
||||||
|
* the TransportLayer.
|
||||||
|
*
|
||||||
|
* @param tsap used the find the correct GroupObject with the help of the AssociationTableObject.
|
||||||
|
* See 3.1.1 of @cite knx:3/3/7
|
||||||
|
*
|
||||||
|
* @param apdu The submitted APDU.
|
||||||
|
*
|
||||||
|
* @param priority The ::Priority of the received request.
|
||||||
|
*
|
||||||
|
* @param hopType Should routing be endless or should the NetworkLayer::hopCount be used? See also ::HopCountType.
|
||||||
|
*
|
||||||
|
* @param status Was the request successful?
|
||||||
|
*
|
||||||
|
* @param ack Did we want a DataLinkLayer acknowledgement? See ::AckType.
|
||||||
|
*/
|
||||||
|
virtual void dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status);
|
||||||
|
virtual void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu);
|
||||||
|
virtual void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, bool status);
|
||||||
|
virtual void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu);
|
||||||
|
virtual void dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, bool status);
|
||||||
|
virtual void dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu);
|
||||||
|
virtual void dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status);
|
||||||
|
virtual void dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu);
|
||||||
|
virtual void dataConnectedConfirm(uint16_t tsap);
|
||||||
|
void connectIndication(uint16_t tsap);
|
||||||
|
void connectConfirm(uint16_t destination, uint16_t tsap, bool status);
|
||||||
|
void disconnectIndication(uint16_t tsap);
|
||||||
|
void disconnectConfirm(Priority priority, uint16_t tsap, bool status);
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region from bau
|
||||||
|
void groupValueReadRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl);
|
||||||
|
void groupValueReadResponse(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength);
|
||||||
|
void groupValueWriteRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength);
|
||||||
|
void individualAddressWriteRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress);
|
||||||
|
void individualAddressReadRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl);
|
||||||
|
void individualAddressReadResponse(AckType ack, HopCountType hopType, const SecurityControl& secCtrl);
|
||||||
|
void individualAddressSerialNumberReadRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber);
|
||||||
|
void individualAddressSerialNumberReadResponse(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber,
|
||||||
|
uint16_t domainAddress);
|
||||||
|
void individualAddressSerialNumberWriteRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber,
|
||||||
|
uint16_t newaddress);
|
||||||
|
void deviceDescriptorReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t descriptorType);
|
||||||
|
void deviceDescriptorReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t descriptorType, uint8_t* deviceDescriptor);
|
||||||
|
void connectRequest(uint16_t destination, Priority priority);
|
||||||
|
void disconnectRequest(Priority priority);
|
||||||
|
bool isConnected();
|
||||||
|
void restartRequest(AckType ack, Priority priority, HopCountType hopType, const SecurityControl& secCtrl);
|
||||||
|
void restartResponse(AckType ack, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t errorCode, uint16_t processTime);
|
||||||
|
void propertyValueReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex);
|
||||||
|
void propertyValueReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length);
|
||||||
|
void propertyValueExtReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length);
|
||||||
|
void propertyValueExtWriteConResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t returnCode);
|
||||||
|
void propertyValueWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length);
|
||||||
|
void adcReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t channelNr, uint8_t readCount, int16_t value);
|
||||||
|
void functionPropertyStateResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t objectIndex, uint8_t propertyId, uint8_t* resultData, uint8_t resultLength);
|
||||||
|
void functionPropertyExtStateResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint16_t objectType, uint8_t objectInstance, uint16_t propertyId, uint8_t* resultData, uint8_t resultLength);
|
||||||
|
void propertyDescriptionReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex);
|
||||||
|
void propertyDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type,
|
||||||
|
uint16_t maxNumberOfElements, uint8_t access);
|
||||||
|
void propertyExtDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint16_t objectType, uint16_t objectInstance, uint16_t propertyId, uint16_t propertyIndex, uint8_t descriptionType, bool writeEnable, uint8_t type,
|
||||||
|
uint16_t maxNumberOfElements, uint8_t access);
|
||||||
|
void memoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress);
|
||||||
|
void memoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* data);
|
||||||
|
void memoryRouterReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* data);
|
||||||
|
void memoryRoutingTableReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* data);
|
||||||
|
void memoryExtReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ReturnCodes code, uint8_t number,
|
||||||
|
uint32_t memoryAddress, uint8_t* data);
|
||||||
|
void memoryExtWriteResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ReturnCodes code, uint8_t number,
|
||||||
|
uint32_t memoryAddress, uint8_t* memoryData);
|
||||||
|
void memoryWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* data);
|
||||||
|
void userMemoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress);
|
||||||
|
void userMemoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress, uint8_t* memoryData);
|
||||||
|
void userMemoryWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress, uint8_t* memoryData);
|
||||||
|
void userManufacturerInfoReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl);
|
||||||
|
void userManufacturerInfoReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t* info);
|
||||||
|
void authorizeRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key);
|
||||||
|
void authorizeResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level);
|
||||||
|
void keyWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, uint32_t key);
|
||||||
|
void keyWriteResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level);
|
||||||
|
|
||||||
|
void systemNetworkParameterReadResponse(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType,
|
||||||
|
uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength,
|
||||||
|
uint8_t* testResult, uint16_t testResultLength);
|
||||||
|
void domainAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA,
|
||||||
|
const uint8_t* knxSerialNumber);
|
||||||
|
void IndividualAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* domainAddress,
|
||||||
|
const uint8_t* knxSerialNumber);
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
protected:
|
||||||
|
#pragma region hooks
|
||||||
|
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,
|
||||||
|
APDU& apdu, const SecurityControl& secCtrl, bool status);
|
||||||
|
void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl& secCtrl);
|
||||||
|
void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl, bool status);
|
||||||
|
void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl& secCtrl);
|
||||||
|
void dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl, bool status);
|
||||||
|
void dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl& secCtrl);
|
||||||
|
void dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl, bool status);
|
||||||
|
void dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl);
|
||||||
|
void dataConnectedConfirm(uint16_t tsap, const SecurityControl& secCtrl);
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
// to transport layer
|
||||||
|
virtual void dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl);
|
||||||
|
virtual void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl);
|
||||||
|
virtual void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl);
|
||||||
|
virtual void dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu, const SecurityControl& secCtrl);
|
||||||
|
virtual void dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu, const SecurityControl& secCtrl); // apdu must be valid until it was confirmed
|
||||||
|
|
||||||
|
uint16_t getConnectedTsasp()
|
||||||
|
{
|
||||||
|
return _connectedTsap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protected: we need to access it in derived class SecureApplicationLayer
|
||||||
|
TransportLayer* _transportLayer = 0;
|
||||||
|
|
||||||
|
static const SecurityControl noSecurity;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void propertyDataSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data,
|
||||||
|
uint8_t length);
|
||||||
|
void propertyExtDataSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length);
|
||||||
|
void memorySend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* memoryData);
|
||||||
|
// Added EC
|
||||||
|
void memoryRouterSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* memoryData);
|
||||||
|
void memoryRoutingTableSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* memoryData);
|
||||||
|
//
|
||||||
|
void userMemorySend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t number, uint32_t memoryAddress, uint8_t* memoryData);
|
||||||
|
void groupValueSend(ApduType type, AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t& dataLength);
|
||||||
|
void individualIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl);
|
||||||
|
void individualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl, bool status);
|
||||||
|
void individualSend(AckType ack, HopCountType hopType, Priority priority, uint16_t asap, APDU& apdu, const SecurityControl& secCtrl);
|
||||||
|
|
||||||
|
uint16_t _savedAsapReadRequest = 0;
|
||||||
|
uint16_t _savedAsapWriteRequest = 0;
|
||||||
|
uint16_t _savedAsapResponse = 0;
|
||||||
|
AssociationTableObject* _assocTable = nullptr;
|
||||||
|
BusAccessUnit& _bau;
|
||||||
|
|
||||||
|
int32_t _connectedTsap = -1;
|
||||||
|
};
|
||||||
99
components/knx/src/knx/application_program_object.cpp
Normal file
99
components/knx/src/knx/application_program_object.cpp
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#include "application_program_object.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include "data_property.h"
|
||||||
|
#include "callback_property.h"
|
||||||
|
#include "dptconvert.h"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
ApplicationProgramObject::ApplicationProgramObject(Memory& memory)
|
||||||
|
#if MASK_VERSION == 0x091A
|
||||||
|
: TableObject(memory, 0x0100, 0x0100)
|
||||||
|
#else
|
||||||
|
: TableObject(memory)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
Property* properties[] =
|
||||||
|
{
|
||||||
|
new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_APPLICATION_PROG),
|
||||||
|
new DataProperty(PID_PROG_VERSION, true, PDT_GENERIC_05, 1, ReadLv3 | WriteLv3),
|
||||||
|
new CallbackProperty<ApplicationProgramObject>(this, PID_PEI_TYPE, false, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv0,
|
||||||
|
[](ApplicationProgramObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t {
|
||||||
|
if (start == 0)
|
||||||
|
{
|
||||||
|
uint16_t currentNoOfElements = 1;
|
||||||
|
pushWord(currentNoOfElements, data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
data[0] = 0;
|
||||||
|
return 1;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
TableObject::initializeProperties(sizeof(properties), properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* ApplicationProgramObject::save(uint8_t* buffer)
|
||||||
|
{
|
||||||
|
uint8_t programVersion[5];
|
||||||
|
property(PID_PROG_VERSION)->read(programVersion);
|
||||||
|
buffer = pushByteArray(programVersion, 5, buffer);
|
||||||
|
|
||||||
|
return TableObject::save(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* ApplicationProgramObject::restore(const uint8_t* buffer)
|
||||||
|
{
|
||||||
|
uint8_t programVersion[5];
|
||||||
|
buffer = popByteArray(programVersion, 5, buffer);
|
||||||
|
property(PID_PROG_VERSION)->write(programVersion);
|
||||||
|
|
||||||
|
return TableObject::restore(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ApplicationProgramObject::saveSize()
|
||||||
|
{
|
||||||
|
return TableObject::saveSize() + 5; // sizeof(programVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* ApplicationProgramObject::data(uint32_t addr)
|
||||||
|
{
|
||||||
|
return TableObject::data() + addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ApplicationProgramObject::getByte(uint32_t addr)
|
||||||
|
{
|
||||||
|
return *(TableObject::data() + addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ApplicationProgramObject::getWord(uint32_t addr)
|
||||||
|
{
|
||||||
|
return ::getWord(TableObject::data() + addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ApplicationProgramObject::getInt(uint32_t addr)
|
||||||
|
{
|
||||||
|
return ::getInt(TableObject::data() + addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
double ApplicationProgramObject::getFloat(uint32_t addr, ParameterFloatEncodings encoding)
|
||||||
|
{
|
||||||
|
switch (encoding)
|
||||||
|
{
|
||||||
|
case Float_Enc_DPT9:
|
||||||
|
return float16FromPayload(TableObject::data() + addr, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Float_Enc_IEEE754Single:
|
||||||
|
return float32FromPayload(TableObject::data() + addr, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Float_Enc_IEEE754Double:
|
||||||
|
return float64FromPayload(TableObject::data() + addr, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
components/knx/src/knx/application_program_object.h
Normal file
18
components/knx/src/knx/application_program_object.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "table_object.h"
|
||||||
|
#include "bits.h"
|
||||||
|
|
||||||
|
class ApplicationProgramObject : public TableObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ApplicationProgramObject(Memory& memory);
|
||||||
|
uint8_t* save(uint8_t* buffer) override;
|
||||||
|
const uint8_t* restore(const uint8_t* buffer) override;
|
||||||
|
uint16_t saveSize() override;
|
||||||
|
uint8_t* data(uint32_t addr);
|
||||||
|
uint8_t getByte(uint32_t addr);
|
||||||
|
uint16_t getWord(uint32_t addr);
|
||||||
|
uint32_t getInt(uint32_t addr);
|
||||||
|
double getFloat(uint32_t addr, ParameterFloatEncodings encoding);
|
||||||
|
};
|
||||||
174
components/knx/src/knx/association_table_object.cpp
Normal file
174
components/knx/src/knx/association_table_object.cpp
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "association_table_object.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include "data_property.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
AssociationTableObject::AssociationTableObject(Memory& memory)
|
||||||
|
: TableObject(memory)
|
||||||
|
{
|
||||||
|
Property* properties[] =
|
||||||
|
{
|
||||||
|
new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_ASSOC_TABLE),
|
||||||
|
new DataProperty(PID_TABLE, false, PDT_GENERIC_04, 65535, ReadLv3 | WriteLv0) //FIXME: implement correctly
|
||||||
|
};
|
||||||
|
|
||||||
|
TableObject::initializeProperties(sizeof(properties), properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t AssociationTableObject::entryCount()
|
||||||
|
{
|
||||||
|
return ntohs(_tableData[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t AssociationTableObject::getTSAP(uint16_t idx)
|
||||||
|
{
|
||||||
|
if (idx >= entryCount())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return ntohs(_tableData[2 * idx + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t AssociationTableObject::getASAP(uint16_t idx)
|
||||||
|
{
|
||||||
|
if (idx >= entryCount())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return ntohs(_tableData[2 * idx + 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// after any table change the table is checked if it allows
|
||||||
|
// binary search access. If not, sortedEntryCount stays 0,
|
||||||
|
// otherwise sortedEntryCount represents size of bin search array
|
||||||
|
void AssociationTableObject::prepareBinarySearch()
|
||||||
|
{
|
||||||
|
sortedEntryCount = 0;
|
||||||
|
#ifdef USE_BINSEARCH
|
||||||
|
uint16_t lastASAP = 0;
|
||||||
|
uint16_t currentASAP = 0;
|
||||||
|
uint16_t lookupIdx = 0;
|
||||||
|
uint16_t lookupASAP = 0;
|
||||||
|
|
||||||
|
// we iterate through all ASAP
|
||||||
|
// the first n ASAP are sorted (strictly increasing number), these are assigning sending TSAP
|
||||||
|
// the remaining ASAP have to be all repetitions, otherwise we set sortedEntryCount to 0, which forces linear search
|
||||||
|
if (_tableData != nullptr)
|
||||||
|
{
|
||||||
|
for (uint16_t idx = 0; idx < entryCount(); idx++)
|
||||||
|
{
|
||||||
|
currentASAP = getASAP(idx);
|
||||||
|
|
||||||
|
if (sortedEntryCount)
|
||||||
|
{
|
||||||
|
// look if the remaining ASAP exist in the previously sorted list.
|
||||||
|
while (lookupIdx < sortedEntryCount)
|
||||||
|
{
|
||||||
|
lookupASAP = getASAP(lookupIdx);
|
||||||
|
|
||||||
|
if (currentASAP <= lookupASAP)
|
||||||
|
break; // while
|
||||||
|
else
|
||||||
|
lookupIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentASAP < lookupASAP || lookupIdx >= sortedEntryCount)
|
||||||
|
{
|
||||||
|
// a new ASAP found, we force linear search
|
||||||
|
sortedEntryCount = 0;
|
||||||
|
break; // for
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// check for strictly increasing ASAP
|
||||||
|
if (currentASAP > lastASAP)
|
||||||
|
lastASAP = currentASAP;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sortedEntryCount = idx; // last found index indicates end of sorted list
|
||||||
|
idx--; // current item has to be handled as remaining ASAP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// in case complete table is strictly increasing
|
||||||
|
if (lookupIdx == 0 && sortedEntryCount == 0)
|
||||||
|
sortedEntryCount = entryCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* AssociationTableObject::restore(const uint8_t* buffer)
|
||||||
|
{
|
||||||
|
buffer = TableObject::restore(buffer);
|
||||||
|
_tableData = (uint16_t*)data();
|
||||||
|
prepareBinarySearch();
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return type is int32 so that we can return uint16 and -1
|
||||||
|
int32_t AssociationTableObject::translateAsap(uint16_t asap)
|
||||||
|
{
|
||||||
|
// sortedEntryCount is determined in prepareBinarySearch()
|
||||||
|
// if ETS provides strictly increasing numbers for ASAP
|
||||||
|
// represents the size of the array to search
|
||||||
|
if (sortedEntryCount)
|
||||||
|
{
|
||||||
|
uint16_t low = 0;
|
||||||
|
uint16_t high = sortedEntryCount - 1;
|
||||||
|
|
||||||
|
while (low <= high)
|
||||||
|
{
|
||||||
|
uint16_t i = (low + high) / 2;
|
||||||
|
uint16_t asap_i = getASAP(i);
|
||||||
|
|
||||||
|
if (asap_i == asap)
|
||||||
|
return getTSAP(i);
|
||||||
|
|
||||||
|
if (asap_i > asap)
|
||||||
|
high = i - 1;
|
||||||
|
else
|
||||||
|
low = i + 1 ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if ASAP numbers are not strictly increasing linear seach is used
|
||||||
|
for (uint16_t i = 0; i < entryCount(); i++)
|
||||||
|
if (getASAP(i) == asap)
|
||||||
|
return getTSAP(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssociationTableObject::beforeStateChange(LoadState& newState)
|
||||||
|
{
|
||||||
|
TableObject::beforeStateChange(newState);
|
||||||
|
|
||||||
|
if (newState != LS_LOADED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_tableData = (uint16_t*)data();
|
||||||
|
prepareBinarySearch();
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t AssociationTableObject::nextAsap(uint16_t tsap, uint16_t& startIdx)
|
||||||
|
{
|
||||||
|
uint16_t entries = entryCount();
|
||||||
|
|
||||||
|
for (uint16_t i = startIdx; i < entries; i++)
|
||||||
|
{
|
||||||
|
startIdx = i + 1;
|
||||||
|
|
||||||
|
if (getTSAP(i) == tsap)
|
||||||
|
{
|
||||||
|
return getASAP(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
25
components/knx/src/knx/association_table_object.h
Normal file
25
components/knx/src/knx/association_table_object.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "table_object.h"
|
||||||
|
|
||||||
|
class AssociationTableObject : public TableObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AssociationTableObject(Memory& memory);
|
||||||
|
|
||||||
|
const uint8_t* restore(const uint8_t* buffer) override;
|
||||||
|
|
||||||
|
int32_t translateAsap(uint16_t asap);
|
||||||
|
int32_t nextAsap(uint16_t tsap, uint16_t& startIdx);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void beforeStateChange(LoadState& newState) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t entryCount();
|
||||||
|
uint16_t getTSAP(uint16_t idx);
|
||||||
|
uint16_t getASAP(uint16_t idx);
|
||||||
|
void prepareBinarySearch();
|
||||||
|
uint16_t* _tableData = 0;
|
||||||
|
uint16_t sortedEntryCount;
|
||||||
|
};
|
||||||
392
components/knx/src/knx/bau.cpp
Normal file
392
components/knx/src/knx/bau.cpp
Normal file
@ -0,0 +1,392 @@
|
|||||||
|
#include "bau.h"
|
||||||
|
|
||||||
|
void BusAccessUnit::groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::groupValueReadResponseConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopTtype, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::individualAddressWriteLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::individualAddressWriteIndication(HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::individualAddressReadLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::individualAddressReadIndication(HopCountType hopType, const SecurityControl& secCtrl)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::individualAddressReadResponseConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::individualAddressReadAppLayerConfirm(HopCountType hopType, const SecurityControl& secCtrl, uint16_t individualAddress)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::individualAddressSerialNumberReadLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::individualAddressSerialNumberReadResponseConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, uint16_t domainAddress, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::individualAddressSerialNumberReadAppLayerConfirm(HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, uint16_t individualAddress, uint16_t domainAddress)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::individualAddressSerialNumberWriteLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber, uint16_t newaddress, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::individualAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newIndividualAddress,
|
||||||
|
uint8_t* knxSerialNumber)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::deviceDescriptorReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptorType, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptorType)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::deviceDescriptorReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptor_type,
|
||||||
|
uint8_t* device_descriptor, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::deviceDescriptorReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptortype, uint8_t* deviceDescriptor)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::restartRequestLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, RestartType restartType, EraseCode eraseCode, uint8_t channel)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::propertyValueReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::propertyValueExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::functionPropertyCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::functionPropertyStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::functionPropertyExtCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::functionPropertyExtStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::propertyValueReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::propertyValueReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::propertyValueWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::propertyValueWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::propertyValueExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool confirmed)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::propertyDescriptionReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::propertyExtDescriptionReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint16_t objectIndex, uint8_t propertyId, uint16_t propertyIndex, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::propertyExtDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint16_t objectType, uint16_t objectInstance, uint16_t propertyId, uint8_t descriptionType, uint16_t propertyIndex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::propertyDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, uint16_t maxNumberOfElements, uint8_t access)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::propertyDescriptionReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, uint16_t maxNumberOfElements, uint8_t access, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::propertyDescriptionReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type, uint16_t maxNumberOfElements, uint8_t access)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::memoryReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::memoryReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::memoryReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::memoryWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::memoryRouterWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void BusAccessUnit::memoryRouterReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void BusAccessUnit::memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void BusAccessUnit::memoryRoutingTableReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void BusAccessUnit::memoryRoutingTableWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::memoryExtReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::memoryExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::memoryExtReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::memoryExtReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::memoryExtWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::memoryExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::memoryExtWriteResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::memoryExtWriteAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::userMemoryReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::userMemoryReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* memoryData, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::userMemoryReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* memoryData)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::userMemoryWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* memoryData, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* memoryData)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::userManufacturerInfoLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::userManufacturerInfoIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::userManufacturerInfoResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t* info, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::userManufacturerInfoAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t* info)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::authorizeLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::authorizeResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::authorizeAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::keyWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, uint32_t key, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::keyWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, uint32_t key)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::keyWriteResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::keyWriteAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::connectConfirm(uint16_t destination)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::systemNetworkParameterReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType,
|
||||||
|
uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::domainAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA,
|
||||||
|
const uint8_t* knxSerialNumber)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::domainAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::systemNetworkParameterReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType,
|
||||||
|
uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::domainAddressSerialNumberWriteLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA,
|
||||||
|
const uint8_t* knxSerialNumber, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::domainAddressSerialNumberReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::propertyValueRead(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId,
|
||||||
|
uint8_t& numberOfElements, uint16_t startIndex,
|
||||||
|
uint8_t** data, uint32_t& length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId,
|
||||||
|
uint8_t& numberOfElements, uint16_t startIndex,
|
||||||
|
uint8_t* data, uint32_t length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::beforeRestartCallback(BeforeRestartCallback func)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BeforeRestartCallback BusAccessUnit::beforeRestartCallback()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::functionPropertyCallback(FunctionPropertyCallback func)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionPropertyCallback BusAccessUnit::functionPropertyCallback()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusAccessUnit::functionPropertyStateCallback(FunctionPropertyCallback func)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionPropertyCallback BusAccessUnit::functionPropertyStateCallback()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
184
components/knx/src/knx/bau.h
Normal file
184
components/knx/src/knx/bau.h
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "knx_types.h"
|
||||||
|
#include "interface_object.h"
|
||||||
|
|
||||||
|
typedef void (*BeforeRestartCallback)(void);
|
||||||
|
typedef bool (*FunctionPropertyCallback)(uint8_t objectIndex, uint8_t propertyId, uint8_t length, uint8_t* data, uint8_t* resultData, uint8_t& resultLength);
|
||||||
|
|
||||||
|
class BusAccessUnit
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~BusAccessUnit() {}
|
||||||
|
virtual void groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, bool status);
|
||||||
|
virtual void groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl);
|
||||||
|
virtual void groupValueReadResponseConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopTtype, const SecurityControl& secCtrl,
|
||||||
|
uint8_t* data, uint8_t dataLength, bool status);
|
||||||
|
virtual void groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl,
|
||||||
|
uint8_t* data, uint8_t dataLength);
|
||||||
|
virtual void groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl,
|
||||||
|
uint8_t* data, uint8_t dataLength, bool status);
|
||||||
|
virtual void groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl,
|
||||||
|
uint8_t* data, uint8_t dataLength);
|
||||||
|
virtual void individualAddressWriteLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl,
|
||||||
|
uint16_t newaddress, bool status);
|
||||||
|
virtual void individualAddressWriteIndication(HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress);
|
||||||
|
virtual void individualAddressReadLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, bool status);
|
||||||
|
virtual void individualAddressReadIndication(HopCountType hopType, const SecurityControl& secCtrl);
|
||||||
|
virtual void individualAddressReadResponseConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, bool status);
|
||||||
|
virtual void individualAddressReadAppLayerConfirm(HopCountType hopType, const SecurityControl& secCtrl, uint16_t individualAddress);
|
||||||
|
virtual void individualAddressSerialNumberReadLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl,
|
||||||
|
uint8_t* serialNumber, bool status);
|
||||||
|
virtual void individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber);
|
||||||
|
virtual void individualAddressSerialNumberReadResponseConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl,
|
||||||
|
uint8_t* serialNumber, uint16_t domainAddress, bool status);
|
||||||
|
virtual void individualAddressSerialNumberReadAppLayerConfirm(HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber,
|
||||||
|
uint16_t individualAddress, uint16_t domainAddress);
|
||||||
|
virtual void individualAddressSerialNumberWriteLocalConfirm(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* serialNumber,
|
||||||
|
uint16_t newaddress, bool status);
|
||||||
|
virtual void individualAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newIndividualAddress,
|
||||||
|
uint8_t* knxSerialNumber);
|
||||||
|
virtual void deviceDescriptorReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t descriptorType, bool status);
|
||||||
|
virtual void deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptorType);
|
||||||
|
virtual void deviceDescriptorReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t descriptor_type, uint8_t* device_descriptor, bool status);
|
||||||
|
virtual void deviceDescriptorReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t descriptortype, uint8_t* deviceDescriptor);
|
||||||
|
virtual void restartRequestLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, bool status);
|
||||||
|
virtual void restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, RestartType restartType, EraseCode eraseCode, uint8_t channel);
|
||||||
|
virtual void propertyValueReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, bool status);
|
||||||
|
virtual void propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex);
|
||||||
|
virtual void propertyValueExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex);
|
||||||
|
virtual void functionPropertyCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t* data, uint8_t length);
|
||||||
|
virtual void functionPropertyStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t* data, uint8_t length);
|
||||||
|
virtual void functionPropertyExtCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance,
|
||||||
|
uint8_t propertyId, uint8_t* data, uint8_t length);
|
||||||
|
virtual void functionPropertyExtStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance,
|
||||||
|
uint8_t propertyId, uint8_t* data, uint8_t length);
|
||||||
|
virtual void propertyValueReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool status);
|
||||||
|
virtual void propertyValueReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length);
|
||||||
|
virtual void propertyValueWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool status);
|
||||||
|
virtual void propertyValueWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length);
|
||||||
|
virtual void propertyValueExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool confirmed);
|
||||||
|
virtual void propertyDescriptionReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool status);
|
||||||
|
virtual void propertyExtDescriptionReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint16_t objectIndex, uint8_t propertyId, uint16_t propertyIndex, bool status);
|
||||||
|
virtual void propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex);
|
||||||
|
virtual void propertyExtDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint16_t objectType, uint16_t objectInstance, uint16_t propertyId, uint8_t descriptionType, uint16_t propertyIndex);
|
||||||
|
virtual void propertyDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type,
|
||||||
|
uint16_t maxNumberOfElements, uint8_t access);
|
||||||
|
virtual void propertyDescriptionReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type,
|
||||||
|
uint16_t maxNumberOfElements, uint8_t access, bool status);
|
||||||
|
virtual void propertyDescriptionReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type,
|
||||||
|
uint16_t maxNumberOfElements, uint8_t access);
|
||||||
|
virtual void memoryReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, bool status);
|
||||||
|
virtual void memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress);
|
||||||
|
virtual void memoryReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* data, bool status);
|
||||||
|
virtual void memoryReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* data);
|
||||||
|
virtual void memoryWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* data, bool status);
|
||||||
|
virtual void memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* data);
|
||||||
|
virtual void memoryRouterWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* data);
|
||||||
|
virtual void memoryRouterReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* data);
|
||||||
|
virtual void memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress);
|
||||||
|
virtual void memoryRoutingTableReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data);
|
||||||
|
virtual void memoryRoutingTableWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data);
|
||||||
|
virtual void memoryExtReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress, bool status);
|
||||||
|
virtual void memoryExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress);
|
||||||
|
virtual void memoryExtReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress, uint8_t* data, bool status);
|
||||||
|
virtual void memoryExtReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress, uint8_t* data);
|
||||||
|
virtual void memoryExtWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress, uint8_t* data, bool status);
|
||||||
|
virtual void memoryExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress, uint8_t* data);
|
||||||
|
virtual void memoryExtWriteResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress, uint8_t* data, bool status);
|
||||||
|
virtual void memoryExtWriteAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress, uint8_t* data);
|
||||||
|
virtual void userMemoryReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress, bool status);
|
||||||
|
virtual void userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress);
|
||||||
|
virtual void userMemoryReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress, uint8_t* memoryData, bool status);
|
||||||
|
virtual void userMemoryReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress, uint8_t* memoryData);
|
||||||
|
virtual void userMemoryWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress, uint8_t* memoryData, bool status);
|
||||||
|
virtual void userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress, uint8_t* memoryData);
|
||||||
|
virtual void userManufacturerInfoLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, bool status);
|
||||||
|
virtual void userManufacturerInfoIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl);
|
||||||
|
virtual void userManufacturerInfoResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t* info, bool status);
|
||||||
|
virtual void userManufacturerInfoAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint8_t* info);
|
||||||
|
virtual void authorizeLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key, bool status);
|
||||||
|
virtual void authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key);
|
||||||
|
virtual void authorizeResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level,
|
||||||
|
bool status);
|
||||||
|
virtual void authorizeAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level);
|
||||||
|
virtual void keyWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level,
|
||||||
|
uint32_t key, bool status);
|
||||||
|
virtual void keyWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level,
|
||||||
|
uint32_t key);
|
||||||
|
virtual void keyWriteResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level,
|
||||||
|
bool status);
|
||||||
|
virtual void keyWriteAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t level);
|
||||||
|
virtual void connectConfirm(uint16_t destination);
|
||||||
|
virtual void systemNetworkParameterReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType,
|
||||||
|
uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength);
|
||||||
|
|
||||||
|
virtual void domainAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA,
|
||||||
|
const uint8_t* knxSerialNumber);
|
||||||
|
|
||||||
|
virtual void domainAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber);
|
||||||
|
|
||||||
|
virtual void systemNetworkParameterReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType,
|
||||||
|
uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength, bool status);
|
||||||
|
|
||||||
|
virtual void domainAddressSerialNumberWriteLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA,
|
||||||
|
const uint8_t* knxSerialNumber, bool status);
|
||||||
|
|
||||||
|
virtual void domainAddressSerialNumberReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber, bool status);
|
||||||
|
|
||||||
|
virtual void propertyValueRead(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId,
|
||||||
|
uint8_t& numberOfElements, uint16_t startIndex,
|
||||||
|
uint8_t** data, uint32_t& length);
|
||||||
|
|
||||||
|
virtual void propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId,
|
||||||
|
uint8_t& numberOfElements, uint16_t startIndex,
|
||||||
|
uint8_t* data, uint32_t length);
|
||||||
|
virtual void beforeRestartCallback(BeforeRestartCallback func);
|
||||||
|
virtual BeforeRestartCallback beforeRestartCallback();
|
||||||
|
virtual void functionPropertyCallback(FunctionPropertyCallback func);
|
||||||
|
virtual FunctionPropertyCallback functionPropertyCallback();
|
||||||
|
virtual void functionPropertyStateCallback(FunctionPropertyCallback func);
|
||||||
|
virtual FunctionPropertyCallback functionPropertyStateCallback();
|
||||||
|
};
|
||||||
178
components/knx/src/knx/bau07B0.cpp
Normal file
178
components/knx/src/knx/bau07B0.cpp
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
#include "config.h"
|
||||||
|
#if MASK_VERSION == 0x07B0
|
||||||
|
|
||||||
|
#include "bau07B0.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
Bau07B0::Bau07B0(Platform& platform)
|
||||||
|
: BauSystemBDevice(platform), DataLinkLayerCallbacks(),
|
||||||
|
_dlLayer(_deviceObj, _netLayer.getInterface(), _platform, (ITpUartCallBacks&) * this, (DataLinkLayerCallbacks*) this)
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
, _cemiServer(*this)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
_netLayer.getInterface().dataLinkLayer(_dlLayer);
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
_cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_TP1);
|
||||||
|
_cemiServer.dataLinkLayer(_dlLayer);
|
||||||
|
_dlLayer.cemiServer(_cemiServer);
|
||||||
|
_memory.addSaveRestore(&_cemiServerObject);
|
||||||
|
#endif
|
||||||
|
// Set Mask Version in Device Object depending on the BAU
|
||||||
|
_deviceObj.maskVersion(0x07B0);
|
||||||
|
|
||||||
|
// Set which interface objects are available in the device object
|
||||||
|
// This differs from BAU to BAU with different medium types.
|
||||||
|
// See PID_IO_LIST
|
||||||
|
Property* prop = _deviceObj.property(PID_IO_LIST);
|
||||||
|
prop->write(1, (uint16_t) OT_DEVICE);
|
||||||
|
prop->write(2, (uint16_t) OT_ADDR_TABLE);
|
||||||
|
prop->write(3, (uint16_t) OT_ASSOC_TABLE);
|
||||||
|
prop->write(4, (uint16_t) OT_GRP_OBJ_TABLE);
|
||||||
|
prop->write(5, (uint16_t) OT_APPLICATION_PROG);
|
||||||
|
#if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER)
|
||||||
|
prop->write(6, (uint16_t) OT_SECURITY);
|
||||||
|
prop->write(7, (uint16_t) OT_CEMI_SERVER);
|
||||||
|
#elif defined(USE_DATASECURE)
|
||||||
|
prop->write(6, (uint16_t) OT_SECURITY);
|
||||||
|
#elif defined(USE_CEMI_SERVER)
|
||||||
|
prop->write(6, (uint16_t) OT_CEMI_SERVER);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
InterfaceObject* Bau07B0::getInterfaceObject(uint8_t idx)
|
||||||
|
{
|
||||||
|
switch (idx)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return &_deviceObj;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
return &_addrTable;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
return &_assocTable;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
return &_groupObjTable;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
return &_appProgram;
|
||||||
|
|
||||||
|
case 5: // would be app_program 2
|
||||||
|
return nullptr;
|
||||||
|
#if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER)
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
return &_secIfObj;
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
return &_cemiServerObject;
|
||||||
|
#elif defined(USE_CEMI_SERVER)
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
return &_cemiServerObject;
|
||||||
|
#elif defined(USE_DATASECURE)
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
return &_secIfObj;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InterfaceObject* Bau07B0::getInterfaceObject(ObjectType objectType, uint16_t objectInstance)
|
||||||
|
{
|
||||||
|
// We do not use it right now.
|
||||||
|
// Required for coupler mode as there are multiple router objects for example
|
||||||
|
(void) objectInstance;
|
||||||
|
|
||||||
|
switch (objectType)
|
||||||
|
{
|
||||||
|
case OT_DEVICE:
|
||||||
|
return &_deviceObj;
|
||||||
|
|
||||||
|
case OT_ADDR_TABLE:
|
||||||
|
return &_addrTable;
|
||||||
|
|
||||||
|
case OT_ASSOC_TABLE:
|
||||||
|
return &_assocTable;
|
||||||
|
|
||||||
|
case OT_GRP_OBJ_TABLE:
|
||||||
|
return &_groupObjTable;
|
||||||
|
|
||||||
|
case OT_APPLICATION_PROG:
|
||||||
|
return &_appProgram;
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
|
||||||
|
case OT_SECURITY:
|
||||||
|
return &_secIfObj;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
|
||||||
|
case OT_CEMI_SERVER:
|
||||||
|
return &_cemiServerObject;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bau07B0::enabled()
|
||||||
|
{
|
||||||
|
return _dlLayer.enabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau07B0::enabled(bool value)
|
||||||
|
{
|
||||||
|
_dlLayer.enabled(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau07B0::loop()
|
||||||
|
{
|
||||||
|
_dlLayer.loop();
|
||||||
|
BauSystemBDevice::loop();
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
_cemiServer.loop();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TPAckType Bau07B0::isAckRequired(uint16_t address, bool isGrpAddr)
|
||||||
|
{
|
||||||
|
if (isGrpAddr)
|
||||||
|
{
|
||||||
|
// ACK for broadcasts
|
||||||
|
if (address == 0)
|
||||||
|
return TPAckType::AckReqAck;
|
||||||
|
|
||||||
|
// is group address in group address table? ACK if yes.
|
||||||
|
if (_addrTable.contains(address))
|
||||||
|
return TPAckType::AckReqAck;
|
||||||
|
else
|
||||||
|
return TPAckType::AckReqNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also ACK for our own individual address
|
||||||
|
if (address == _deviceObj.individualAddress())
|
||||||
|
return TPAckType::AckReqAck;
|
||||||
|
|
||||||
|
if (address == 0)
|
||||||
|
{
|
||||||
|
println("Invalid broadcast detected: destination address is 0, but address type is \"individual\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
return TPAckType::AckReqNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
TpUartDataLinkLayer* Bau07B0::getDataLinkLayer()
|
||||||
|
{
|
||||||
|
return (TpUartDataLinkLayer*)&_dlLayer;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
34
components/knx/src/knx/bau07B0.h
Normal file
34
components/knx/src/knx/bau07B0.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#if MASK_VERSION == 0x07B0
|
||||||
|
|
||||||
|
#include "bau_systemB_device.h"
|
||||||
|
#include "tpuart_data_link_layer.h"
|
||||||
|
#include "cemi_server.h"
|
||||||
|
#include "cemi_server_object.h"
|
||||||
|
|
||||||
|
class Bau07B0 : public BauSystemBDevice, public ITpUartCallBacks, public DataLinkLayerCallbacks
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Bau07B0(Platform& platform);
|
||||||
|
void loop() override;
|
||||||
|
bool enabled() override;
|
||||||
|
void enabled(bool value) override;
|
||||||
|
|
||||||
|
TpUartDataLinkLayer* getDataLinkLayer();
|
||||||
|
protected:
|
||||||
|
InterfaceObject* getInterfaceObject(uint8_t idx);
|
||||||
|
InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance);
|
||||||
|
|
||||||
|
// For TP1 only
|
||||||
|
TPAckType isAckRequired(uint16_t address, bool isGrpAddr) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TpUartDataLinkLayer _dlLayer;
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
CemiServer _cemiServer;
|
||||||
|
CemiServerObject _cemiServerObject;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
#endif
|
||||||
262
components/knx/src/knx/bau091A.cpp
Normal file
262
components/knx/src/knx/bau091A.cpp
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
#include "config.h"
|
||||||
|
#if MASK_VERSION == 0x091A
|
||||||
|
|
||||||
|
#include "bau091A.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
/* ToDos
|
||||||
|
Announce the line status of sec side 03_05_01 4.4.3
|
||||||
|
implement PID_COUPLER_SERVICES_CONTROL 03_05_01 4.4.7
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bau091A::Bau091A(Platform& platform)
|
||||||
|
: BauSystemBCoupler(platform), DataLinkLayerCallbacks(),
|
||||||
|
_routerObj(memory(), 0x200, 0x2000), // the Filtertable of 0x091A IP Routers is fixed at 0x200 and 0x2000 long
|
||||||
|
_ipParameters(_deviceObj, platform),
|
||||||
|
_dlLayerPrimary(_deviceObj, _ipParameters, _netLayer.getPrimaryInterface(), _platform, (DataLinkLayerCallbacks*) this),
|
||||||
|
_dlLayerSecondary(_deviceObj, _netLayer.getSecondaryInterface(), platform, (ITpUartCallBacks&) * this, (DataLinkLayerCallbacks*) this)
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
, _cemiServer(*this)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
// Before accessing anything of the router object they have to be initialized according to the used medium
|
||||||
|
// Coupler model 1.x
|
||||||
|
_routerObj.initialize1x(DptMedium::KNX_IP, 220);
|
||||||
|
|
||||||
|
// Mask 091A uses older coupler model 1.x which only uses one router object
|
||||||
|
_netLayer.rtObj(_routerObj);
|
||||||
|
|
||||||
|
_netLayer.getPrimaryInterface().dataLinkLayer(_dlLayerPrimary);
|
||||||
|
_netLayer.getSecondaryInterface().dataLinkLayer(_dlLayerSecondary);
|
||||||
|
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
_cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_IP);
|
||||||
|
_cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_TP1);
|
||||||
|
_cemiServer.dataLinkLayerPrimary(_dlLayerPrimary);
|
||||||
|
_cemiServer.dataLinkLayer(_dlLayerSecondary); // Secondary I/F is the important one!
|
||||||
|
_dlLayerPrimary.cemiServer(_cemiServer);
|
||||||
|
_dlLayerSecondary.cemiServer(_cemiServer);
|
||||||
|
_memory.addSaveRestore(&_cemiServerObject);
|
||||||
|
uint8_t count = 1;
|
||||||
|
uint16_t suppCommModes = 0x0100;
|
||||||
|
_cemiServerObject.writeProperty(PID_COMM_MODES_SUPPORTED, 1, (uint8_t*)&suppCommModes, count); // set the properties Bit 0 to 1 meaning "LinkLayer supported"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_memory.addSaveRestore(&_routerObj);
|
||||||
|
|
||||||
|
_memory.addSaveRestore(&_ipParameters);
|
||||||
|
|
||||||
|
// Set Mask Version in Device Object depending on the BAU
|
||||||
|
_deviceObj.maskVersion(0x091A);
|
||||||
|
|
||||||
|
// Set which interface objects are available in the device object
|
||||||
|
// This differs from BAU to BAU with different medium types.
|
||||||
|
// See PID_IO_LIST
|
||||||
|
Property* prop = _deviceObj.property(PID_IO_LIST);
|
||||||
|
prop->write(1, (uint16_t) OT_DEVICE);
|
||||||
|
prop->write(2, (uint16_t) OT_ROUTER);
|
||||||
|
prop->write(3, (uint16_t) OT_APPLICATION_PROG);
|
||||||
|
prop->write(4, (uint16_t) OT_IP_PARAMETER);
|
||||||
|
#if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER)
|
||||||
|
prop->write(5, (uint16_t) OT_SECURITY);
|
||||||
|
prop->write(6, (uint16_t) OT_CEMI_SERVER);
|
||||||
|
#elif defined(USE_DATASECURE)
|
||||||
|
prop->write(5, (uint16_t) OT_SECURITY);
|
||||||
|
#elif defined(USE_CEMI_SERVER)
|
||||||
|
prop->write(5, (uint16_t) OT_CEMI_SERVER);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
InterfaceObject* Bau091A::getInterfaceObject(uint8_t idx)
|
||||||
|
{
|
||||||
|
switch (idx)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return &_deviceObj;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
return &_routerObj;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
return &_appProgram;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
return &_ipParameters;
|
||||||
|
#if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER)
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
return &_secIfObj;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
return &_cemiServerObject;
|
||||||
|
#elif defined(USE_CEMI_SERVER)
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
return &_cemiServerObject;
|
||||||
|
#elif defined(USE_DATASECURE)
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
return &_secIfObj;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InterfaceObject* Bau091A::getInterfaceObject(ObjectType objectType, uint16_t objectInstance)
|
||||||
|
{
|
||||||
|
// We do not use it right now.
|
||||||
|
// Required for coupler mode as there are multiple router objects for example
|
||||||
|
(void) objectInstance;
|
||||||
|
|
||||||
|
switch (objectType)
|
||||||
|
{
|
||||||
|
case OT_DEVICE:
|
||||||
|
return &_deviceObj;
|
||||||
|
|
||||||
|
case OT_ROUTER:
|
||||||
|
return &_routerObj;
|
||||||
|
|
||||||
|
case OT_APPLICATION_PROG:
|
||||||
|
return &_appProgram;
|
||||||
|
|
||||||
|
case OT_IP_PARAMETER:
|
||||||
|
return &_ipParameters;
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
|
||||||
|
case OT_SECURITY:
|
||||||
|
return &_secIfObj;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
|
||||||
|
case OT_CEMI_SERVER:
|
||||||
|
return &_cemiServerObject;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau091A::doMasterReset(EraseCode eraseCode, uint8_t channel)
|
||||||
|
{
|
||||||
|
// Common SystemB objects
|
||||||
|
BauSystemBCoupler::doMasterReset(eraseCode, channel);
|
||||||
|
|
||||||
|
_ipParameters.masterReset(eraseCode, channel);
|
||||||
|
_routerObj.masterReset(eraseCode, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bau091A::enabled()
|
||||||
|
{
|
||||||
|
return _dlLayerPrimary.enabled() && _dlLayerSecondary.enabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau091A::enabled(bool value)
|
||||||
|
{
|
||||||
|
_dlLayerPrimary.enabled(value);
|
||||||
|
_dlLayerSecondary.enabled(value);
|
||||||
|
|
||||||
|
// ToDo change frame repitition in the TP layer - but default is ok.
|
||||||
|
//_dlLayerSecondary.setFrameRepetition(3,3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau091A::loop()
|
||||||
|
{
|
||||||
|
_dlLayerPrimary.loop();
|
||||||
|
_dlLayerSecondary.loop();
|
||||||
|
BauSystemBCoupler::loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
TPAckType Bau091A::isAckRequired(uint16_t address, bool isGrpAddr)
|
||||||
|
{
|
||||||
|
//only called from TpUartDataLinkLayer
|
||||||
|
TPAckType ack = TPAckType::AckReqNone;
|
||||||
|
|
||||||
|
uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible.
|
||||||
|
Property* prop_lcconfig = _routerObj.property(PID_SUB_LCCONFIG);
|
||||||
|
|
||||||
|
if (lcconfig)
|
||||||
|
prop_lcconfig->read(lcconfig);
|
||||||
|
|
||||||
|
if (isGrpAddr)
|
||||||
|
{
|
||||||
|
// ACK for broadcasts
|
||||||
|
if (address == 0)
|
||||||
|
{
|
||||||
|
ack = TPAckType::AckReqAck;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(lcconfig & LCCONFIG::GROUP_IACK_ROUT)
|
||||||
|
{
|
||||||
|
// is group address in filter table? ACK if yes, No if not
|
||||||
|
if(_netLayer.isRoutedGroupAddress(address, 1))
|
||||||
|
ack = TPAckType::AckReqAck;
|
||||||
|
else
|
||||||
|
ack = TPAckType::AckReqNone;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// all are ACKED
|
||||||
|
ack = TPAckType::AckReqAck;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
|
||||||
|
if (_dlLayerPrimary.isSentToTunnel(address, isGrpAddr))
|
||||||
|
ack = TPAckType::AckReqAck;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((lcconfig & LCCONFIG::PHYS_IACK) == LCCONFIG::PHYS_IACK_ALL)
|
||||||
|
ack = TPAckType::AckReqAck;
|
||||||
|
else if ((lcconfig & LCCONFIG::PHYS_IACK) == LCCONFIG::PHYS_IACK_NACK)
|
||||||
|
ack = TPAckType::AckReqNack;
|
||||||
|
else if (_netLayer.isRoutedIndividualAddress(address, 1) || address == _deviceObj.individualAddress()) // Also ACK for our own individual address
|
||||||
|
ack = TPAckType::AckReqAck;
|
||||||
|
else
|
||||||
|
ack = TPAckType::AckReqNone;
|
||||||
|
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
|
||||||
|
if (_dlLayerPrimary.isSentToTunnel(address, isGrpAddr))
|
||||||
|
ack = TPAckType::AckReqAck;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return ack;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bau091A::configured()
|
||||||
|
{
|
||||||
|
// _configured is set to true initially, if the device was configured with ETS it will be set to true after restart
|
||||||
|
|
||||||
|
if (!_configured)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_configured = _routerObj.loadState() == LS_LOADED;
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
_configured &= _secIfObj.loadState() == LS_LOADED;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return _configured;
|
||||||
|
}
|
||||||
|
|
||||||
|
IpDataLinkLayer* Bau091A::getPrimaryDataLinkLayer()
|
||||||
|
{
|
||||||
|
return (IpDataLinkLayer*)&_dlLayerPrimary;
|
||||||
|
}
|
||||||
|
|
||||||
|
TpUartDataLinkLayer* Bau091A::getSecondaryDataLinkLayer()
|
||||||
|
{
|
||||||
|
return (TpUartDataLinkLayer*)&_dlLayerSecondary;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
42
components/knx/src/knx/bau091A.h
Normal file
42
components/knx/src/knx/bau091A.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#if MASK_VERSION == 0x091A
|
||||||
|
|
||||||
|
#include "bau_systemB_coupler.h"
|
||||||
|
#include "router_object.h"
|
||||||
|
#include "ip_parameter_object.h"
|
||||||
|
#include "ip_data_link_layer.h"
|
||||||
|
#include "tpuart_data_link_layer.h"
|
||||||
|
#include "cemi_server_object.h"
|
||||||
|
|
||||||
|
class Bau091A : public BauSystemBCoupler, public ITpUartCallBacks, public DataLinkLayerCallbacks
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Bau091A(Platform& platform);
|
||||||
|
void loop() override;
|
||||||
|
bool enabled() override;
|
||||||
|
void enabled(bool value) override;
|
||||||
|
bool configured() override;
|
||||||
|
|
||||||
|
IpDataLinkLayer* getPrimaryDataLinkLayer();
|
||||||
|
TpUartDataLinkLayer* getSecondaryDataLinkLayer();
|
||||||
|
protected:
|
||||||
|
InterfaceObject* getInterfaceObject(uint8_t idx);
|
||||||
|
InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance);
|
||||||
|
|
||||||
|
// For TP1 only
|
||||||
|
TPAckType isAckRequired(uint16_t address, bool isGrpAddr) override;
|
||||||
|
|
||||||
|
void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
||||||
|
private:
|
||||||
|
RouterObject _routerObj;
|
||||||
|
IpParameterObject _ipParameters;
|
||||||
|
IpDataLinkLayer _dlLayerPrimary;
|
||||||
|
TpUartDataLinkLayer _dlLayerSecondary;
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
CemiServer _cemiServer;
|
||||||
|
CemiServerObject _cemiServerObject;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
#endif
|
||||||
207
components/knx/src/knx/bau27B0.cpp
Normal file
207
components/knx/src/knx/bau27B0.cpp
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
#include "config.h"
|
||||||
|
#if MASK_VERSION == 0x27B0
|
||||||
|
|
||||||
|
#include "bau27B0.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
Bau27B0::Bau27B0(Platform& platform)
|
||||||
|
: BauSystemBDevice(platform),
|
||||||
|
_dlLayer(_deviceObj, _rfMediumObj, _netLayer.getInterface(), _platform)
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
, _cemiServer(*this)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
_netLayer.getInterface().dataLinkLayer(_dlLayer);
|
||||||
|
_memory.addSaveRestore(&_rfMediumObj);
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
_cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_RF);
|
||||||
|
_cemiServer.dataLinkLayer(_dlLayer);
|
||||||
|
_dlLayer.cemiServer(_cemiServer);
|
||||||
|
_memory.addSaveRestore(&_cemiServerObject);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Set Mask Version in Device Object depending on the BAU
|
||||||
|
_deviceObj.maskVersion(0x27B0);
|
||||||
|
|
||||||
|
// Set the maximum APDU length
|
||||||
|
// ETS will consider this value while programming the device
|
||||||
|
// For KNX-RF we use a smallest allowed value for now,
|
||||||
|
// although long frame are also supported by the implementation.
|
||||||
|
// Needs some experimentation.
|
||||||
|
_deviceObj.maxApduLength(15);
|
||||||
|
|
||||||
|
// Set which interface objects are available in the device object
|
||||||
|
// This differs from BAU to BAU with different medium types.
|
||||||
|
// See PID_IO_LIST
|
||||||
|
Property* prop = _deviceObj.property(PID_IO_LIST);
|
||||||
|
prop->write(1, (uint16_t) OT_DEVICE);
|
||||||
|
prop->write(2, (uint16_t) OT_ADDR_TABLE);
|
||||||
|
prop->write(3, (uint16_t) OT_ASSOC_TABLE);
|
||||||
|
prop->write(4, (uint16_t) OT_GRP_OBJ_TABLE);
|
||||||
|
prop->write(5, (uint16_t) OT_APPLICATION_PROG);
|
||||||
|
prop->write(6, (uint16_t) OT_RF_MEDIUM);
|
||||||
|
#if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER)
|
||||||
|
prop->write(7, (uint16_t) OT_SECURITY);
|
||||||
|
prop->write(8, (uint16_t) OT_CEMI_SERVER);
|
||||||
|
#elif defined(USE_DATASECURE)
|
||||||
|
prop->write(7, (uint16_t) OT_SECURITY);
|
||||||
|
#elif defined(USE_CEMI_SERVER)
|
||||||
|
prop->write(7, (uint16_t)OT_CEMI_SERVER);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// see KNX AN160 p.74 for mask 27B0
|
||||||
|
InterfaceObject* Bau27B0::getInterfaceObject(uint8_t idx)
|
||||||
|
{
|
||||||
|
switch (idx)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return &_deviceObj;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
return &_addrTable;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
return &_assocTable;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
return &_groupObjTable;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
return &_appProgram;
|
||||||
|
|
||||||
|
case 5: // would be app_program 2
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
return &_rfMediumObj;
|
||||||
|
#if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER)
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
return &_secIfObj;
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
return &_cemiServerObject;
|
||||||
|
#elif defined(USE_CEMI_SERVER)
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
return &_cemiServerObject;
|
||||||
|
#elif defined(USE_DATASECURE)
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
return &_secIfObj;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InterfaceObject* Bau27B0::getInterfaceObject(ObjectType objectType, uint16_t objectInstance)
|
||||||
|
{
|
||||||
|
// We do not use it right now.
|
||||||
|
// Required for coupler mode as there are multiple router objects for example
|
||||||
|
(void) objectInstance;
|
||||||
|
|
||||||
|
switch (objectType)
|
||||||
|
{
|
||||||
|
case OT_DEVICE:
|
||||||
|
return &_deviceObj;
|
||||||
|
|
||||||
|
case OT_ADDR_TABLE:
|
||||||
|
return &_addrTable;
|
||||||
|
|
||||||
|
case OT_ASSOC_TABLE:
|
||||||
|
return &_assocTable;
|
||||||
|
|
||||||
|
case OT_GRP_OBJ_TABLE:
|
||||||
|
return &_groupObjTable;
|
||||||
|
|
||||||
|
case OT_APPLICATION_PROG:
|
||||||
|
return &_appProgram;
|
||||||
|
|
||||||
|
case OT_RF_MEDIUM:
|
||||||
|
return &_rfMediumObj;
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
|
||||||
|
case OT_SECURITY:
|
||||||
|
return &_secIfObj;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
|
||||||
|
case OT_CEMI_SERVER:
|
||||||
|
return &_cemiServerObject;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau27B0::doMasterReset(EraseCode eraseCode, uint8_t channel)
|
||||||
|
{
|
||||||
|
// Common SystemB objects
|
||||||
|
BauSystemB::doMasterReset(eraseCode, channel);
|
||||||
|
|
||||||
|
_rfMediumObj.masterReset(eraseCode, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bau27B0::enabled()
|
||||||
|
{
|
||||||
|
return _dlLayer.enabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau27B0::enabled(bool value)
|
||||||
|
{
|
||||||
|
_dlLayer.enabled(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau27B0::loop()
|
||||||
|
{
|
||||||
|
_dlLayer.loop();
|
||||||
|
BauSystemBDevice::loop();
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
_cemiServer.loop();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau27B0::domainAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA,
|
||||||
|
const uint8_t* knxSerialNumber)
|
||||||
|
{
|
||||||
|
// If the received serial number matches our serial number
|
||||||
|
// then store the received RF domain address in the RF medium object
|
||||||
|
if (!memcmp(knxSerialNumber, _deviceObj.propertyData(PID_SERIAL_NUMBER), 6))
|
||||||
|
_rfMediumObj.rfDomainAddress(rfDoA);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau27B0::domainAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber)
|
||||||
|
{
|
||||||
|
// If the received serial number matches our serial number
|
||||||
|
// then send a response with the current RF domain address stored in the RF medium object
|
||||||
|
if (!memcmp(knxSerialNumber, _deviceObj.propertyData(PID_SERIAL_NUMBER), 6))
|
||||||
|
_appLayer.domainAddressSerialNumberReadResponse(priority, hopType, secCtrl, _rfMediumObj.rfDomainAddress(), knxSerialNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau27B0::individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber)
|
||||||
|
{
|
||||||
|
#pragma warning "individualAddressSerialNumberReadIndication is not available for rf"
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau27B0::domainAddressSerialNumberWriteLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA,
|
||||||
|
const uint8_t* knxSerialNumber, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau27B0::domainAddressSerialNumberReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RfDataLinkLayer* Bau27B0::getDataLinkLayer()
|
||||||
|
{
|
||||||
|
return (RfDataLinkLayer*)&_dlLayer;
|
||||||
|
}
|
||||||
|
#endif // #ifdef USE_RF
|
||||||
47
components/knx/src/knx/bau27B0.h
Normal file
47
components/knx/src/knx/bau27B0.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#if MASK_VERSION == 0x27B0
|
||||||
|
|
||||||
|
#include "bau_systemB_device.h"
|
||||||
|
#include "rf_medium_object.h"
|
||||||
|
#if defined(DeviceFamily_CC13X0)
|
||||||
|
#include "rf_physical_layer_cc1310.h"
|
||||||
|
#else
|
||||||
|
#include "rf_physical_layer_cc1101.h"
|
||||||
|
#endif
|
||||||
|
#include "rf_data_link_layer.h"
|
||||||
|
#include "cemi_server.h"
|
||||||
|
#include "cemi_server_object.h"
|
||||||
|
|
||||||
|
class Bau27B0 : public BauSystemBDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Bau27B0(Platform& platform);
|
||||||
|
void loop() override;
|
||||||
|
bool enabled() override;
|
||||||
|
void enabled(bool value) override;
|
||||||
|
|
||||||
|
RfDataLinkLayer* getDataLinkLayer();
|
||||||
|
protected:
|
||||||
|
InterfaceObject* getInterfaceObject(uint8_t idx);
|
||||||
|
InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance);
|
||||||
|
|
||||||
|
void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
||||||
|
private:
|
||||||
|
RfDataLinkLayer _dlLayer;
|
||||||
|
RfMediumObject _rfMediumObj;
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
CemiServer _cemiServer;
|
||||||
|
CemiServerObject _cemiServerObject;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void domainAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA,
|
||||||
|
const uint8_t* knxSerialNumber) override;
|
||||||
|
void domainAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber) override;
|
||||||
|
void individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber) override;
|
||||||
|
void domainAddressSerialNumberWriteLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* rfDoA,
|
||||||
|
const uint8_t* knxSerialNumber, bool status) override;
|
||||||
|
void domainAddressSerialNumberReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, const uint8_t* knxSerialNumber, bool status) override;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
181
components/knx/src/knx/bau2920.cpp
Normal file
181
components/knx/src/knx/bau2920.cpp
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
#include "config.h"
|
||||||
|
#if MASK_VERSION == 0x2920
|
||||||
|
|
||||||
|
#include "bau2920.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
// Mask 0x2920 uses coupler model 2.0
|
||||||
|
Bau2920::Bau2920(Platform& platform)
|
||||||
|
: BauSystemBCoupler(platform),
|
||||||
|
_rtObjPrimary(memory()),
|
||||||
|
_rtObjSecondary(memory()),
|
||||||
|
_rfMediumObject(),
|
||||||
|
_dlLayerPrimary(_deviceObj, _netLayer.getPrimaryInterface(), _platform, (ITpUartCallBacks&) * this),
|
||||||
|
_dlLayerSecondary(_deviceObj, _rfMediumObject, _netLayer.getSecondaryInterface(), platform)
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
,
|
||||||
|
_cemiServer(*this)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
// Before accessing anything of the two router objects they have to be initialized according to the used media combination
|
||||||
|
// Coupler model 2.0
|
||||||
|
_rtObjPrimary.initialize20(1, DptMedium::KNX_TP1, RouterObjectType::Primary, 201);
|
||||||
|
_rtObjSecondary.initialize20(2, DptMedium::KNX_RF, RouterObjectType::Secondary, 201);
|
||||||
|
|
||||||
|
_netLayer.rtObjPrimary(_rtObjPrimary);
|
||||||
|
_netLayer.rtObjSecondary(_rtObjSecondary);
|
||||||
|
_netLayer.getPrimaryInterface().dataLinkLayer(_dlLayerPrimary);
|
||||||
|
_netLayer.getSecondaryInterface().dataLinkLayer(_dlLayerSecondary);
|
||||||
|
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
_cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_TP1);
|
||||||
|
_cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_RF);
|
||||||
|
_cemiServer.dataLinkLayer(_dlLayerSecondary); // Secondary I/F is the important one!
|
||||||
|
_dlLayerSecondary.cemiServer(_cemiServer);
|
||||||
|
_memory.addSaveRestore(&_cemiServerObject);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_memory.addSaveRestore(&_rtObjPrimary);
|
||||||
|
_memory.addSaveRestore(&_rtObjSecondary);
|
||||||
|
|
||||||
|
_memory.addSaveRestore(&_rfMediumObject);
|
||||||
|
|
||||||
|
// Set Mask Version in Device Object depending on the BAU
|
||||||
|
_deviceObj.maskVersion(0x2920);
|
||||||
|
|
||||||
|
// Set which interface objects are available in the device object
|
||||||
|
// This differs from BAU to BAU with different medium types.
|
||||||
|
// See PID_IO_LIST
|
||||||
|
Property* prop = _deviceObj.property(PID_IO_LIST);
|
||||||
|
prop->write(1, (uint16_t) OT_DEVICE);
|
||||||
|
prop->write(2, (uint16_t) OT_ROUTER);
|
||||||
|
prop->write(3, (uint16_t) OT_ROUTER);
|
||||||
|
prop->write(4, (uint16_t) OT_APPLICATION_PROG);
|
||||||
|
prop->write(5, (uint16_t) OT_RF_MEDIUM);
|
||||||
|
#if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER)
|
||||||
|
prop->write(6, (uint16_t) OT_SECURITY);
|
||||||
|
prop->write(7, (uint16_t) OT_CEMI_SERVER);
|
||||||
|
#elif defined(USE_DATASECURE)
|
||||||
|
prop->write(6, (uint16_t) OT_SECURITY);
|
||||||
|
#elif defined(USE_CEMI_SERVER)
|
||||||
|
prop->write(6, (uint16_t) OT_CEMI_SERVER);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
InterfaceObject* Bau2920::getInterfaceObject(uint8_t idx)
|
||||||
|
{
|
||||||
|
switch (idx)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return &_deviceObj;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
return &_rtObjPrimary;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
return &_rtObjSecondary;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
return &_appProgram;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
return &_rfMediumObject;
|
||||||
|
#if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER)
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
return &_secIfObj;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
return &_cemiServerObject;
|
||||||
|
#elif defined(USE_CEMI_SERVER)
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
return &_cemiServerObject;
|
||||||
|
#elif defined(USE_DATASECURE)
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
return &_secIfObj;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InterfaceObject* Bau2920::getInterfaceObject(ObjectType objectType, uint16_t objectInstance)
|
||||||
|
{
|
||||||
|
// We do not use it right now.
|
||||||
|
// Required for coupler mode as there are multiple router objects for example
|
||||||
|
(void) objectInstance;
|
||||||
|
|
||||||
|
switch (objectType)
|
||||||
|
{
|
||||||
|
case OT_DEVICE:
|
||||||
|
return &_deviceObj;
|
||||||
|
|
||||||
|
case OT_ROUTER:
|
||||||
|
return objectInstance == 0 ? &_rtObjPrimary : &_rtObjSecondary;
|
||||||
|
|
||||||
|
case OT_APPLICATION_PROG:
|
||||||
|
return &_appProgram;
|
||||||
|
|
||||||
|
case OT_RF_MEDIUM:
|
||||||
|
return &_rfMediumObject;
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
|
||||||
|
case OT_SECURITY:
|
||||||
|
return &_secIfObj;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
|
||||||
|
case OT_CEMI_SERVER:
|
||||||
|
return &_cemiServerObject;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau2920::doMasterReset(EraseCode eraseCode, uint8_t channel)
|
||||||
|
{
|
||||||
|
// Common SystemB objects
|
||||||
|
BauSystemBCoupler::doMasterReset(eraseCode, channel);
|
||||||
|
|
||||||
|
_rfMediumObject.masterReset(eraseCode, channel);
|
||||||
|
_rtObjPrimary.masterReset(eraseCode, channel);
|
||||||
|
_rtObjSecondary.masterReset(eraseCode, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bau2920::enabled()
|
||||||
|
{
|
||||||
|
return _dlLayerPrimary.enabled() && _dlLayerSecondary.enabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau2920::enabled(bool value)
|
||||||
|
{
|
||||||
|
_dlLayerPrimary.enabled(value);
|
||||||
|
_dlLayerSecondary.enabled(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau2920::loop()
|
||||||
|
{
|
||||||
|
_dlLayerPrimary.loop();
|
||||||
|
_dlLayerSecondary.loop();
|
||||||
|
BauSystemBCoupler::loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
TpUartDataLinkLayer* Bau2920::getPrimaryDataLinkLayer()
|
||||||
|
{
|
||||||
|
return (TpUartDataLinkLayer*)&_dlLayerPrimary;
|
||||||
|
}
|
||||||
|
|
||||||
|
RfDataLinkLayer* Bau2920::getSecondaryDataLinkLayer()
|
||||||
|
{
|
||||||
|
return (RfDataLinkLayer*)&_dlLayerSecondary;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
43
components/knx/src/knx/bau2920.h
Normal file
43
components/knx/src/knx/bau2920.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#if MASK_VERSION == 0x2920
|
||||||
|
|
||||||
|
#include "bau_systemB_coupler.h"
|
||||||
|
#include "tpuart_data_link_layer.h"
|
||||||
|
#if defined(DeviceFamily_CC13X0)
|
||||||
|
#include "rf_physical_layer_cc1310.h"
|
||||||
|
#else
|
||||||
|
#include "rf_physical_layer_cc1101.h"
|
||||||
|
#endif
|
||||||
|
#include "rf_data_link_layer.h"
|
||||||
|
#include "rf_medium_object.h"
|
||||||
|
#include "cemi_server_object.h"
|
||||||
|
|
||||||
|
class Bau2920 : public BauSystemBCoupler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Bau2920(Platform& platform);
|
||||||
|
void loop() override;
|
||||||
|
bool enabled() override;
|
||||||
|
void enabled(bool value) override;
|
||||||
|
|
||||||
|
TpUartDataLinkLayer* getPrimaryDataLinkLayer();
|
||||||
|
RfDataLinkLayer* getSecondaryDataLinkLayer();
|
||||||
|
protected:
|
||||||
|
InterfaceObject* getInterfaceObject(uint8_t idx);
|
||||||
|
InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance);
|
||||||
|
|
||||||
|
void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
||||||
|
private:
|
||||||
|
RouterObject _rtObjPrimary;
|
||||||
|
RouterObject _rtObjSecondary;
|
||||||
|
RfMediumObject _rfMediumObject;
|
||||||
|
TpUartDataLinkLayer _dlLayerPrimary;
|
||||||
|
RfDataLinkLayer _dlLayerSecondary;
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
CemiServer _cemiServer;
|
||||||
|
CemiServerObject _cemiServerObject;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
#endif
|
||||||
169
components/knx/src/knx/bau57B0.cpp
Normal file
169
components/knx/src/knx/bau57B0.cpp
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
#include "config.h"
|
||||||
|
#if MASK_VERSION == 0x57B0
|
||||||
|
|
||||||
|
#include "bau57B0.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
Bau57B0::Bau57B0(Platform& platform)
|
||||||
|
: BauSystemBDevice(platform), DataLinkLayerCallbacks(),
|
||||||
|
_ipParameters(_deviceObj, platform),
|
||||||
|
_dlLayer(_deviceObj, _ipParameters, _netLayer.getInterface(), _platform, (DataLinkLayerCallbacks*) this)
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
, _cemiServer(*this)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
_netLayer.getInterface().dataLinkLayer(_dlLayer);
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
_cemiServerObject.setMediumTypeAsSupported(DptMedium::KNX_IP);
|
||||||
|
_cemiServer.dataLinkLayer(_dlLayer);
|
||||||
|
_dlLayer.cemiServer(_cemiServer);
|
||||||
|
_memory.addSaveRestore(&_cemiServerObject);
|
||||||
|
#endif
|
||||||
|
_memory.addSaveRestore(&_ipParameters);
|
||||||
|
|
||||||
|
// Set Mask Version in Device Object depending on the BAU
|
||||||
|
_deviceObj.maskVersion(0x57B0);
|
||||||
|
|
||||||
|
// Set which interface objects are available in the device object
|
||||||
|
// This differs from BAU to BAU with different medium types.
|
||||||
|
// See PID_IO_LIST
|
||||||
|
Property* prop = _deviceObj.property(PID_IO_LIST);
|
||||||
|
prop->write(1, (uint16_t) OT_DEVICE);
|
||||||
|
prop->write(2, (uint16_t) OT_ADDR_TABLE);
|
||||||
|
prop->write(3, (uint16_t) OT_ASSOC_TABLE);
|
||||||
|
prop->write(4, (uint16_t) OT_GRP_OBJ_TABLE);
|
||||||
|
prop->write(5, (uint16_t) OT_APPLICATION_PROG);
|
||||||
|
prop->write(6, (uint16_t) OT_IP_PARAMETER);
|
||||||
|
#if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER)
|
||||||
|
prop->write(7, (uint16_t) OT_SECURITY);
|
||||||
|
prop->write(8, (uint16_t) OT_CEMI_SERVER);
|
||||||
|
#elif defined(USE_DATASECURE)
|
||||||
|
prop->write(7, (uint16_t) OT_SECURITY);
|
||||||
|
#elif defined(USE_CEMI_SERVER)
|
||||||
|
prop->write(7, (uint16_t) OT_CEMI_SERVER);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
InterfaceObject* Bau57B0::getInterfaceObject(uint8_t idx)
|
||||||
|
{
|
||||||
|
switch (idx)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return &_deviceObj;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
return &_addrTable;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
return &_assocTable;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
return &_groupObjTable;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
return &_appProgram;
|
||||||
|
|
||||||
|
case 5: // would be app_program 2
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
return &_ipParameters;
|
||||||
|
#if defined(USE_DATASECURE) && defined(USE_CEMI_SERVER)
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
return &_secIfObj;
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
return &_cemiServerObject;
|
||||||
|
#elif defined(USE_CEMI_SERVER)
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
return &_cemiServerObject;
|
||||||
|
#elif defined(USE_DATASECURE)
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
return &_secIfObj;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InterfaceObject* Bau57B0::getInterfaceObject(ObjectType objectType, uint16_t objectInstance)
|
||||||
|
{
|
||||||
|
// We do not use it right now.
|
||||||
|
// Required for coupler mode as there are multiple router objects for example
|
||||||
|
(void) objectInstance;
|
||||||
|
|
||||||
|
switch (objectType)
|
||||||
|
{
|
||||||
|
case OT_DEVICE:
|
||||||
|
return &_deviceObj;
|
||||||
|
|
||||||
|
case OT_ADDR_TABLE:
|
||||||
|
return &_addrTable;
|
||||||
|
|
||||||
|
case OT_ASSOC_TABLE:
|
||||||
|
return &_assocTable;
|
||||||
|
|
||||||
|
case OT_GRP_OBJ_TABLE:
|
||||||
|
return &_groupObjTable;
|
||||||
|
|
||||||
|
case OT_APPLICATION_PROG:
|
||||||
|
return &_appProgram;
|
||||||
|
|
||||||
|
case OT_IP_PARAMETER:
|
||||||
|
return &_ipParameters;
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
|
||||||
|
case OT_SECURITY:
|
||||||
|
return &_secIfObj;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
|
||||||
|
case OT_CEMI_SERVER:
|
||||||
|
return &_cemiServerObject;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau57B0::doMasterReset(EraseCode eraseCode, uint8_t channel)
|
||||||
|
{
|
||||||
|
// Common SystemB objects
|
||||||
|
BauSystemB::doMasterReset(eraseCode, channel);
|
||||||
|
|
||||||
|
_ipParameters.masterReset(eraseCode, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bau57B0::enabled()
|
||||||
|
{
|
||||||
|
return _dlLayer.enabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau57B0::enabled(bool value)
|
||||||
|
{
|
||||||
|
_dlLayer.enabled(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bau57B0::loop()
|
||||||
|
{
|
||||||
|
_dlLayer.loop();
|
||||||
|
BauSystemBDevice::loop();
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
_cemiServer.loop();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
IpDataLinkLayer* Bau57B0::getDataLinkLayer()
|
||||||
|
{
|
||||||
|
return (IpDataLinkLayer*)&_dlLayer;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
33
components/knx/src/knx/bau57B0.h
Normal file
33
components/knx/src/knx/bau57B0.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#if MASK_VERSION == 0x57B0
|
||||||
|
|
||||||
|
#include "bau_systemB_device.h"
|
||||||
|
#include "ip_parameter_object.h"
|
||||||
|
#include "ip_data_link_layer.h"
|
||||||
|
#include "cemi_server_object.h"
|
||||||
|
|
||||||
|
class Bau57B0 : public BauSystemBDevice, public DataLinkLayerCallbacks
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Bau57B0(Platform& platform);
|
||||||
|
void loop() override;
|
||||||
|
bool enabled() override;
|
||||||
|
void enabled(bool value) override;
|
||||||
|
|
||||||
|
IpDataLinkLayer* getDataLinkLayer();
|
||||||
|
protected:
|
||||||
|
InterfaceObject* getInterfaceObject(uint8_t idx);
|
||||||
|
InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance);
|
||||||
|
|
||||||
|
void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
||||||
|
private:
|
||||||
|
IpParameterObject _ipParameters;
|
||||||
|
IpDataLinkLayer _dlLayer;
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
CemiServer _cemiServer;
|
||||||
|
CemiServerObject _cemiServerObject;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
#endif
|
||||||
812
components/knx/src/knx/bau_systemB.cpp
Normal file
812
components/knx/src/knx/bau_systemB.cpp
Normal file
@ -0,0 +1,812 @@
|
|||||||
|
#include "bau_systemB.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
enum NmReadSerialNumberType
|
||||||
|
{
|
||||||
|
NM_Read_SerialNumber_By_ProgrammingMode = 0x01,
|
||||||
|
NM_Read_SerialNumber_By_ExFactoryState = 0x02,
|
||||||
|
NM_Read_SerialNumber_By_PowerReset = 0x03,
|
||||||
|
NM_Read_SerialNumber_By_ManufacturerSpecific = 0xFE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr auto kFunctionPropertyResultBufferMaxSize = 0xFF;
|
||||||
|
static constexpr auto kRestartProcessTime = 3;
|
||||||
|
|
||||||
|
BauSystemB::BauSystemB(Platform& platform): _memory(platform, _deviceObj),
|
||||||
|
_appProgram(_memory),
|
||||||
|
_platform(platform)
|
||||||
|
{
|
||||||
|
_memory.addSaveRestore(&_appProgram);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::readMemory()
|
||||||
|
{
|
||||||
|
_memory.readMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::writeMemory()
|
||||||
|
{
|
||||||
|
_memory.writeMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform& BauSystemB::platform()
|
||||||
|
{
|
||||||
|
return _platform;
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplicationProgramObject& BauSystemB::parameters()
|
||||||
|
{
|
||||||
|
return _appProgram;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceObject& BauSystemB::deviceObject()
|
||||||
|
{
|
||||||
|
return _deviceObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BauSystemB::checkmasterResetValidity(EraseCode eraseCode, uint8_t channel)
|
||||||
|
{
|
||||||
|
static constexpr uint8_t successCode = 0x00; // Where does this come from? It is the code for "success".
|
||||||
|
static constexpr uint8_t invalidEraseCode = 0x02; // Where does this come from? It is the error code for "unspported erase code".
|
||||||
|
|
||||||
|
switch (eraseCode)
|
||||||
|
{
|
||||||
|
case EraseCode::ConfirmedRestart:
|
||||||
|
{
|
||||||
|
println("Confirmed restart requested.");
|
||||||
|
return successCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EraseCode::ResetAP:
|
||||||
|
{
|
||||||
|
// TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER)
|
||||||
|
println("ResetAP requested. Not implemented yet.");
|
||||||
|
return successCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EraseCode::ResetIA:
|
||||||
|
{
|
||||||
|
// TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER)
|
||||||
|
println("ResetIA requested. Not implemented yet.");
|
||||||
|
return successCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EraseCode::ResetLinks:
|
||||||
|
{
|
||||||
|
// TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER)
|
||||||
|
println("ResetLinks requested. Not implemented yet.");
|
||||||
|
return successCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EraseCode::ResetParam:
|
||||||
|
{
|
||||||
|
// TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER)
|
||||||
|
println("ResetParam requested. Not implemented yet.");
|
||||||
|
return successCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EraseCode::FactoryReset:
|
||||||
|
{
|
||||||
|
// TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER)
|
||||||
|
println("Factory reset requested. type: with IA");
|
||||||
|
return successCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EraseCode::FactoryResetWithoutIA:
|
||||||
|
{
|
||||||
|
// TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER)
|
||||||
|
println("Factory reset requested. type: without IA");
|
||||||
|
return successCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
print("Unhandled erase code: ");
|
||||||
|
println(eraseCode, HEX);
|
||||||
|
return invalidEraseCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptorType)
|
||||||
|
{
|
||||||
|
if (descriptorType != 0)
|
||||||
|
descriptorType = 0x3f;
|
||||||
|
|
||||||
|
uint8_t data[2];
|
||||||
|
pushWord(_deviceObj.maskVersion(), data);
|
||||||
|
applicationLayer().deviceDescriptorReadResponse(AckRequested, priority, hopType, asap, secCtrl, descriptorType, data);
|
||||||
|
}
|
||||||
|
void BauSystemB::memoryRouterWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* data)
|
||||||
|
{
|
||||||
|
print("Writing memory at: ");
|
||||||
|
print(memoryAddress, HEX);
|
||||||
|
print(" length: ");
|
||||||
|
print(number);
|
||||||
|
print(" data: ");
|
||||||
|
printHex("=>", data, number);
|
||||||
|
_memory.writeMemory(memoryAddress, number, data);
|
||||||
|
|
||||||
|
if (_deviceObj.verifyMode())
|
||||||
|
{
|
||||||
|
print("Sending Read indication");
|
||||||
|
memoryRouterReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::memoryRouterReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* data)
|
||||||
|
{
|
||||||
|
applicationLayer().memoryRouterReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data)
|
||||||
|
{
|
||||||
|
applicationLayer().memoryRoutingTableReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, data);
|
||||||
|
}
|
||||||
|
void BauSystemB::memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress)
|
||||||
|
{
|
||||||
|
memoryRoutingTableReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress, _memory.toAbsolute(memoryAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::memoryRoutingTableWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data)
|
||||||
|
{
|
||||||
|
print("Writing memory at: ");
|
||||||
|
print(memoryAddress, HEX);
|
||||||
|
print(" length: ");
|
||||||
|
print(number);
|
||||||
|
print(" data: ");
|
||||||
|
printHex("=>", data, number);
|
||||||
|
_memory.writeMemory(memoryAddress, number, data);
|
||||||
|
|
||||||
|
if (_deviceObj.verifyMode())
|
||||||
|
memoryRoutingTableReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* data)
|
||||||
|
{
|
||||||
|
_memory.writeMemory(memoryAddress, number, data);
|
||||||
|
|
||||||
|
if (_deviceObj.verifyMode())
|
||||||
|
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,
|
||||||
|
uint16_t memoryAddress)
|
||||||
|
{
|
||||||
|
applicationLayer().memoryReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress,
|
||||||
|
_memory.toAbsolute(memoryAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::memoryExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data)
|
||||||
|
{
|
||||||
|
_memory.writeMemory(memoryAddress, number, data);
|
||||||
|
|
||||||
|
applicationLayer().memoryExtWriteResponse(AckRequested, priority, hopType, asap, secCtrl, ReturnCodes::Success, number, memoryAddress, _memory.toAbsolute(memoryAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::memoryExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress)
|
||||||
|
{
|
||||||
|
applicationLayer().memoryExtReadResponse(AckRequested, priority, hopType, asap, secCtrl, ReturnCodes::Success, number, memoryAddress, _memory.toAbsolute(memoryAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::doMasterReset(EraseCode eraseCode, uint8_t channel)
|
||||||
|
{
|
||||||
|
_deviceObj.masterReset(eraseCode, channel);
|
||||||
|
_appProgram.masterReset(eraseCode, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, RestartType restartType, EraseCode eraseCode, uint8_t channel)
|
||||||
|
{
|
||||||
|
if (restartType == RestartType::BasicRestart)
|
||||||
|
{
|
||||||
|
println("Basic restart requested");
|
||||||
|
|
||||||
|
if (_beforeRestart != 0)
|
||||||
|
_beforeRestart();
|
||||||
|
}
|
||||||
|
else if (restartType == RestartType::MasterReset)
|
||||||
|
{
|
||||||
|
uint8_t errorCode = checkmasterResetValidity(eraseCode, channel);
|
||||||
|
// We send the restart response now before actually applying the reset values
|
||||||
|
// Processing time is kRestartProcessTime (example 3 seconds) that we require for the applying the master reset with restart
|
||||||
|
applicationLayer().restartResponse(AckRequested, priority, hopType, secCtrl, errorCode, (errorCode == 0) ? kRestartProcessTime : 0);
|
||||||
|
doMasterReset(eraseCode, channel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Cannot happen as restartType is just one bit
|
||||||
|
println("Unhandled restart type.");
|
||||||
|
_platform.fatalError();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush the EEPROM before resetting
|
||||||
|
_memory.writeMemory();
|
||||||
|
_platform.restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key)
|
||||||
|
{
|
||||||
|
applicationLayer().authorizeResponse(AckRequested, priority, hopType, asap, secCtrl, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress)
|
||||||
|
{
|
||||||
|
applicationLayer().userMemoryReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress,
|
||||||
|
_memory.toAbsolute(memoryAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data)
|
||||||
|
{
|
||||||
|
_memory.writeMemory(memoryAddress, number, data);
|
||||||
|
|
||||||
|
if (_deviceObj.verifyMode())
|
||||||
|
userMemoryReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t propertyIndex)
|
||||||
|
{
|
||||||
|
uint8_t pid = propertyId;
|
||||||
|
bool writeEnable = false;
|
||||||
|
uint8_t type = 0;
|
||||||
|
uint16_t numberOfElements = 0;
|
||||||
|
uint8_t access = 0;
|
||||||
|
InterfaceObject* obj = getInterfaceObject(objectIndex);
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
obj->readPropertyDescription(pid, propertyIndex, writeEnable, type, numberOfElements, access);
|
||||||
|
|
||||||
|
applicationLayer().propertyDescriptionReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, pid, propertyIndex,
|
||||||
|
writeEnable, type, numberOfElements, access);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::propertyExtDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint16_t objectType, uint16_t objectInstance, uint16_t propertyId, uint8_t descriptionType, uint16_t propertyIndex)
|
||||||
|
{
|
||||||
|
uint8_t pid = propertyId;
|
||||||
|
uint8_t pidx = propertyIndex;
|
||||||
|
|
||||||
|
if (propertyId > 0xFF || propertyIndex > 0xFF)
|
||||||
|
{
|
||||||
|
println("BauSystemB::propertyExtDescriptionReadIndication: propertyId or Idx > 256 are not supported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptionType != 0)
|
||||||
|
{
|
||||||
|
println("BauSystemB::propertyExtDescriptionReadIndication: only descriptionType 0 supported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool writeEnable = false;
|
||||||
|
uint8_t type = 0;
|
||||||
|
uint16_t numberOfElements = 0;
|
||||||
|
uint8_t access = 0;
|
||||||
|
InterfaceObject* obj = getInterfaceObject((ObjectType)objectType, objectInstance);
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
obj->readPropertyDescription(pid, pidx, writeEnable, type, numberOfElements, access);
|
||||||
|
|
||||||
|
applicationLayer().propertyExtDescriptionReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, propertyIndex,
|
||||||
|
descriptionType, writeEnable, type, numberOfElements, access);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::propertyValueWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
InterfaceObject* obj = getInterfaceObject(objectIndex);
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
obj->writeProperty((PropertyID)propertyId, startIndex, data, numberOfElements);
|
||||||
|
|
||||||
|
propertyValueReadIndication(priority, hopType, asap, secCtrl, objectIndex, propertyId, numberOfElements, startIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::propertyValueExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool confirmed)
|
||||||
|
{
|
||||||
|
uint8_t returnCode = ReturnCodes::Success;
|
||||||
|
|
||||||
|
InterfaceObject* obj = getInterfaceObject(objectType, objectInstance);
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
obj->writeProperty((PropertyID)propertyId, startIndex, data, numberOfElements);
|
||||||
|
else
|
||||||
|
returnCode = ReturnCodes::AddressVoid;
|
||||||
|
|
||||||
|
if (confirmed)
|
||||||
|
{
|
||||||
|
applicationLayer().propertyValueExtWriteConResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, numberOfElements, startIndex, returnCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex)
|
||||||
|
{
|
||||||
|
uint8_t size = 0;
|
||||||
|
uint8_t elementCount = numberOfElements;
|
||||||
|
#ifdef LOG_KNX_PROP
|
||||||
|
print("propertyValueReadIndication: ObjIdx ");
|
||||||
|
print(objectIndex);
|
||||||
|
print(" propId ");
|
||||||
|
print(propertyId);
|
||||||
|
print(" num ");
|
||||||
|
print(numberOfElements);
|
||||||
|
print(" start ");
|
||||||
|
print(startIndex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
InterfaceObject* obj = getInterfaceObject(objectIndex);
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
{
|
||||||
|
uint8_t elementSize = obj->propertySize((PropertyID)propertyId);
|
||||||
|
|
||||||
|
if (startIndex > 0)
|
||||||
|
size = elementSize * numberOfElements;
|
||||||
|
else
|
||||||
|
size = sizeof(uint16_t); // size of property array entry 0 which contains the current number of elements
|
||||||
|
}
|
||||||
|
else
|
||||||
|
elementCount = 0;
|
||||||
|
|
||||||
|
uint8_t data[size];
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
obj->readProperty((PropertyID)propertyId, startIndex, elementCount, data);
|
||||||
|
|
||||||
|
if (elementCount == 0)
|
||||||
|
size = 0;
|
||||||
|
|
||||||
|
applicationLayer().propertyValueReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, propertyId, elementCount,
|
||||||
|
startIndex, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::propertyValueExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex)
|
||||||
|
{
|
||||||
|
uint8_t size = 0;
|
||||||
|
uint8_t elementCount = numberOfElements;
|
||||||
|
InterfaceObject* obj = getInterfaceObject(objectType, objectInstance);
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
{
|
||||||
|
uint8_t elementSize = obj->propertySize((PropertyID)propertyId);
|
||||||
|
|
||||||
|
if (startIndex > 0)
|
||||||
|
size = elementSize * numberOfElements;
|
||||||
|
else
|
||||||
|
size = sizeof(uint16_t); // size of propert array entry 0 which is the size
|
||||||
|
}
|
||||||
|
else
|
||||||
|
elementCount = 0;
|
||||||
|
|
||||||
|
uint8_t data[size];
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
obj->readProperty((PropertyID)propertyId, startIndex, elementCount, data);
|
||||||
|
|
||||||
|
if (elementCount == 0)
|
||||||
|
size = 0;
|
||||||
|
|
||||||
|
applicationLayer().propertyValueExtReadResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, elementCount,
|
||||||
|
startIndex, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::functionPropertyCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
uint8_t resultData[kFunctionPropertyResultBufferMaxSize];
|
||||||
|
uint8_t resultLength = sizeof(resultData); // tell the callee the maximum size of the buffer
|
||||||
|
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
InterfaceObject* obj = getInterfaceObject(objectIndex);
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
{
|
||||||
|
if (obj->property((PropertyID)propertyId)->Type() == PDT_FUNCTION)
|
||||||
|
{
|
||||||
|
obj->command((PropertyID)propertyId, data, length, resultData, resultLength);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_functionProperty != 0)
|
||||||
|
if (_functionProperty(objectIndex, propertyId, length, data, resultData, resultLength))
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_functionProperty != 0)
|
||||||
|
if (_functionProperty(objectIndex, propertyId, length, data, resultData, resultLength))
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//only return a value it was handled by a property or function
|
||||||
|
if (handled)
|
||||||
|
applicationLayer().functionPropertyStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, propertyId, resultData, resultLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::functionPropertyStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
uint8_t resultData[kFunctionPropertyResultBufferMaxSize];
|
||||||
|
uint8_t resultLength = sizeof(resultData); // tell the callee the maximum size of the buffer
|
||||||
|
|
||||||
|
bool handled = true;
|
||||||
|
|
||||||
|
InterfaceObject* obj = getInterfaceObject(objectIndex);
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
{
|
||||||
|
if (obj->property((PropertyID)propertyId)->Type() == PDT_FUNCTION)
|
||||||
|
{
|
||||||
|
obj->state((PropertyID)propertyId, data, length, resultData, resultLength);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_functionPropertyState != 0)
|
||||||
|
if (_functionPropertyState(objectIndex, propertyId, length, data, resultData, resultLength))
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_functionPropertyState != 0)
|
||||||
|
if (_functionPropertyState(objectIndex, propertyId, length, data, resultData, resultLength))
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//only return a value it was handled by a property or function
|
||||||
|
if (handled)
|
||||||
|
applicationLayer().functionPropertyStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectIndex, propertyId, resultData, resultLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::functionPropertyExtCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance,
|
||||||
|
uint8_t propertyId, uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
uint8_t resultData[kFunctionPropertyResultBufferMaxSize];
|
||||||
|
uint8_t resultLength = 1; // we always have to include the return code at least
|
||||||
|
|
||||||
|
InterfaceObject* obj = getInterfaceObject(objectType, objectInstance);
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
{
|
||||||
|
PropertyDataType propType = obj->property((PropertyID)propertyId)->Type();
|
||||||
|
|
||||||
|
if (propType == PDT_FUNCTION)
|
||||||
|
{
|
||||||
|
// The first byte is reserved and 0 for PDT_FUNCTION
|
||||||
|
uint8_t reservedByte = data[0];
|
||||||
|
|
||||||
|
if (reservedByte != 0x00)
|
||||||
|
{
|
||||||
|
resultData[0] = ReturnCodes::DataVoid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultLength = sizeof(resultData); // tell the callee the maximum size of the buffer
|
||||||
|
obj->command((PropertyID)propertyId, data, length, resultData, resultLength);
|
||||||
|
// resultLength was modified by the callee
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (propType == PDT_CONTROL)
|
||||||
|
{
|
||||||
|
uint8_t count = 1;
|
||||||
|
// write the event
|
||||||
|
obj->writeProperty((PropertyID)propertyId, 1, data, count);
|
||||||
|
|
||||||
|
if (count == 1)
|
||||||
|
{
|
||||||
|
// Read the current state (one byte only) for the response
|
||||||
|
obj->readProperty((PropertyID)propertyId, 1, count, &resultData[1]);
|
||||||
|
resultLength = count ? 2 : 1;
|
||||||
|
resultData[0] = count ? ReturnCodes::Success : ReturnCodes::DataVoid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultData[0] = ReturnCodes::AddressVoid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultData[0] = ReturnCodes::DataTypeConflict;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultData[0] = ReturnCodes::GenericError;
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationLayer().functionPropertyExtStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, resultData, resultLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::functionPropertyExtStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance,
|
||||||
|
uint8_t propertyId, uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
uint8_t resultData[kFunctionPropertyResultBufferMaxSize];
|
||||||
|
uint8_t resultLength = sizeof(resultData); // tell the callee the maximum size of the buffer
|
||||||
|
|
||||||
|
InterfaceObject* obj = getInterfaceObject(objectType, objectInstance);
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
{
|
||||||
|
PropertyDataType propType = obj->property((PropertyID)propertyId)->Type();
|
||||||
|
|
||||||
|
if (propType == PDT_FUNCTION)
|
||||||
|
{
|
||||||
|
// The first byte is reserved and 0 for PDT_FUNCTION
|
||||||
|
uint8_t reservedByte = data[0];
|
||||||
|
|
||||||
|
if (reservedByte != 0x00)
|
||||||
|
{
|
||||||
|
resultData[0] = ReturnCodes::DataVoid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultLength = sizeof(resultData); // tell the callee the maximum size of the buffer
|
||||||
|
obj->state((PropertyID)propertyId, data, length, resultData, resultLength);
|
||||||
|
// resultLength was modified by the callee
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (propType == PDT_CONTROL)
|
||||||
|
{
|
||||||
|
uint8_t count = 1;
|
||||||
|
// Read the current state (one byte only) for the response
|
||||||
|
obj->readProperty((PropertyID)propertyId, 1, count, &resultData[1]);
|
||||||
|
resultLength = count ? 2 : 1;
|
||||||
|
resultData[0] = count ? ReturnCodes::Success : ReturnCodes::DataVoid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultData[0] = ReturnCodes::DataTypeConflict;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultData[0] = ReturnCodes::GenericError;
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationLayer().functionPropertyExtStateResponse(AckRequested, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, resultData, resultLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::individualAddressReadIndication(HopCountType hopType, const SecurityControl& secCtrl)
|
||||||
|
{
|
||||||
|
if (_deviceObj.progMode())
|
||||||
|
applicationLayer().individualAddressReadResponse(AckRequested, hopType, secCtrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::individualAddressWriteIndication(HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress)
|
||||||
|
{
|
||||||
|
if (_deviceObj.progMode())
|
||||||
|
_deviceObj.individualAddress(newaddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::individualAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newIndividualAddress,
|
||||||
|
uint8_t* knxSerialNumber)
|
||||||
|
{
|
||||||
|
// If the received serial number matches our serial number
|
||||||
|
// then store the received new individual address in the device object
|
||||||
|
if (!memcmp(knxSerialNumber, _deviceObj.propertyData(PID_SERIAL_NUMBER), 6))
|
||||||
|
_deviceObj.individualAddress(newIndividualAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber)
|
||||||
|
{
|
||||||
|
// If the received serial number matches our serial number
|
||||||
|
// then send a response with the serial number. The domain address is set to 0 for closed media.
|
||||||
|
// An open medium BAU has to override this method and provide a proper domain address.
|
||||||
|
if (!memcmp(knxSerialNumber, _deviceObj.propertyData(PID_SERIAL_NUMBER), 6))
|
||||||
|
{
|
||||||
|
uint8_t emptyDomainAddress[2] = {0x00};
|
||||||
|
applicationLayer().IndividualAddressSerialNumberReadResponse(priority, hopType, secCtrl, emptyDomainAddress, knxSerialNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::addSaveRestore(SaveRestore* obj)
|
||||||
|
{
|
||||||
|
_memory.addSaveRestore(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BauSystemB::restartRequest(uint16_t asap, const SecurityControl secCtrl)
|
||||||
|
{
|
||||||
|
if (applicationLayer().isConnected())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_restartState = Connecting; // order important, has to be set BEFORE connectRequest
|
||||||
|
_restartSecurity = secCtrl;
|
||||||
|
applicationLayer().connectRequest(asap, SystemPriority);
|
||||||
|
applicationLayer().deviceDescriptorReadRequest(AckRequested, SystemPriority, NetworkLayerParameter, asap, secCtrl, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::connectConfirm(uint16_t tsap)
|
||||||
|
{
|
||||||
|
if (_restartState == Connecting)
|
||||||
|
{
|
||||||
|
/* restart connection is confirmed, go to the next state */
|
||||||
|
_restartState = Connected;
|
||||||
|
_restartDelay = millis();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_restartState = Idle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::nextRestartState()
|
||||||
|
{
|
||||||
|
switch (_restartState)
|
||||||
|
{
|
||||||
|
case Idle:
|
||||||
|
/* inactive state, do nothing */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Connecting:
|
||||||
|
/* wait for connection, we do nothing here */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Connected:
|
||||||
|
|
||||||
|
/* connection confirmed, we send restartRequest, but we wait a moment (sending ACK etc)... */
|
||||||
|
if (millis() - _restartDelay > 30)
|
||||||
|
{
|
||||||
|
applicationLayer().restartRequest(AckRequested, SystemPriority, NetworkLayerParameter, _restartSecurity);
|
||||||
|
_restartState = Restarted;
|
||||||
|
_restartDelay = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Restarted:
|
||||||
|
|
||||||
|
/* restart is finished, we send a disconnect */
|
||||||
|
if (millis() - _restartDelay > 30)
|
||||||
|
{
|
||||||
|
applicationLayer().disconnectRequest(SystemPriority);
|
||||||
|
_restartState = Idle;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::systemNetworkParameterReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType,
|
||||||
|
uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength)
|
||||||
|
{
|
||||||
|
uint8_t operand;
|
||||||
|
|
||||||
|
popByte(operand, testInfo + 1); // First byte (+ 0) contains only 4 reserved bits (0)
|
||||||
|
|
||||||
|
// See KNX spec. 3.5.2 p.33 (Management Procedures: Procedures with A_SystemNetworkParameter_Read)
|
||||||
|
switch ((NmReadSerialNumberType)operand)
|
||||||
|
{
|
||||||
|
case NM_Read_SerialNumber_By_ProgrammingMode: // NM_Read_SerialNumber_By_ProgrammingMode
|
||||||
|
|
||||||
|
// Only send a reply if programming mode is on
|
||||||
|
if (_deviceObj.progMode() && (objectType == OT_DEVICE) && (propertyId == PID_SERIAL_NUMBER))
|
||||||
|
{
|
||||||
|
// Send reply. testResult data is KNX serial number
|
||||||
|
applicationLayer().systemNetworkParameterReadResponse(priority, hopType, secCtrl, objectType, propertyId,
|
||||||
|
testInfo, testInfoLength, (uint8_t*)_deviceObj.propertyData(PID_SERIAL_NUMBER), 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NM_Read_SerialNumber_By_ExFactoryState: // NM_Read_SerialNumber_By_ExFactoryState
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NM_Read_SerialNumber_By_PowerReset: // NM_Read_SerialNumber_By_PowerReset
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NM_Read_SerialNumber_By_ManufacturerSpecific: // Manufacturer specific use of A_SystemNetworkParameter_Read
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::systemNetworkParameterReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType,
|
||||||
|
uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength, bool status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::propertyValueRead(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId,
|
||||||
|
uint8_t& numberOfElements, uint16_t startIndex,
|
||||||
|
uint8_t** data, uint32_t& length)
|
||||||
|
{
|
||||||
|
uint32_t size = 0;
|
||||||
|
uint8_t elementCount = numberOfElements;
|
||||||
|
|
||||||
|
InterfaceObject* obj = getInterfaceObject(objectType, objectInstance);
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
{
|
||||||
|
uint8_t elementSize = obj->propertySize((PropertyID)propertyId);
|
||||||
|
|
||||||
|
if (startIndex > 0)
|
||||||
|
size = elementSize * numberOfElements;
|
||||||
|
else
|
||||||
|
size = sizeof(uint16_t); // size of property array entry 0 which contains the current number of elements
|
||||||
|
|
||||||
|
*data = new uint8_t [size];
|
||||||
|
obj->readProperty((PropertyID)propertyId, startIndex, elementCount, *data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
elementCount = 0;
|
||||||
|
*data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
numberOfElements = elementCount;
|
||||||
|
length = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId,
|
||||||
|
uint8_t& numberOfElements, uint16_t startIndex,
|
||||||
|
uint8_t* data, uint32_t length)
|
||||||
|
{
|
||||||
|
InterfaceObject* obj = getInterfaceObject(objectType, objectInstance);
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
obj->writeProperty((PropertyID)propertyId, startIndex, data, numberOfElements);
|
||||||
|
else
|
||||||
|
numberOfElements = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Memory& BauSystemB::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemB::functionPropertyCallback(FunctionPropertyCallback func)
|
||||||
|
{
|
||||||
|
_functionProperty = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionPropertyCallback BauSystemB::functionPropertyCallback()
|
||||||
|
{
|
||||||
|
return _functionProperty;
|
||||||
|
}
|
||||||
|
void BauSystemB::functionPropertyStateCallback(FunctionPropertyCallback func)
|
||||||
|
{
|
||||||
|
_functionPropertyState = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionPropertyCallback BauSystemB::functionPropertyStateCallback()
|
||||||
|
{
|
||||||
|
return _functionPropertyState;
|
||||||
|
}
|
||||||
133
components/knx/src/knx/bau_systemB.h
Normal file
133
components/knx/src/knx/bau_systemB.h
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "bau.h"
|
||||||
|
#include "security_interface_object.h"
|
||||||
|
#include "application_program_object.h"
|
||||||
|
#include "application_layer.h"
|
||||||
|
#include "secure_application_layer.h"
|
||||||
|
#include "transport_layer.h"
|
||||||
|
#include "network_layer.h"
|
||||||
|
#include "data_link_layer.h"
|
||||||
|
#include "platform.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
class BauSystemB : protected BusAccessUnit
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BauSystemB(Platform& platform);
|
||||||
|
virtual void loop() = 0;
|
||||||
|
virtual bool configured() = 0;
|
||||||
|
virtual bool enabled() = 0;
|
||||||
|
virtual void enabled(bool value) = 0;
|
||||||
|
|
||||||
|
Platform& platform();
|
||||||
|
ApplicationProgramObject& parameters();
|
||||||
|
DeviceObject& deviceObject();
|
||||||
|
|
||||||
|
Memory& memory();
|
||||||
|
void readMemory();
|
||||||
|
void writeMemory();
|
||||||
|
void addSaveRestore(SaveRestore* obj);
|
||||||
|
|
||||||
|
bool restartRequest(uint16_t asap, const SecurityControl secCtrl);
|
||||||
|
uint8_t checkmasterResetValidity(EraseCode eraseCode, uint8_t channel);
|
||||||
|
|
||||||
|
void propertyValueRead(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId,
|
||||||
|
uint8_t& numberOfElements, uint16_t startIndex,
|
||||||
|
uint8_t** data, uint32_t& length) override;
|
||||||
|
void propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId,
|
||||||
|
uint8_t& numberOfElements, uint16_t startIndex,
|
||||||
|
uint8_t* data, uint32_t length) override;
|
||||||
|
void versionCheckCallback(VersionCheckCallback func);
|
||||||
|
VersionCheckCallback versionCheckCallback();
|
||||||
|
void beforeRestartCallback(BeforeRestartCallback func);
|
||||||
|
BeforeRestartCallback beforeRestartCallback();
|
||||||
|
void functionPropertyCallback(FunctionPropertyCallback func);
|
||||||
|
FunctionPropertyCallback functionPropertyCallback();
|
||||||
|
void functionPropertyStateCallback(FunctionPropertyCallback func);
|
||||||
|
FunctionPropertyCallback functionPropertyStateCallback();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ApplicationLayer& applicationLayer() = 0;
|
||||||
|
virtual InterfaceObject* getInterfaceObject(uint8_t idx) = 0;
|
||||||
|
virtual InterfaceObject* getInterfaceObject(ObjectType objectType, uint16_t objectInstance) = 0;
|
||||||
|
|
||||||
|
void memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* data) override;
|
||||||
|
void memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
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 memoryRouterWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* data);
|
||||||
|
void memoryRouterReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* data);
|
||||||
|
void memoryRoutingTableWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint16_t memoryAddress, uint8_t* data);
|
||||||
|
void memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress, uint8_t* data);
|
||||||
|
void memoryRoutingTableReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint16_t memoryAddress);
|
||||||
|
//
|
||||||
|
void memoryExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress, uint8_t* data) override;
|
||||||
|
void memoryExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress) override;
|
||||||
|
void deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t descriptorType) override;
|
||||||
|
void restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, RestartType restartType, EraseCode eraseCode, uint8_t channel) override;
|
||||||
|
void authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint32_t key) override;
|
||||||
|
void userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number, uint32_t memoryAddress) override;
|
||||||
|
void userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
|
||||||
|
uint32_t memoryAddress, uint8_t* memoryData) override;
|
||||||
|
void propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t propertyIndex) override;
|
||||||
|
void propertyExtDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
|
||||||
|
uint16_t objectType, uint16_t objectInstance, uint16_t propertyId, uint8_t descriptionType, uint16_t propertyIndex) override;
|
||||||
|
void propertyValueWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length) override;
|
||||||
|
void propertyValueExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length, bool confirmed);
|
||||||
|
void propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) override;
|
||||||
|
void propertyValueExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance,
|
||||||
|
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) override;
|
||||||
|
void functionPropertyCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t* data, uint8_t length) override;
|
||||||
|
void functionPropertyStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t objectIndex,
|
||||||
|
uint8_t propertyId, uint8_t* data, uint8_t length) override;
|
||||||
|
void functionPropertyExtCommandIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance,
|
||||||
|
uint8_t propertyId, uint8_t* data, uint8_t length) override;
|
||||||
|
void functionPropertyExtStateIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ObjectType objectType, uint8_t objectInstance,
|
||||||
|
uint8_t propertyId, uint8_t* data, uint8_t length) override;
|
||||||
|
void individualAddressReadIndication(HopCountType hopType, const SecurityControl& secCtrl) override;
|
||||||
|
void individualAddressWriteIndication(HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress) override;
|
||||||
|
void individualAddressSerialNumberWriteIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newIndividualAddress,
|
||||||
|
uint8_t* knxSerialNumber) override;
|
||||||
|
void individualAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* knxSerialNumber) override;
|
||||||
|
void systemNetworkParameterReadIndication(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType,
|
||||||
|
uint16_t propertyId, uint8_t* testInfo, uint16_t testinfoLength) override;
|
||||||
|
void systemNetworkParameterReadLocalConfirm(Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint16_t objectType,
|
||||||
|
uint16_t propertyId, uint8_t* testInfo, uint16_t testInfoLength, bool status) override;
|
||||||
|
void connectConfirm(uint16_t tsap) override;
|
||||||
|
|
||||||
|
void nextRestartState();
|
||||||
|
virtual void doMasterReset(EraseCode eraseCode, uint8_t channel);
|
||||||
|
|
||||||
|
enum RestartState
|
||||||
|
{
|
||||||
|
Idle,
|
||||||
|
Connecting,
|
||||||
|
Connected,
|
||||||
|
Restarted
|
||||||
|
};
|
||||||
|
|
||||||
|
Memory _memory;
|
||||||
|
DeviceObject _deviceObj;
|
||||||
|
ApplicationProgramObject _appProgram;
|
||||||
|
Platform& _platform;
|
||||||
|
RestartState _restartState = Idle;
|
||||||
|
SecurityControl _restartSecurity;
|
||||||
|
uint32_t _restartDelay = 0;
|
||||||
|
BeforeRestartCallback _beforeRestart = 0;
|
||||||
|
FunctionPropertyCallback _functionProperty = 0;
|
||||||
|
FunctionPropertyCallback _functionPropertyState = 0;
|
||||||
|
};
|
||||||
60
components/knx/src/knx/bau_systemB_coupler.cpp
Normal file
60
components/knx/src/knx/bau_systemB_coupler.cpp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#include "bau_systemB_coupler.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
BauSystemBCoupler::BauSystemBCoupler(Platform& platform) :
|
||||||
|
BauSystemB(platform),
|
||||||
|
_platform(platform),
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
_appLayer(_deviceObj, _secIfObj, *this),
|
||||||
|
#else
|
||||||
|
_appLayer(*this),
|
||||||
|
#endif
|
||||||
|
_transLayer(_appLayer),
|
||||||
|
_netLayer(_deviceObj, _transLayer)
|
||||||
|
{
|
||||||
|
_appLayer.transportLayer(_transLayer);
|
||||||
|
_transLayer.networkLayer(_netLayer);
|
||||||
|
_memory.addSaveRestore(&_deviceObj);
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
_memory.addSaveRestore(&_secIfObj);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplicationLayer& BauSystemBCoupler::applicationLayer()
|
||||||
|
{
|
||||||
|
return _appLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemBCoupler::loop()
|
||||||
|
{
|
||||||
|
_transLayer.loop();
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
_appLayer.loop();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BauSystemBCoupler::configured()
|
||||||
|
{
|
||||||
|
// _configured is set to true initially, if the device was configured with ETS it will be set to true after restart
|
||||||
|
|
||||||
|
if (!_configured)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_configured = _appProgram.loadState() == LS_LOADED;
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
_configured &= _secIfObj.loadState() == LS_LOADED;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return _configured;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemBCoupler::doMasterReset(EraseCode eraseCode, uint8_t channel)
|
||||||
|
{
|
||||||
|
BauSystemB::doMasterReset(eraseCode, channel);
|
||||||
|
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
_secIfObj.masterReset(eraseCode, channel);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
40
components/knx/src/knx/bau_systemB_coupler.h
Normal file
40
components/knx/src/knx/bau_systemB_coupler.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "bau_systemB.h"
|
||||||
|
#include "device_object.h"
|
||||||
|
#include "security_interface_object.h"
|
||||||
|
#include "application_program_object.h"
|
||||||
|
#include "router_object.h"
|
||||||
|
#include "application_layer.h"
|
||||||
|
#include "secure_application_layer.h"
|
||||||
|
#include "transport_layer.h"
|
||||||
|
#include "network_layer_coupler.h"
|
||||||
|
#include "data_link_layer.h"
|
||||||
|
#include "platform.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
class BauSystemBCoupler : public BauSystemB
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BauSystemBCoupler(Platform& platform);
|
||||||
|
void loop() override;
|
||||||
|
bool configured() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ApplicationLayer& applicationLayer() override;
|
||||||
|
|
||||||
|
void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
||||||
|
|
||||||
|
Platform& _platform;
|
||||||
|
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
SecureApplicationLayer _appLayer;
|
||||||
|
SecurityInterfaceObject _secIfObj;
|
||||||
|
#else
|
||||||
|
ApplicationLayer _appLayer;
|
||||||
|
#endif
|
||||||
|
TransportLayer _transLayer;
|
||||||
|
NetworkLayerCoupler _netLayer;
|
||||||
|
bool _configured = true;
|
||||||
|
};
|
||||||
262
components/knx/src/knx/bau_systemB_device.cpp
Normal file
262
components/knx/src/knx/bau_systemB_device.cpp
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
#include "bau_systemB_device.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
BauSystemBDevice::BauSystemBDevice(Platform& platform) :
|
||||||
|
BauSystemB(platform),
|
||||||
|
_addrTable(_memory),
|
||||||
|
_assocTable(_memory), _groupObjTable(_memory),
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
_appLayer(_deviceObj, _secIfObj, *this),
|
||||||
|
#else
|
||||||
|
_appLayer(*this),
|
||||||
|
#endif
|
||||||
|
_transLayer(_appLayer), _netLayer(_deviceObj, _transLayer)
|
||||||
|
{
|
||||||
|
_appLayer.transportLayer(_transLayer);
|
||||||
|
_appLayer.associationTableObject(_assocTable);
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
_appLayer.groupAddressTable(_addrTable);
|
||||||
|
#endif
|
||||||
|
_transLayer.networkLayer(_netLayer);
|
||||||
|
_transLayer.groupAddressTable(_addrTable);
|
||||||
|
|
||||||
|
_memory.addSaveRestore(&_deviceObj);
|
||||||
|
_memory.addSaveRestore(&_groupObjTable); // changed order for better memory management
|
||||||
|
_memory.addSaveRestore(&_addrTable);
|
||||||
|
_memory.addSaveRestore(&_assocTable);
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
_memory.addSaveRestore(&_secIfObj);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplicationLayer& BauSystemBDevice::applicationLayer()
|
||||||
|
{
|
||||||
|
return _appLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupObjectTableObject& BauSystemBDevice::groupObjectTable()
|
||||||
|
{
|
||||||
|
return _groupObjTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemBDevice::loop()
|
||||||
|
{
|
||||||
|
_transLayer.loop();
|
||||||
|
sendNextGroupTelegram();
|
||||||
|
nextRestartState();
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
_appLayer.loop();
|
||||||
|
#endif
|
||||||
|
_memory.loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemBDevice::sendNextGroupTelegram()
|
||||||
|
{
|
||||||
|
if (!configured())
|
||||||
|
return;
|
||||||
|
|
||||||
|
static uint16_t startIdx = 1;
|
||||||
|
|
||||||
|
GroupObjectTableObject& table = _groupObjTable;
|
||||||
|
uint16_t objCount = table.entryCount();
|
||||||
|
|
||||||
|
for (uint16_t asap = startIdx; asap <= objCount; asap++)
|
||||||
|
{
|
||||||
|
GroupObject& go = table.get(asap);
|
||||||
|
|
||||||
|
ComFlag flag = go.commFlag();
|
||||||
|
|
||||||
|
if (flag != ReadRequest && flag != WriteRequest)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (flag == WriteRequest)
|
||||||
|
{
|
||||||
|
#ifdef SMALL_GROUPOBJECT
|
||||||
|
GroupObject::processClassCallback(go);
|
||||||
|
#else
|
||||||
|
GroupObjectUpdatedHandler handler = go.callback();
|
||||||
|
|
||||||
|
if (handler)
|
||||||
|
handler(go);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!go.communicationEnable())
|
||||||
|
{
|
||||||
|
go.commFlag(Ok);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SecurityControl goSecurity;
|
||||||
|
goSecurity.toolAccess = false; // Secured group communication never uses the toolkey. ETS knows all keys, also the group keys.
|
||||||
|
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
// Get security flags from Security Interface Object for this group object
|
||||||
|
goSecurity.dataSecurity = _secIfObj.getGroupObjectSecurity(asap);
|
||||||
|
#else
|
||||||
|
goSecurity.dataSecurity = DataSecurity::None;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (flag == WriteRequest && go.transmitEnable())
|
||||||
|
{
|
||||||
|
uint8_t* data = go.valueRef();
|
||||||
|
_appLayer.groupValueWriteRequest(AckRequested, asap, go.priority(), NetworkLayerParameter, goSecurity, data,
|
||||||
|
go.sizeInTelegram());
|
||||||
|
}
|
||||||
|
else if (flag == ReadRequest)
|
||||||
|
{
|
||||||
|
_appLayer.groupValueReadRequest(AckRequested, asap, go.priority(), NetworkLayerParameter, goSecurity);
|
||||||
|
}
|
||||||
|
|
||||||
|
go.commFlag(Transmitting);
|
||||||
|
|
||||||
|
startIdx = asap + 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
startIdx = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemBDevice::updateGroupObject(GroupObject& go, uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
uint8_t* goData = go.valueRef();
|
||||||
|
|
||||||
|
if (length != go.valueSize())
|
||||||
|
{
|
||||||
|
go.commFlag(Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(goData, data, length);
|
||||||
|
|
||||||
|
if (go.commFlag() != WriteRequest)
|
||||||
|
{
|
||||||
|
go.commFlag(Updated);
|
||||||
|
#ifdef SMALL_GROUPOBJECT
|
||||||
|
GroupObject::processClassCallback(go);
|
||||||
|
#else
|
||||||
|
GroupObjectUpdatedHandler handler = go.callback();
|
||||||
|
|
||||||
|
if (handler)
|
||||||
|
handler(go);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
go.commFlag(Updated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BauSystemBDevice::configured()
|
||||||
|
{
|
||||||
|
// _configured is set to true initially, if the device was configured with ETS it will be set to true after restart
|
||||||
|
|
||||||
|
if (!_configured)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_configured = _groupObjTable.loadState() == LS_LOADED
|
||||||
|
&& _addrTable.loadState() == LS_LOADED
|
||||||
|
&& _assocTable.loadState() == LS_LOADED
|
||||||
|
&& _appProgram.loadState() == LS_LOADED;
|
||||||
|
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
_configured &= _secIfObj.loadState() == LS_LOADED;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return _configured;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemBDevice::doMasterReset(EraseCode eraseCode, uint8_t channel)
|
||||||
|
{
|
||||||
|
BauSystemB::doMasterReset(eraseCode, channel);
|
||||||
|
|
||||||
|
_addrTable.masterReset(eraseCode, channel);
|
||||||
|
_assocTable.masterReset(eraseCode, channel);
|
||||||
|
_groupObjTable.masterReset(eraseCode, channel);
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
_secIfObj.masterReset(eraseCode, channel);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemBDevice::groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength, bool status)
|
||||||
|
{
|
||||||
|
GroupObject& go = _groupObjTable.get(asap);
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
go.commFlag(Ok);
|
||||||
|
else
|
||||||
|
go.commFlag(Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemBDevice::groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, bool status)
|
||||||
|
{
|
||||||
|
GroupObject& go = _groupObjTable.get(asap);
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
go.commFlag(Ok);
|
||||||
|
else
|
||||||
|
go.commFlag(Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemBDevice::groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl)
|
||||||
|
{
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
DataSecurity requiredGoSecurity;
|
||||||
|
|
||||||
|
// Get security flags from Security Interface Object for this group object
|
||||||
|
requiredGoSecurity = _secIfObj.getGroupObjectSecurity(asap);
|
||||||
|
|
||||||
|
if (secCtrl.dataSecurity != requiredGoSecurity)
|
||||||
|
{
|
||||||
|
println("GroupValueRead: access denied due to wrong security flags");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GroupObject& go = _groupObjTable.get(asap);
|
||||||
|
|
||||||
|
if (!go.communicationEnable() || !go.readEnable())
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint8_t* data = go.valueRef();
|
||||||
|
_appLayer.groupValueReadResponse(AckRequested, asap, priority, hopType, secCtrl, data, go.sizeInTelegram());
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemBDevice::groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data,
|
||||||
|
uint8_t dataLength)
|
||||||
|
{
|
||||||
|
GroupObject& go = _groupObjTable.get(asap);
|
||||||
|
|
||||||
|
if (!go.communicationEnable() || !go.responseUpdateEnable())
|
||||||
|
return;
|
||||||
|
|
||||||
|
updateGroupObject(go, data, dataLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BauSystemBDevice::groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t* data, uint8_t dataLength)
|
||||||
|
{
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
DataSecurity requiredGoSecurity;
|
||||||
|
|
||||||
|
// Get security flags from Security Interface Object for this group object
|
||||||
|
requiredGoSecurity = _secIfObj.getGroupObjectSecurity(asap);
|
||||||
|
|
||||||
|
if (secCtrl.dataSecurity != requiredGoSecurity)
|
||||||
|
{
|
||||||
|
println("GroupValueWrite: access denied due to wrong security flags");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
GroupObject& go = _groupObjTable.get(asap);
|
||||||
|
|
||||||
|
if (!go.communicationEnable() || !go.writeEnable())
|
||||||
|
return;
|
||||||
|
|
||||||
|
updateGroupObject(go, data, dataLength);
|
||||||
|
}
|
||||||
57
components/knx/src/knx/bau_systemB_device.h
Normal file
57
components/knx/src/knx/bau_systemB_device.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "bau_systemB.h"
|
||||||
|
#include "device_object.h"
|
||||||
|
#include "address_table_object.h"
|
||||||
|
#include "association_table_object.h"
|
||||||
|
#include "group_object_table_object.h"
|
||||||
|
#include "security_interface_object.h"
|
||||||
|
#include "application_program_object.h"
|
||||||
|
#include "application_layer.h"
|
||||||
|
#include "secure_application_layer.h"
|
||||||
|
#include "transport_layer.h"
|
||||||
|
#include "network_layer_device.h"
|
||||||
|
#include "data_link_layer.h"
|
||||||
|
#include "platform.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
class BauSystemBDevice : public BauSystemB
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BauSystemBDevice(Platform& platform);
|
||||||
|
void loop() override;
|
||||||
|
bool configured() override;
|
||||||
|
GroupObjectTableObject& groupObjectTable();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ApplicationLayer& applicationLayer() override;
|
||||||
|
|
||||||
|
void groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl,
|
||||||
|
uint8_t* data, uint8_t dataLength, bool status) override;
|
||||||
|
void groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, bool status) override;
|
||||||
|
void groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl) override;
|
||||||
|
void groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl,
|
||||||
|
uint8_t* data, uint8_t dataLength) override;
|
||||||
|
void groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl,
|
||||||
|
uint8_t* data, uint8_t dataLength) override;
|
||||||
|
|
||||||
|
void sendNextGroupTelegram();
|
||||||
|
void updateGroupObject(GroupObject& go, uint8_t* data, uint8_t length);
|
||||||
|
|
||||||
|
void doMasterReset(EraseCode eraseCode, uint8_t channel) override;
|
||||||
|
|
||||||
|
AddressTableObject _addrTable;
|
||||||
|
AssociationTableObject _assocTable;
|
||||||
|
GroupObjectTableObject _groupObjTable;
|
||||||
|
#ifdef USE_DATASECURE
|
||||||
|
SecureApplicationLayer _appLayer;
|
||||||
|
SecurityInterfaceObject _secIfObj;
|
||||||
|
#else
|
||||||
|
ApplicationLayer _appLayer;
|
||||||
|
#endif
|
||||||
|
TransportLayer _transLayer;
|
||||||
|
NetworkLayerDevice _netLayer;
|
||||||
|
|
||||||
|
bool _configured = true;
|
||||||
|
};
|
||||||
364
components/knx/src/knx/bits.cpp
Normal file
364
components/knx/src/knx/bits.cpp
Normal file
@ -0,0 +1,364 @@
|
|||||||
|
#include "bits.h"
|
||||||
|
#include <cstring> // for memcpy()
|
||||||
|
|
||||||
|
const uint8_t* popByte(uint8_t& b, const uint8_t* data)
|
||||||
|
{
|
||||||
|
b = *data;
|
||||||
|
data += 1;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef KNX_NO_PRINT
|
||||||
|
void printHex(const char* suffix, const uint8_t* data, size_t length, bool newline)
|
||||||
|
{
|
||||||
|
print(suffix);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
if (data[i] < 0x10)
|
||||||
|
{
|
||||||
|
print("0");
|
||||||
|
}
|
||||||
|
|
||||||
|
print(data[i], HEX);
|
||||||
|
print(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newline)
|
||||||
|
{
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const uint8_t* popWord(uint16_t& w, const uint8_t* data)
|
||||||
|
{
|
||||||
|
w = getWord(data);
|
||||||
|
data += 2;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* popInt(uint32_t& i, const uint8_t* data)
|
||||||
|
{
|
||||||
|
i = getInt(data);
|
||||||
|
data += 4;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* popByteArray(uint8_t* dst, uint32_t size, const uint8_t* data)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < size; i++)
|
||||||
|
dst[i] = data[i];
|
||||||
|
|
||||||
|
data += size;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* pushByte(uint8_t b, uint8_t* data)
|
||||||
|
{
|
||||||
|
data[0] = b;
|
||||||
|
data += 1;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* pushWord(uint16_t w, uint8_t* data)
|
||||||
|
{
|
||||||
|
data[0] = ((w >> 8) & 0xff);
|
||||||
|
data[1] = (w & 0xff);
|
||||||
|
data += 2;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* pushInt(uint32_t i, uint8_t* data)
|
||||||
|
{
|
||||||
|
data[0] = ((i >> 24) & 0xff);
|
||||||
|
data[1] = ((i >> 16) & 0xff);
|
||||||
|
data[2] = ((i >> 8) & 0xff);
|
||||||
|
data[3] = (i & 0xff);
|
||||||
|
data += 4;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* pushByteArray(const uint8_t* src, uint32_t size, uint8_t* data)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < size; i++)
|
||||||
|
data[i] = src[i];
|
||||||
|
|
||||||
|
data += size;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t getWord(const uint8_t* data)
|
||||||
|
{
|
||||||
|
return (data[0] << 8) + data[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getInt(const uint8_t* data)
|
||||||
|
{
|
||||||
|
return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
void sixBytesFromUInt64(uint64_t num, uint8_t* toByteArray)
|
||||||
|
{
|
||||||
|
toByteArray[0] = ((num >> 40) & 0xff);
|
||||||
|
toByteArray[1] = ((num >> 32) & 0xff);
|
||||||
|
toByteArray[2] = ((num >> 24) & 0xff);
|
||||||
|
toByteArray[3] = ((num >> 16) & 0xff);
|
||||||
|
toByteArray[4] = ((num >> 8) & 0xff);
|
||||||
|
toByteArray[5] = (num & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t sixBytesToUInt64(uint8_t* data)
|
||||||
|
{
|
||||||
|
uint64_t l = 0;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
l = (l << 8) + data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The CRC of the Memory Control Block Table Property is a CRC16-CCITT with the following
|
||||||
|
// parameters:
|
||||||
|
// Width = 16 bit
|
||||||
|
// Truncated polynomial = 1021h
|
||||||
|
// Initial value = FFFFh
|
||||||
|
// Input date is NOT reflected.
|
||||||
|
// Output CRC is NOT reflected.
|
||||||
|
// No XOR is performed on the output CRC.
|
||||||
|
// EXAMPLE The correct CRC16-CCITT of the string ‘123456789’ is E5CCh.
|
||||||
|
|
||||||
|
uint16_t crc16Ccitt(uint8_t* input, uint16_t length)
|
||||||
|
{
|
||||||
|
uint32_t polynom = 0x1021;
|
||||||
|
|
||||||
|
uint32_t result = 0xffff;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < 8 * ((uint32_t)length + 2); i++)
|
||||||
|
{
|
||||||
|
result <<= 1;
|
||||||
|
uint32_t nextBit;
|
||||||
|
nextBit = ((i / 8) < length) ? ((input[i / 8] >> (7 - (i % 8))) & 0x1) : 0;
|
||||||
|
result |= nextBit;
|
||||||
|
|
||||||
|
if ((result & 0x10000) != 0)
|
||||||
|
result ^= polynom;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t crc16Dnp(uint8_t* input, uint16_t length)
|
||||||
|
{
|
||||||
|
// CRC-16-DNP
|
||||||
|
// generator polynomial = 2^16 + 2^13 + 2^12 + 2^11 + 2^10 + 2^8 + 2^6 + 2^5 + 2^2 + 2^0
|
||||||
|
uint32_t pn = 0x13d65; // 1 0011 1101 0110 0101
|
||||||
|
|
||||||
|
// for much data, using a lookup table would be a way faster CRC calculation
|
||||||
|
uint32_t crc = 0;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
uint8_t bite = input[i] & 0xff;
|
||||||
|
|
||||||
|
for (uint8_t b = 8; b -- > 0;)
|
||||||
|
{
|
||||||
|
bool bit = ((bite >> b) & 1) == 1;
|
||||||
|
bool one = (crc >> 15 & 1) == 1;
|
||||||
|
crc <<= 1;
|
||||||
|
|
||||||
|
if (one ^ bit)
|
||||||
|
crc ^= pn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (~crc) & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Produce Arduino print and println in ESP IDF for ESP32 family using printf().
|
||||||
|
#ifndef ARDUINO
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
// Helper function to print a number in binary format
|
||||||
|
static void print_binary(unsigned long long n)
|
||||||
|
{
|
||||||
|
if (n == 0)
|
||||||
|
{
|
||||||
|
printf("0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer for the maximum possible bits in an unsigned long long
|
||||||
|
char binary_string[65];
|
||||||
|
int i = 0;
|
||||||
|
while (n > 0)
|
||||||
|
{
|
||||||
|
binary_string[i++] = (n % 2) + '0';
|
||||||
|
n /= 2;
|
||||||
|
}
|
||||||
|
binary_string[i] = '\0';
|
||||||
|
|
||||||
|
// Reverse the string to get the correct binary representation
|
||||||
|
for (int j = 0; j < i / 2; ++j)
|
||||||
|
{
|
||||||
|
char temp = binary_string[j];
|
||||||
|
binary_string[j] = binary_string[i - j - 1];
|
||||||
|
binary_string[i - j - 1] = temp;
|
||||||
|
}
|
||||||
|
printf("%s", binary_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- print function implementations ---
|
||||||
|
|
||||||
|
void print(const char str[]) {
|
||||||
|
printf("%s", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(char c) {
|
||||||
|
printf("%c", c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(unsigned char b, int base) {
|
||||||
|
if (base == BIN) {
|
||||||
|
print_binary(b);
|
||||||
|
} else if (base == DEC) {
|
||||||
|
printf("%u", (unsigned int)b);
|
||||||
|
} else if (base == HEX) {
|
||||||
|
printf("%x", (unsigned int)b);
|
||||||
|
} else if (base == OCT) {
|
||||||
|
printf("%o", (unsigned int)b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(int n, int base) {
|
||||||
|
if (base == BIN) {
|
||||||
|
print_binary(n);
|
||||||
|
} else if (base == DEC) {
|
||||||
|
printf("%d", n);
|
||||||
|
} else if (base == HEX) {
|
||||||
|
printf("%x", n);
|
||||||
|
} else if (base == OCT) {
|
||||||
|
printf("%o", n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(unsigned int n, int base) {
|
||||||
|
if (base == BIN) {
|
||||||
|
print_binary(n);
|
||||||
|
} else if (base == DEC) {
|
||||||
|
printf("%u", n);
|
||||||
|
} else if (base == HEX) {
|
||||||
|
printf("%x", n);
|
||||||
|
} else if (base == OCT) {
|
||||||
|
printf("%o", n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(long n, int base) {
|
||||||
|
if (base == BIN) {
|
||||||
|
print_binary(n);
|
||||||
|
} else if (base == DEC) {
|
||||||
|
printf("%ld", n);
|
||||||
|
} else if (base == HEX) {
|
||||||
|
printf("%lx", n);
|
||||||
|
} else if (base == OCT) {
|
||||||
|
printf("%lo", n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(unsigned long n, int base) {
|
||||||
|
if (base == BIN) {
|
||||||
|
print_binary(n);
|
||||||
|
} else if (base == DEC) {
|
||||||
|
printf("%lu", n);
|
||||||
|
} else if (base == HEX) {
|
||||||
|
printf("%lx", n);
|
||||||
|
} else if (base == OCT) {
|
||||||
|
printf("%lo", n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(long long n, int base) {
|
||||||
|
if (base == BIN) {
|
||||||
|
print_binary(n);
|
||||||
|
} else if (base == DEC) {
|
||||||
|
printf("%lld", n);
|
||||||
|
} else if (base == HEX) {
|
||||||
|
printf("%llx", n);
|
||||||
|
} else if (base == OCT) {
|
||||||
|
printf("%llo", n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(unsigned long long n, int base) {
|
||||||
|
if (base == BIN) {
|
||||||
|
print_binary(n);
|
||||||
|
} else if (base == DEC) {
|
||||||
|
printf("%llu", n);
|
||||||
|
} else if (base == HEX) {
|
||||||
|
printf("%llx", n);
|
||||||
|
} else if (base == OCT) {
|
||||||
|
printf("%llo", n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(double n) {
|
||||||
|
printf("%f", n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(void) {
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(const char c[]) {
|
||||||
|
print(c);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(char c) {
|
||||||
|
print(c);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(unsigned char b, int base) {
|
||||||
|
print(b, base);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(int num, int base) {
|
||||||
|
print(num, base);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(unsigned int num, int base) {
|
||||||
|
print(num, base);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(long num, int base) {
|
||||||
|
print(num, base);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(unsigned long num, int base) {
|
||||||
|
print(num, base);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(long long num, int base) {
|
||||||
|
print(num, base);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(unsigned long long num, int base) {
|
||||||
|
print(num, base);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(double num) {
|
||||||
|
print(num);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
#endif // ESP_PLATFORM
|
||||||
|
#endif // !ARDUINO
|
||||||
161
components/knx/src/knx/bits.h
Normal file
161
components/knx/src/knx/bits.h
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#elif defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_STM32) || defined (DeviceFamily_CC13X0)
|
||||||
|
#define getbyte(x,n) (*(((uint8_t*)&(x))+n))
|
||||||
|
#define htons(x) ( (getbyte(x,0)<<8) | getbyte(x,1) )
|
||||||
|
#define htonl(x) ( (getbyte(x,0)<<24) | (getbyte(x,1)<<16) | (getbyte(x,2)<<8) | getbyte(x,3) )
|
||||||
|
#define ntohs(x) htons(x)
|
||||||
|
#define ntohl(x) htonl(x)
|
||||||
|
#elif defined(LIBRETINY)
|
||||||
|
#include <lwip/udp.h>
|
||||||
|
#define htons(x) lwip_htons(x)
|
||||||
|
#define htonl(x) lwip_htonl(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_STM32) || defined(LIBRETINY)
|
||||||
|
#include <Arduino.h>
|
||||||
|
#elif defined(ARDUINO_ARCH_ESP8266)
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <user_interface.h>
|
||||||
|
#elif defined(ARDUINO_ARCH_ESP32)
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <esp_wifi.h>
|
||||||
|
#elif defined(ESP_PLATFORM)
|
||||||
|
#include <lwip/inet.h>
|
||||||
|
#include <driver/gpio.h>
|
||||||
|
// // Define Arduino-like macros if needed for compatibility
|
||||||
|
|
||||||
|
#define lowByte(val) ((val)&255)
|
||||||
|
#define highByte(val) (((val) >> ((sizeof(val) - 1) << 3)) & 255)
|
||||||
|
#define bitRead(val, bitno) (((val) >> (bitno)) & 1)
|
||||||
|
#define DEC 10
|
||||||
|
#define HEX 16
|
||||||
|
#define OCT 8
|
||||||
|
#define BIN 2
|
||||||
|
#define LOW 0
|
||||||
|
#define HIGH 1
|
||||||
|
#define CHANGE GPIO_INTR_ANYEDGE
|
||||||
|
#define FALLING GPIO_INTR_NEGEDGE
|
||||||
|
#define RISING GPIO_INTR_POSEDGE
|
||||||
|
// Implement or map Arduino-like functions if needed
|
||||||
|
uint32_t millis();
|
||||||
|
typedef void (*IsrFuncPtr)(void); // Arduino-style
|
||||||
|
typedef void (*EspIsrFuncPtr)(void*); // ESP-IDF-style
|
||||||
|
void attachInterrupt(uint32_t pin, IsrFuncPtr callback, uint32_t mode);
|
||||||
|
#else // Non-Arduino platforms
|
||||||
|
#define lowByte(val) ((val)&255)
|
||||||
|
#define highByte(val) (((val) >> ((sizeof(val) - 1) << 3)) & 255)
|
||||||
|
#define bitRead(val, bitno) (((val) >> (bitno)) & 1)
|
||||||
|
|
||||||
|
// print functions are implemented in the platform files
|
||||||
|
#define DEC 10
|
||||||
|
#define HEX 16
|
||||||
|
|
||||||
|
#define INPUT (0x0)
|
||||||
|
#define OUTPUT (0x1)
|
||||||
|
#define INPUT_PULLUP (0x2)
|
||||||
|
#define INPUT_PULLDOWN (0x3)
|
||||||
|
|
||||||
|
#define LOW (0x0)
|
||||||
|
#define HIGH (0x1)
|
||||||
|
#define CHANGE 2
|
||||||
|
#define FALLING 3
|
||||||
|
#define RISING 4
|
||||||
|
|
||||||
|
void delay(uint32_t millis);
|
||||||
|
void delayMicroseconds (unsigned int howLong);
|
||||||
|
uint32_t millis();
|
||||||
|
void pinMode(uint32_t dwPin, uint32_t dwMode);
|
||||||
|
void digitalWrite(uint32_t dwPin, uint32_t dwVal);
|
||||||
|
uint32_t digitalRead(uint32_t dwPin);
|
||||||
|
typedef void (*voidFuncPtr)(void);
|
||||||
|
void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(a, b) ((a < b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(a, b) ((a > b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ABS
|
||||||
|
#define ABS(x) ((x > 0) ? (x) : (-x))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef KNX_NO_PRINT
|
||||||
|
void print(const char[]);
|
||||||
|
void print(char);
|
||||||
|
void print(unsigned char, int = DEC);
|
||||||
|
void print(int, int = DEC);
|
||||||
|
void print(unsigned int, int = DEC);
|
||||||
|
void print(long, int = DEC);
|
||||||
|
void print(unsigned long, int = DEC);
|
||||||
|
void print(long long, int = DEC);
|
||||||
|
void print(unsigned long long, int = DEC);
|
||||||
|
void print(double);
|
||||||
|
|
||||||
|
void println(const char[]);
|
||||||
|
void println(char);
|
||||||
|
void println(unsigned char, int = DEC);
|
||||||
|
void println(int, int = DEC);
|
||||||
|
void println(unsigned int, int = DEC);
|
||||||
|
void println(long, int = DEC);
|
||||||
|
void println(unsigned long, int = DEC);
|
||||||
|
void println(long long, int = DEC);
|
||||||
|
void println(unsigned long long, int = DEC);
|
||||||
|
void println(double);
|
||||||
|
void println(void);
|
||||||
|
|
||||||
|
void printHex(const char* suffix, const uint8_t* data, size_t length, bool newline = true);
|
||||||
|
#else
|
||||||
|
#define print(...) do {} while(0)
|
||||||
|
#define println(...) do {} while(0)
|
||||||
|
#define printHex(...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef KNX_ACTIVITYCALLBACK
|
||||||
|
#define KNX_ACTIVITYCALLBACK_DIR 0x00
|
||||||
|
#define KNX_ACTIVITYCALLBACK_DIR_RECV 0x00
|
||||||
|
#define KNX_ACTIVITYCALLBACK_DIR_SEND 0x01
|
||||||
|
#define KNX_ACTIVITYCALLBACK_IPUNICAST 0x02
|
||||||
|
#define KNX_ACTIVITYCALLBACK_NET 0x04
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const uint8_t* popByte(uint8_t& b, const uint8_t* data);
|
||||||
|
const uint8_t* popWord(uint16_t& w, const uint8_t* data);
|
||||||
|
const uint8_t* popInt(uint32_t& i, const uint8_t* data);
|
||||||
|
const uint8_t* popByteArray(uint8_t* dst, uint32_t size, const uint8_t* data);
|
||||||
|
uint8_t* pushByte(uint8_t b, uint8_t* data);
|
||||||
|
uint8_t* pushWord(uint16_t w, uint8_t* data);
|
||||||
|
uint8_t* pushInt(uint32_t i, uint8_t* data);
|
||||||
|
uint8_t* pushByteArray(const uint8_t* src, uint32_t size, uint8_t* data);
|
||||||
|
uint16_t getWord(const uint8_t* data);
|
||||||
|
uint32_t getInt(const uint8_t* data);
|
||||||
|
|
||||||
|
void sixBytesFromUInt64(uint64_t num, uint8_t* toByteArray);
|
||||||
|
uint64_t sixBytesToUInt64(uint8_t* data);
|
||||||
|
|
||||||
|
uint16_t crc16Ccitt(uint8_t* input, uint16_t length);
|
||||||
|
uint16_t crc16Dnp(uint8_t* input, uint16_t length);
|
||||||
|
|
||||||
|
enum ParameterFloatEncodings
|
||||||
|
{
|
||||||
|
Float_Enc_DPT9 = 0, // 2 Byte. See Chapter 3.7.2 section 3.10 (Datapoint Types 2-Octet Float Value)
|
||||||
|
Float_Enc_IEEE754Single = 1, // 4 Byte. C++ float
|
||||||
|
Float_Enc_IEEE754Double = 2, // 8 Byte. C++ double
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_SAMD)
|
||||||
|
// temporary undef until framework-arduino-samd > 1.8.9 is released. See https://github.com/arduino/ArduinoCore-samd/pull/399 for a PR should will probably address this
|
||||||
|
#undef max
|
||||||
|
#undef min
|
||||||
|
// end of temporary undef
|
||||||
|
#endif
|
||||||
39
components/knx/src/knx/callback_property.h
Normal file
39
components/knx/src/knx/callback_property.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "property.h"
|
||||||
|
|
||||||
|
class InterfaceObject;
|
||||||
|
|
||||||
|
template <class T> class CallbackProperty : public Property
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CallbackProperty(T* io, PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements,
|
||||||
|
uint8_t access, uint8_t (*readCallback)(T*, uint16_t, uint8_t, uint8_t*),
|
||||||
|
uint8_t (*writeCallback)(T*, uint16_t, uint8_t, const uint8_t*))
|
||||||
|
: Property(id, writeEnable, type, maxElements, access),
|
||||||
|
_interfaceObject(io), _readCallback(readCallback), _writeCallback(writeCallback)
|
||||||
|
{}
|
||||||
|
CallbackProperty(T* io, PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements,
|
||||||
|
uint8_t access, uint8_t (*readCallback)(T*, uint16_t, uint8_t, uint8_t*))
|
||||||
|
: Property(id, writeEnable, type, maxElements, access), _interfaceObject(io), _readCallback(readCallback)
|
||||||
|
{}
|
||||||
|
|
||||||
|
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)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return _readCallback(_interfaceObject, start, count, data);
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return _writeCallback(_interfaceObject, start, count, data);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
T* _interfaceObject = nullptr;
|
||||||
|
uint8_t (*_readCallback)(T*, uint16_t, uint8_t, uint8_t*) = nullptr;
|
||||||
|
uint8_t (*_writeCallback)(T*, uint16_t, uint8_t, const uint8_t*) = nullptr;
|
||||||
|
};
|
||||||
403
components/knx/src/knx/cemi_frame.cpp
Normal file
403
components/knx/src/knx/cemi_frame.cpp
Normal file
@ -0,0 +1,403 @@
|
|||||||
|
#include "cemi_frame.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
cEMI Frame Format
|
||||||
|
|
||||||
|
+--------+--------+--------+--------+---------+---------+--------+---------+
|
||||||
|
| _data |
|
||||||
|
+--------+--------+--------+--------+---------+---------+--------+---------+
|
||||||
|
| LPDU |
|
||||||
|
+--------+--------+--------+--------+---------+---------+--------+---------+
|
||||||
|
| NPDU |
|
||||||
|
+---------+--------+--------+--------+--------+---------+---------+--------+---------+
|
||||||
|
| Header | Msg |Add.Info| Ctrl 1 | Ctrl 2 | Source | Dest. | Data | TPDU |
|
||||||
|
| | Code | Length | | | Address | Address | Length | APDU |
|
||||||
|
+---------+--------+--------+--------+--------+---------+---------+--------+---------+
|
||||||
|
6 bytes 1 byte 1 byte 1 byte 1 byte 2 bytes 2 bytes 1 byte n bytes
|
||||||
|
|
||||||
|
Header = See below the structure of a cEMI header
|
||||||
|
Message Code = See below. On Appendix A is the list of all existing EMI and cEMI codes
|
||||||
|
Add.Info Length = 0x00 - no additional info
|
||||||
|
Control Field 1 =
|
||||||
|
Control Field 2 =
|
||||||
|
Source Address = 0x0000 - filled in by router/gateway with its source address which is
|
||||||
|
part of the KNX subnet
|
||||||
|
Dest. Address = KNX group or individual address (2 byte)
|
||||||
|
Data Length = Number of bytes of data in the APDU excluding the TPCI/APCI bits
|
||||||
|
APDU = Application Protocol Data Unit - the actual payload including transport
|
||||||
|
protocol control information (TPCI), application protocol control
|
||||||
|
information (APCI) and data passed as an argument from higher layers of
|
||||||
|
the KNX communication stack
|
||||||
|
|
||||||
|
Control Field 1
|
||||||
|
|
||||||
|
Bit |
|
||||||
|
------+---------------------------------------------------------------
|
||||||
|
7 | Frame Type - 0x0 for extended frame
|
||||||
|
| 0x1 for standard frame
|
||||||
|
------+---------------------------------------------------------------
|
||||||
|
6 | Reserved
|
||||||
|
|
|
||||||
|
------+---------------------------------------------------------------
|
||||||
|
5 | Repeat Flag - 0x0 repeat frame on medium in case of an error
|
||||||
|
| 0x1 do not repeat
|
||||||
|
------+---------------------------------------------------------------
|
||||||
|
4 | System Broadcast - 0x0 system broadcast
|
||||||
|
| 0x1 broadcast
|
||||||
|
------+---------------------------------------------------------------
|
||||||
|
3 | Priority - 0x0 system
|
||||||
|
| 0x1 normal
|
||||||
|
------+ 0x2 urgent
|
||||||
|
2 | 0x3 low
|
||||||
|
|
|
||||||
|
------+---------------------------------------------------------------
|
||||||
|
1 | Acknowledge Request - 0x0 no ACK requested
|
||||||
|
| (L_Data.req) 0x1 ACK requested
|
||||||
|
------+---------------------------------------------------------------
|
||||||
|
0 | Confirm - 0x0 no error
|
||||||
|
| (L_Data.con) - 0x1 error
|
||||||
|
------+---------------------------------------------------------------
|
||||||
|
|
||||||
|
Control Field 2
|
||||||
|
|
||||||
|
Bit |
|
||||||
|
------+---------------------------------------------------------------
|
||||||
|
7 | Destination Address Type - 0x0 individual address
|
||||||
|
| - 0x1 group address
|
||||||
|
------+---------------------------------------------------------------
|
||||||
|
6-4 | Hop Count (0-7)
|
||||||
|
------+---------------------------------------------------------------
|
||||||
|
3-0 | Extended Frame Format - 0x0 standard frame
|
||||||
|
------+---------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
CemiFrame::CemiFrame(uint8_t* data, uint16_t length)
|
||||||
|
: _npdu(data + data[1] + NPDU_LPDU_DIFF, *this),
|
||||||
|
_tpdu(data + data[1] + TPDU_LPDU_DIFF, *this),
|
||||||
|
_apdu(data + data[1] + APDU_LPDU_DIFF, *this)
|
||||||
|
{
|
||||||
|
_data = data;
|
||||||
|
_ctrl1 = data + data[1] + CEMI_HEADER_SIZE;
|
||||||
|
_length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
CemiFrame::CemiFrame(uint8_t apduLength)
|
||||||
|
: _data(buffer),
|
||||||
|
_npdu(_data + NPDU_LPDU_DIFF, *this),
|
||||||
|
_tpdu(_data + TPDU_LPDU_DIFF, *this),
|
||||||
|
_apdu(_data + APDU_LPDU_DIFF, *this)
|
||||||
|
{
|
||||||
|
_ctrl1 = _data + CEMI_HEADER_SIZE;
|
||||||
|
|
||||||
|
memset(_data, 0, apduLength + APDU_LPDU_DIFF);
|
||||||
|
_ctrl1[0] |= Broadcast;
|
||||||
|
_npdu.octetCount(apduLength);
|
||||||
|
_length = _npdu.length() + NPDU_LPDU_DIFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
CemiFrame::CemiFrame(const CemiFrame& other)
|
||||||
|
: _data(buffer),
|
||||||
|
_npdu(_data + NPDU_LPDU_DIFF, *this),
|
||||||
|
_tpdu(_data + TPDU_LPDU_DIFF, *this),
|
||||||
|
_apdu(_data + APDU_LPDU_DIFF, *this)
|
||||||
|
{
|
||||||
|
_ctrl1 = _data + CEMI_HEADER_SIZE;
|
||||||
|
_length = other._length;
|
||||||
|
|
||||||
|
memcpy(_data, other._data, other.totalLenght());
|
||||||
|
}
|
||||||
|
|
||||||
|
CemiFrame& CemiFrame::operator=(CemiFrame other)
|
||||||
|
{
|
||||||
|
_length = other._length;
|
||||||
|
_data = buffer;
|
||||||
|
_ctrl1 = _data + CEMI_HEADER_SIZE;
|
||||||
|
memcpy(_data, other._data, other.totalLenght());
|
||||||
|
_npdu._data = _data + NPDU_LPDU_DIFF;
|
||||||
|
_tpdu._data = _data + TPDU_LPDU_DIFF;
|
||||||
|
_apdu._data = _data + APDU_LPDU_DIFF;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MessageCode CemiFrame::messageCode() const
|
||||||
|
{
|
||||||
|
return (MessageCode)_data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiFrame::messageCode(MessageCode msgCode)
|
||||||
|
{
|
||||||
|
_data[0] = msgCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t CemiFrame::totalLenght() const
|
||||||
|
{
|
||||||
|
return _length;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t CemiFrame::telegramLengthtTP() const
|
||||||
|
{
|
||||||
|
if (frameType() == StandardFrame)
|
||||||
|
return totalLenght() - 2; /*-AddInfo -MsgCode - only one CTRL + CRC, */
|
||||||
|
else
|
||||||
|
return totalLenght() - 1; /*-AddInfo -MsgCode + CRC, */
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiFrame::fillTelegramTP(uint8_t* data)
|
||||||
|
{
|
||||||
|
uint16_t len = telegramLengthtTP();
|
||||||
|
|
||||||
|
if (frameType() == StandardFrame)
|
||||||
|
{
|
||||||
|
uint8_t octet5 = (_ctrl1[1] & 0xF0) | (_ctrl1[6] & 0x0F);
|
||||||
|
data[0] = _ctrl1[0]; //CTRL
|
||||||
|
memcpy(data + 1, _ctrl1 + 2, 4); // SA, DA
|
||||||
|
data[5] = octet5; // LEN; Hopcount, ..
|
||||||
|
memcpy(data + 6, _ctrl1 + 7, len - 7); // APDU
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(data, _ctrl1, len - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
data[len - 1] = calcCrcTP(data, len - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_RF
|
||||||
|
|
||||||
|
uint16_t CemiFrame::telegramLengthtRF() const
|
||||||
|
{
|
||||||
|
return totalLenght() - 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiFrame::fillTelegramRF(uint8_t* data)
|
||||||
|
{
|
||||||
|
uint16_t len = telegramLengthtRF();
|
||||||
|
|
||||||
|
// We prepare the actual KNX telegram for RF here only.
|
||||||
|
// The packaging into blocks with CRC16 (Format based on FT3 Data Link Layer (IEC 870-5))
|
||||||
|
// is done in the RF Data Link Layer code.
|
||||||
|
// RF always uses the Extended Frame Format. However, the length field is missing (right before the APDU)
|
||||||
|
// as there is already a length field at the beginning of the raw RF frame which is also used by the
|
||||||
|
// physical layer to control the HW packet engine of the transceiver.
|
||||||
|
|
||||||
|
data[0] = _ctrl1[1] & 0x0F; // KNX CTRL field for RF (bits 3..0 EFF only), bits 7..4 are set to 0 for asynchronous RF frames
|
||||||
|
memcpy(data + 1, _ctrl1 + 2, 4); // SA, DA
|
||||||
|
data[5] = (_ctrl1[1] & 0xF0) | ((_rfLfn & 0x7) << 1) | ((_ctrl1[0] & 0x10) >> 4); // L/NPCI field: AT, Hopcount, LFN, AET
|
||||||
|
memcpy(data + 6, _ctrl1 + 7, len - 6); // APDU
|
||||||
|
|
||||||
|
//printHex("cEMI_fill: ", &data[0], len);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
uint8_t* CemiFrame::data()
|
||||||
|
{
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t CemiFrame::dataLength()
|
||||||
|
{
|
||||||
|
return _length;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CemiFrame::calcCrcTP(uint8_t* buffer, uint16_t len)
|
||||||
|
{
|
||||||
|
uint8_t crc = 0xFF;
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < len; i++)
|
||||||
|
crc ^= buffer[i];
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameFormat CemiFrame::frameType() const
|
||||||
|
{
|
||||||
|
return (FrameFormat)(_ctrl1[0] & StandardFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiFrame::frameType(FrameFormat type)
|
||||||
|
{
|
||||||
|
_ctrl1[0] &= ~StandardFrame;
|
||||||
|
_ctrl1[0] |= type;
|
||||||
|
}
|
||||||
|
|
||||||
|
Repetition CemiFrame::repetition() const
|
||||||
|
{
|
||||||
|
return (Repetition)(_ctrl1[0] & RepetitionAllowed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiFrame::repetition(Repetition rep)
|
||||||
|
{
|
||||||
|
_ctrl1[0] &= ~RepetitionAllowed;
|
||||||
|
_ctrl1[0] |= rep;
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemBroadcast CemiFrame::systemBroadcast() const
|
||||||
|
{
|
||||||
|
return (SystemBroadcast)(_ctrl1[0] & Broadcast);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiFrame::systemBroadcast(SystemBroadcast value)
|
||||||
|
{
|
||||||
|
_ctrl1[0] &= ~Broadcast;
|
||||||
|
_ctrl1[0] |= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Priority CemiFrame::priority() const
|
||||||
|
{
|
||||||
|
return (Priority)(_ctrl1[0] & LowPriority);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiFrame::priority(Priority value)
|
||||||
|
{
|
||||||
|
_ctrl1[0] &= ~LowPriority;
|
||||||
|
_ctrl1[0] |= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
AckType CemiFrame::ack() const
|
||||||
|
{
|
||||||
|
return (AckType)(_ctrl1[0] & AckRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiFrame::ack(AckType value)
|
||||||
|
{
|
||||||
|
_ctrl1[0] &= ~AckRequested;
|
||||||
|
_ctrl1[0] |= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Confirm CemiFrame::confirm() const
|
||||||
|
{
|
||||||
|
return (Confirm)(_ctrl1[0] & ConfirmError);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiFrame::confirm(Confirm value)
|
||||||
|
{
|
||||||
|
_ctrl1[0] &= ~ConfirmError;
|
||||||
|
_ctrl1[0] |= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressType CemiFrame::addressType() const
|
||||||
|
{
|
||||||
|
return (AddressType)(_ctrl1[1] & GroupAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiFrame::addressType(AddressType value)
|
||||||
|
{
|
||||||
|
_ctrl1[1] &= ~GroupAddress;
|
||||||
|
_ctrl1[1] |= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CemiFrame::hopCount() const
|
||||||
|
{
|
||||||
|
return ((_ctrl1[1] >> 4) & 0x7);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiFrame::hopCount(uint8_t value)
|
||||||
|
{
|
||||||
|
_ctrl1[1] &= ~(0x7 << 4);
|
||||||
|
_ctrl1[1] |= ((value & 0x7) << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t CemiFrame::sourceAddress() const
|
||||||
|
{
|
||||||
|
uint16_t addr;
|
||||||
|
popWord(addr, _ctrl1 + 2);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiFrame::sourceAddress(uint16_t value)
|
||||||
|
{
|
||||||
|
pushWord(value, _ctrl1 + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t CemiFrame::destinationAddress() const
|
||||||
|
{
|
||||||
|
uint16_t addr;
|
||||||
|
popWord(addr, _ctrl1 + 4);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiFrame::destinationAddress(uint16_t value)
|
||||||
|
{
|
||||||
|
pushWord(value, _ctrl1 + 4);
|
||||||
|
}
|
||||||
|
#ifdef USE_RF
|
||||||
|
uint8_t* CemiFrame::rfSerialOrDoA() const
|
||||||
|
{
|
||||||
|
return _rfSerialOrDoA;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiFrame::rfSerialOrDoA(const uint8_t* rfSerialOrDoA)
|
||||||
|
{
|
||||||
|
_rfSerialOrDoA = (uint8_t*)rfSerialOrDoA;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CemiFrame::rfInfo() const
|
||||||
|
{
|
||||||
|
return _rfInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiFrame::rfInfo(uint8_t rfInfo)
|
||||||
|
{
|
||||||
|
_rfInfo = rfInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CemiFrame::rfLfn() const
|
||||||
|
{
|
||||||
|
return _rfLfn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiFrame::rfLfn(uint8_t rfLfn)
|
||||||
|
{
|
||||||
|
_rfLfn = rfLfn;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
NPDU& CemiFrame::npdu()
|
||||||
|
{
|
||||||
|
return _npdu;
|
||||||
|
}
|
||||||
|
|
||||||
|
TPDU& CemiFrame::tpdu()
|
||||||
|
{
|
||||||
|
return _tpdu;
|
||||||
|
}
|
||||||
|
|
||||||
|
APDU& CemiFrame::apdu()
|
||||||
|
{
|
||||||
|
return _apdu;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CemiFrame::valid() const
|
||||||
|
{
|
||||||
|
uint8_t addInfoLen = _data[1];
|
||||||
|
uint8_t apduLen = _data[_data[1] + NPDU_LPDU_DIFF];
|
||||||
|
|
||||||
|
if (_length != 0 && _length != (addInfoLen + apduLen + NPDU_LPDU_DIFF + 2))
|
||||||
|
{
|
||||||
|
print("length issue, length: ");
|
||||||
|
print(_length);
|
||||||
|
print(" addInfoLen: ");
|
||||||
|
print(addInfoLen);
|
||||||
|
print(" apduLen: ");
|
||||||
|
print(apduLen);
|
||||||
|
print(" expected length: ");
|
||||||
|
println(addInfoLen + apduLen + NPDU_LPDU_DIFF + 2);
|
||||||
|
printHex("Frame: ", _data, _length, true);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((_ctrl1[0] & 0x40) > 0 // Bit 6 has do be 0
|
||||||
|
|| (_ctrl1[1] & 0xF) > 0 // only standard or extended frames
|
||||||
|
|| _npdu.octetCount() == 0xFF // not allowed
|
||||||
|
|| (_npdu.octetCount() > 15 && frameType() == StandardFrame)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
print("Other issue");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
94
components/knx/src/knx/cemi_frame.h
Normal file
94
components/knx/src/knx/cemi_frame.h
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "knx_types.h"
|
||||||
|
#include "stdint.h"
|
||||||
|
#include "npdu.h"
|
||||||
|
#include "tpdu.h"
|
||||||
|
#include "apdu.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#define NPDU_LPDU_DIFF 8
|
||||||
|
#define TPDU_NPDU_DIFF 1
|
||||||
|
#define APDU_TPDU_DIFF 0
|
||||||
|
#define TPDU_LPDU_DIFF (TPDU_NPDU_DIFF + NPDU_LPDU_DIFF)
|
||||||
|
#define APDU_LPDU_DIFF (APDU_TPDU_DIFF + TPDU_NPDU_DIFF + NPDU_LPDU_DIFF)
|
||||||
|
|
||||||
|
// Mesg Code and additional info length
|
||||||
|
#define CEMI_HEADER_SIZE 2
|
||||||
|
|
||||||
|
class CemiFrame
|
||||||
|
{
|
||||||
|
friend class DataLinkLayer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CemiFrame(uint8_t* data, uint16_t length);
|
||||||
|
CemiFrame(uint8_t apduLength);
|
||||||
|
CemiFrame(const CemiFrame& other);
|
||||||
|
CemiFrame& operator=(CemiFrame other);
|
||||||
|
|
||||||
|
MessageCode messageCode() const;
|
||||||
|
void messageCode(MessageCode value);
|
||||||
|
uint16_t totalLenght() const;
|
||||||
|
uint16_t telegramLengthtTP() const;
|
||||||
|
void fillTelegramTP(uint8_t* data);
|
||||||
|
uint16_t telegramLengthtRF() const;
|
||||||
|
void fillTelegramRF(uint8_t* data);
|
||||||
|
uint8_t* data();
|
||||||
|
uint16_t dataLength();
|
||||||
|
|
||||||
|
FrameFormat frameType() const;
|
||||||
|
void frameType(FrameFormat value);
|
||||||
|
Repetition repetition() const;
|
||||||
|
void repetition(Repetition value);
|
||||||
|
SystemBroadcast systemBroadcast() const;
|
||||||
|
void systemBroadcast(SystemBroadcast value);
|
||||||
|
Priority priority() const;
|
||||||
|
void priority(Priority value);
|
||||||
|
AckType ack() const;
|
||||||
|
void ack(AckType value);
|
||||||
|
Confirm confirm() const;
|
||||||
|
void confirm(Confirm value);
|
||||||
|
AddressType addressType() const;
|
||||||
|
void addressType(AddressType value);
|
||||||
|
uint8_t hopCount() const;
|
||||||
|
void hopCount(uint8_t value);
|
||||||
|
uint16_t sourceAddress() const;
|
||||||
|
void sourceAddress(uint16_t value);
|
||||||
|
uint16_t destinationAddress() const;
|
||||||
|
void destinationAddress(uint16_t value);
|
||||||
|
|
||||||
|
#ifdef USE_RF
|
||||||
|
// only for RF medium
|
||||||
|
uint8_t* rfSerialOrDoA() const;
|
||||||
|
void rfSerialOrDoA(const uint8_t* rfSerialOrDoA);
|
||||||
|
uint8_t rfInfo() const;
|
||||||
|
void rfInfo(uint8_t rfInfo);
|
||||||
|
uint8_t rfLfn() const;
|
||||||
|
void rfLfn(uint8_t rfInfo);
|
||||||
|
#endif
|
||||||
|
NPDU& npdu();
|
||||||
|
TPDU& tpdu();
|
||||||
|
APDU& apdu();
|
||||||
|
|
||||||
|
uint8_t calcCrcTP(uint8_t* buffer, uint16_t len);
|
||||||
|
bool valid() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t buffer[0xff + NPDU_LPDU_DIFF] = {0}; //only valid of add info is zero
|
||||||
|
uint8_t* _data = 0;
|
||||||
|
uint8_t* _ctrl1 = 0;
|
||||||
|
NPDU _npdu;
|
||||||
|
TPDU _tpdu;
|
||||||
|
APDU _apdu;
|
||||||
|
uint16_t _length = 0; // only set if created from byte array
|
||||||
|
|
||||||
|
#ifdef USE_RF
|
||||||
|
// FIXME: integrate this propery in _data
|
||||||
|
// only for RF medium
|
||||||
|
uint8_t* _rfSerialOrDoA = 0;
|
||||||
|
uint8_t _rfInfo = 0;
|
||||||
|
uint8_t _rfLfn = 0xFF; // RF Data Link layer frame number
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t _sourceInterfaceIndex;
|
||||||
|
};
|
||||||
443
components/knx/src/knx/cemi_server.cpp
Normal file
443
components/knx/src/knx/cemi_server.cpp
Normal file
@ -0,0 +1,443 @@
|
|||||||
|
#include "config.h"
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
|
||||||
|
#include "cemi_server.h"
|
||||||
|
#include "cemi_frame.h"
|
||||||
|
#include "bau_systemB.h"
|
||||||
|
#include "usb_tunnel_interface.h"
|
||||||
|
#include "data_link_layer.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
CemiServer::CemiServer(BauSystemB& bau)
|
||||||
|
: _bau(bau)
|
||||||
|
#ifdef USE_USB
|
||||||
|
,
|
||||||
|
_usbTunnelInterface(*this,
|
||||||
|
_bau.deviceObject().maskVersion(),
|
||||||
|
_bau.deviceObject().manufacturerId())
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
// The cEMI server will hand out the device address + 1 to the cEMI client (e.g. ETS),
|
||||||
|
// so that the device and the cEMI client/server connection(tunnel) can operate simultaneously.
|
||||||
|
_clientAddress = _bau.deviceObject().individualAddress() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiServer::dataLinkLayer(DataLinkLayer& layer)
|
||||||
|
{
|
||||||
|
_dataLinkLayer = &layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
void CemiServer::dataLinkLayerPrimary(DataLinkLayer& layer)
|
||||||
|
{
|
||||||
|
_dataLinkLayerPrimary = &layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
uint16_t CemiServer::clientAddress() const
|
||||||
|
{
|
||||||
|
return _clientAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiServer::clientAddress(uint16_t value)
|
||||||
|
{
|
||||||
|
_clientAddress = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiServer::dataConfirmationToTunnel(CemiFrame& frame)
|
||||||
|
{
|
||||||
|
MessageCode backupMsgCode = frame.messageCode();
|
||||||
|
|
||||||
|
frame.messageCode(L_data_con);
|
||||||
|
|
||||||
|
#ifdef KNX_LOG_TUNNELING
|
||||||
|
print("L_data_con: src: ");
|
||||||
|
print(frame.sourceAddress(), HEX);
|
||||||
|
print(" dst: ");
|
||||||
|
print(frame.destinationAddress(), HEX);
|
||||||
|
|
||||||
|
printHex(" frame: ", frame.data(), frame.dataLength());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_USB
|
||||||
|
_usbTunnelInterface.sendCemiFrame(frame);
|
||||||
|
#elif defined(KNX_TUNNELING)
|
||||||
|
_dataLinkLayerPrimary->dataConfirmationToTunnel(frame);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
frame.messageCode(backupMsgCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiServer::dataIndicationToTunnel(CemiFrame& frame)
|
||||||
|
{
|
||||||
|
#ifdef USE_RF
|
||||||
|
bool isRf = _dataLinkLayer->mediumType() == DptMedium::KNX_RF;
|
||||||
|
uint8_t data[frame.dataLength() + (isRf ? 10 : 0)];
|
||||||
|
#else
|
||||||
|
uint8_t data[frame.dataLength()];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_RF
|
||||||
|
|
||||||
|
if (isRf)
|
||||||
|
{
|
||||||
|
data[0] = L_data_ind; // Message Code
|
||||||
|
data[1] = 0x0A; // Total additional info length
|
||||||
|
data[2] = 0x02; // RF add. info: type
|
||||||
|
data[3] = 0x08; // RF add. info: length
|
||||||
|
data[4] = frame.rfInfo(); // RF add. info: info field (batt ok, bidir)
|
||||||
|
pushByteArray(frame.rfSerialOrDoA(), 6, &data[5]); // RF add. info:Serial or Domain Address
|
||||||
|
data[11] = frame.rfLfn(); // RF add. info: link layer frame number
|
||||||
|
memcpy(&data[12], &((frame.data())[2]), frame.dataLength() - 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
memcpy(&data[0], frame.data(), frame.dataLength());
|
||||||
|
#ifdef USE_RF
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CemiFrame tmpFrame(data, sizeof(data));
|
||||||
|
|
||||||
|
#ifdef KNX_LOG_TUNNELING
|
||||||
|
print("ToTunnel ");
|
||||||
|
print("L_data_ind: src: ");
|
||||||
|
print(tmpFrame.sourceAddress(), HEX);
|
||||||
|
print(" dst: ");
|
||||||
|
print(tmpFrame.destinationAddress(), HEX);
|
||||||
|
|
||||||
|
printHex(" frame: ", tmpFrame.data(), tmpFrame.dataLength());
|
||||||
|
#endif
|
||||||
|
tmpFrame.apdu().type();
|
||||||
|
|
||||||
|
#ifdef USE_USB
|
||||||
|
_usbTunnelInterface.sendCemiFrame(tmpFrame);
|
||||||
|
#elif defined(KNX_TUNNELING)
|
||||||
|
_dataLinkLayerPrimary->dataIndicationToTunnel(frame);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiServer::frameReceived(CemiFrame& frame)
|
||||||
|
{
|
||||||
|
switch (frame.messageCode())
|
||||||
|
{
|
||||||
|
case L_data_req:
|
||||||
|
{
|
||||||
|
handleLData(frame);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case M_PropRead_req:
|
||||||
|
{
|
||||||
|
handleMPropRead(frame);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case M_PropWrite_req:
|
||||||
|
{
|
||||||
|
handleMPropWrite(frame);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case M_FuncPropCommand_req:
|
||||||
|
{
|
||||||
|
println("M_FuncPropCommand_req not implemented");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case M_FuncPropStateRead_req:
|
||||||
|
{
|
||||||
|
println("M_FuncPropStateRead_req not implemented");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case M_Reset_req:
|
||||||
|
{
|
||||||
|
handleMReset(frame);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we should never receive these: server -> client
|
||||||
|
case L_data_con:
|
||||||
|
case L_data_ind:
|
||||||
|
case M_PropInfo_ind:
|
||||||
|
case M_PropRead_con:
|
||||||
|
case M_PropWrite_con:
|
||||||
|
case M_FuncPropCommand_con:
|
||||||
|
|
||||||
|
//case M_FuncPropStateRead_con: // same value as M_FuncPropCommand_con
|
||||||
|
case M_Reset_ind:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiServer::handleLData(CemiFrame& frame)
|
||||||
|
{
|
||||||
|
// Fill in the cEMI client address if the client sets
|
||||||
|
// source address to 0.
|
||||||
|
#ifndef KNX_TUNNELING
|
||||||
|
//We already set the correct IA
|
||||||
|
if (frame.sourceAddress() == 0x0000)
|
||||||
|
{
|
||||||
|
frame.sourceAddress(_clientAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_RF
|
||||||
|
|
||||||
|
if (_dataLinkLayer->mediumType() == DptMedium::KNX_RF)
|
||||||
|
{
|
||||||
|
// Check if we have additional info for RF
|
||||||
|
if (((frame.data())[1] == 0x0A) && // Additional info total length: we only handle one additional info of type RF
|
||||||
|
((frame.data())[2] == 0x02) && // Additional info type: RF
|
||||||
|
((frame.data())[3] == 0x08) ) // Additional info length of type RF: 8 bytes (fixed)
|
||||||
|
{
|
||||||
|
frame.rfInfo((frame.data())[4]);
|
||||||
|
|
||||||
|
// Use the values provided in the RF additonal info
|
||||||
|
if ( ((frame.data())[5] != 0x00) || ((frame.data())[6] != 0x00) || ((frame.data())[7] != 0x00) ||
|
||||||
|
((frame.data())[8] != 0x00) || ((frame.data())[9] != 0x00) || ((frame.data())[10] != 0x00) )
|
||||||
|
{
|
||||||
|
frame.rfSerialOrDoA(&((frame.data())[5]));
|
||||||
|
} // else leave the nullptr as it is
|
||||||
|
|
||||||
|
frame.rfLfn((frame.data())[11]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the cEMI client does not provide a link layer frame number (LFN),
|
||||||
|
// we use our own counter.
|
||||||
|
// Note: There is another link layer frame number counter inside the RF data link layer class!
|
||||||
|
// That counter is solely for the local application!
|
||||||
|
// If we set a LFN here, the data link layer counter is NOT used!
|
||||||
|
if (frame.rfLfn() == 0xFF)
|
||||||
|
{
|
||||||
|
// Set Data Link Layer Frame Number
|
||||||
|
frame.rfLfn(_frameNumber);
|
||||||
|
// Link Layer frame number counts 0..7
|
||||||
|
_frameNumber = (_frameNumber + 1) & 0x7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef KNX_LOG_TUNNELING
|
||||||
|
print("L_data_req: src: ");
|
||||||
|
print(frame.sourceAddress(), HEX);
|
||||||
|
print(" dst: ");
|
||||||
|
print(frame.destinationAddress(), HEX);
|
||||||
|
printHex(" frame: ", frame.data(), frame.dataLength());
|
||||||
|
#endif
|
||||||
|
_dataLinkLayer->dataRequestFromTunnel(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiServer::handleMPropRead(CemiFrame& frame)
|
||||||
|
{
|
||||||
|
#ifdef KNX_LOG_TUNNELING
|
||||||
|
print("M_PropRead_req: ");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint16_t objectType;
|
||||||
|
popWord(objectType, &frame.data()[1]);
|
||||||
|
uint8_t objectInstance = frame.data()[3];
|
||||||
|
uint8_t propertyId = frame.data()[4];
|
||||||
|
uint8_t numberOfElements = frame.data()[5] >> 4;
|
||||||
|
uint16_t startIndex = frame.data()[6] | ((frame.data()[5] & 0x0F) << 8);
|
||||||
|
uint8_t* data = nullptr;
|
||||||
|
uint32_t dataSize = 0;
|
||||||
|
|
||||||
|
#ifdef KNX_LOG_TUNNELING
|
||||||
|
print("ObjType: ");
|
||||||
|
print(objectType, DEC);
|
||||||
|
print(" ObjInst: ");
|
||||||
|
print(objectInstance, DEC);
|
||||||
|
print(" PropId: ");
|
||||||
|
print(propertyId, DEC);
|
||||||
|
print(" NoE: ");
|
||||||
|
print(numberOfElements, DEC);
|
||||||
|
print(" startIdx: ");
|
||||||
|
print(startIndex, DEC);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// propertyValueRead() allocates memory for the data! Needs to be deleted again!
|
||||||
|
_bau.propertyValueRead((ObjectType)objectType, objectInstance, propertyId, numberOfElements, startIndex, &data, dataSize);
|
||||||
|
|
||||||
|
// Patch result for device address in device object
|
||||||
|
// The cEMI server will hand out the device address + 1 to the cEMI client (e.g. ETS),
|
||||||
|
// so that the device and the cEMI client/server connection(tunnel) can operate simultaneously.
|
||||||
|
// KNX IP Interfaces which offer multiple simultaneous tunnel connections seem to operate the same way.
|
||||||
|
// Each tunnel has its own cEMI client address which is based on the main device address.
|
||||||
|
if (((ObjectType) objectType == OT_DEVICE) &&
|
||||||
|
(propertyId == PID_DEVICE_ADDR) &&
|
||||||
|
(numberOfElements == 1))
|
||||||
|
{
|
||||||
|
data[0] = (uint8_t) (_clientAddress & 0xFF);
|
||||||
|
}
|
||||||
|
else if (((ObjectType) objectType == OT_DEVICE) &&
|
||||||
|
(propertyId == PID_SUBNET_ADDR) &&
|
||||||
|
(numberOfElements == 1))
|
||||||
|
{
|
||||||
|
data[0] = (uint8_t) ((_clientAddress >> 8) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data && dataSize && numberOfElements)
|
||||||
|
{
|
||||||
|
#ifdef KNX_LOG_TUNNELING
|
||||||
|
printHex(" <- data: ", data, dataSize);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Prepare positive response
|
||||||
|
uint8_t responseData[7 + dataSize];
|
||||||
|
memcpy(responseData, frame.data(), 7);
|
||||||
|
memcpy(&responseData[7], data, dataSize);
|
||||||
|
|
||||||
|
CemiFrame responseFrame(responseData, sizeof(responseData));
|
||||||
|
responseFrame.messageCode(M_PropRead_con);
|
||||||
|
#ifdef USE_USB
|
||||||
|
_usbTunnelInterface.sendCemiFrame(responseFrame);
|
||||||
|
#elif defined(KNX_TUNNELING)
|
||||||
|
_dataLinkLayerPrimary->dataRequestToTunnel(responseFrame);
|
||||||
|
#endif
|
||||||
|
delete[] data;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Prepare negative response
|
||||||
|
uint8_t responseData[7 + 1];
|
||||||
|
memcpy(responseData, frame.data(), sizeof(responseData));
|
||||||
|
responseData[7] = Void_DP; // Set cEMI error code
|
||||||
|
responseData[5] = 0; // Set Number of elements to zero
|
||||||
|
|
||||||
|
printHex(" <- error: ", &responseData[7], 1);
|
||||||
|
println("");
|
||||||
|
|
||||||
|
CemiFrame responseFrame(responseData, sizeof(responseData));
|
||||||
|
responseFrame.messageCode(M_PropRead_con);
|
||||||
|
#ifdef USE_USB
|
||||||
|
_usbTunnelInterface.sendCemiFrame(responseFrame);
|
||||||
|
#elif defined(KNX_TUNNELING)
|
||||||
|
_dataLinkLayerPrimary->dataRequestToTunnel(responseFrame);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiServer::handleMPropWrite(CemiFrame& frame)
|
||||||
|
{
|
||||||
|
print("M_PropWrite_req: ");
|
||||||
|
|
||||||
|
uint16_t objectType;
|
||||||
|
popWord(objectType, &frame.data()[1]);
|
||||||
|
uint8_t objectInstance = frame.data()[3];
|
||||||
|
uint8_t propertyId = frame.data()[4];
|
||||||
|
uint8_t numberOfElements = frame.data()[5] >> 4;
|
||||||
|
uint16_t startIndex = frame.data()[6] | ((frame.data()[5] & 0x0F) << 8);
|
||||||
|
uint8_t* requestData = &frame.data()[7];
|
||||||
|
uint32_t requestDataSize = frame.dataLength() - 7;
|
||||||
|
|
||||||
|
print("ObjType: ");
|
||||||
|
print(objectType, DEC);
|
||||||
|
print(" ObjInst: ");
|
||||||
|
print(objectInstance, DEC);
|
||||||
|
print(" PropId: ");
|
||||||
|
print(propertyId, DEC);
|
||||||
|
print(" NoE: ");
|
||||||
|
print(numberOfElements, DEC);
|
||||||
|
print(" startIdx: ");
|
||||||
|
print(startIndex, DEC);
|
||||||
|
|
||||||
|
printHex(" -> data: ", requestData, requestDataSize);
|
||||||
|
|
||||||
|
// Patch request for device address in device object
|
||||||
|
if (((ObjectType) objectType == OT_DEVICE) &&
|
||||||
|
(propertyId == PID_DEVICE_ADDR) &&
|
||||||
|
(numberOfElements == 1))
|
||||||
|
{
|
||||||
|
// Temporarily store new cEMI client address in memory
|
||||||
|
// We also be sent back if the client requests it again
|
||||||
|
_clientAddress = (_clientAddress & 0xFF00) | requestData[0];
|
||||||
|
print("cEMI client address: ");
|
||||||
|
println(_clientAddress, HEX);
|
||||||
|
}
|
||||||
|
else if (((ObjectType) objectType == OT_DEVICE) &&
|
||||||
|
(propertyId == PID_SUBNET_ADDR) &&
|
||||||
|
(numberOfElements == 1))
|
||||||
|
{
|
||||||
|
// Temporarily store new cEMI client address in memory
|
||||||
|
// We also be sent back if the client requests it again
|
||||||
|
_clientAddress = (_clientAddress & 0x00FF) | (requestData[0] << 8);
|
||||||
|
print("cEMI client address: ");
|
||||||
|
println(_clientAddress, HEX);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_bau.propertyValueWrite((ObjectType)objectType, objectInstance, propertyId, numberOfElements, startIndex, requestData, requestDataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numberOfElements)
|
||||||
|
{
|
||||||
|
// Prepare positive response
|
||||||
|
uint8_t responseData[7];
|
||||||
|
memcpy(responseData, frame.data(), sizeof(responseData));
|
||||||
|
|
||||||
|
println(" <- no error");
|
||||||
|
|
||||||
|
CemiFrame responseFrame(responseData, sizeof(responseData));
|
||||||
|
responseFrame.messageCode(M_PropWrite_con);
|
||||||
|
#ifdef USE_USB
|
||||||
|
_usbTunnelInterface.sendCemiFrame(responseFrame);
|
||||||
|
#elif defined(KNX_TUNNELING)
|
||||||
|
_dataLinkLayerPrimary->dataRequestToTunnel(responseFrame);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Prepare negative response
|
||||||
|
uint8_t responseData[7 + 1];
|
||||||
|
memcpy(responseData, frame.data(), sizeof(responseData));
|
||||||
|
responseData[7] = Illegal_Command; // Set cEMI error code
|
||||||
|
responseData[5] = 0; // Set Number of elements to zero
|
||||||
|
|
||||||
|
printHex(" <- error: ", &responseData[7], 1);
|
||||||
|
println("");
|
||||||
|
|
||||||
|
CemiFrame responseFrame(responseData, sizeof(responseData));
|
||||||
|
responseFrame.messageCode(M_PropWrite_con);
|
||||||
|
#ifdef USE_USB
|
||||||
|
_usbTunnelInterface.sendCemiFrame(responseFrame);
|
||||||
|
#elif defined(KNX_TUNNELING)
|
||||||
|
_dataLinkLayerPrimary->dataRequestToTunnel(responseFrame);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiServer::handleMReset(CemiFrame& frame)
|
||||||
|
{
|
||||||
|
println("M_Reset_req: sending M_Reset_ind");
|
||||||
|
// A real device reset does not work for USB or KNXNET/IP.
|
||||||
|
// Thus, M_Reset_ind is NOT mandatory for USB and KNXNET/IP.
|
||||||
|
// We just save all data to the EEPROM
|
||||||
|
_bau.writeMemory();
|
||||||
|
// Prepare response
|
||||||
|
uint8_t responseData[1];
|
||||||
|
CemiFrame responseFrame(responseData, sizeof(responseData));
|
||||||
|
responseFrame.messageCode(M_Reset_ind);
|
||||||
|
#ifdef USE_USB
|
||||||
|
_usbTunnelInterface.sendCemiFrame(responseFrame);
|
||||||
|
#elif defined(KNX_TUNNELING)
|
||||||
|
_dataLinkLayerPrimary->dataRequestToTunnel(responseFrame);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiServer::loop()
|
||||||
|
{
|
||||||
|
#ifdef USE_USB
|
||||||
|
_usbTunnelInterface.loop();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
68
components/knx/src/knx/cemi_server.h
Normal file
68
components/knx/src/knx/cemi_server.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "knx_types.h"
|
||||||
|
#include "usb_tunnel_interface.h"
|
||||||
|
|
||||||
|
class BauSystemB;
|
||||||
|
class DataLinkLayer;
|
||||||
|
class CemiFrame;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an implementation of the cEMI server as specified in @cite knx:3/6/3.
|
||||||
|
* Overview on page 57.
|
||||||
|
* It provides methods for the BusAccessUnit to do different things and translates this
|
||||||
|
* call to an cEMI frame and calls the correct method of the data link layer.
|
||||||
|
* It also takes calls from data link layer, decodes the submitted cEMI frames and calls the corresponding
|
||||||
|
* methods of the BusAccessUnit class.
|
||||||
|
*/
|
||||||
|
class CemiServer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* The constructor.
|
||||||
|
* @param bau methods are called here depending of the content of the APDU
|
||||||
|
*/
|
||||||
|
CemiServer(BauSystemB& bau);
|
||||||
|
|
||||||
|
void dataLinkLayer(DataLinkLayer& layer);
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
void dataLinkLayerPrimary(DataLinkLayer& layer);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// from data link layer
|
||||||
|
// Only L_Data service
|
||||||
|
void dataIndicationToTunnel(CemiFrame& frame);
|
||||||
|
void dataConfirmationToTunnel(CemiFrame& frame);
|
||||||
|
|
||||||
|
// From tunnel interface
|
||||||
|
void frameReceived(CemiFrame& frame);
|
||||||
|
|
||||||
|
uint16_t clientAddress() const;
|
||||||
|
void clientAddress(uint16_t value);
|
||||||
|
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t _clientAddress = 0;
|
||||||
|
uint8_t _frameNumber = 0;
|
||||||
|
|
||||||
|
void handleLData(CemiFrame& frame);
|
||||||
|
void handleMPropRead(CemiFrame& frame);
|
||||||
|
void handleMPropWrite(CemiFrame& frame);
|
||||||
|
void handleMReset(CemiFrame& frame);
|
||||||
|
|
||||||
|
DataLinkLayer* _dataLinkLayer = nullptr;
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
DataLinkLayer* _dataLinkLayerPrimary = nullptr;
|
||||||
|
#endif
|
||||||
|
BauSystemB& _bau;
|
||||||
|
#ifdef USE_USB
|
||||||
|
UsbTunnelInterface _usbTunnelInterface;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
61
components/knx/src/knx/cemi_server_object.cpp
Normal file
61
components/knx/src/knx/cemi_server_object.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include "config.h"
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include "cemi_server_object.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include "data_property.h"
|
||||||
|
|
||||||
|
CemiServerObject::CemiServerObject()
|
||||||
|
{
|
||||||
|
Property* properties[] =
|
||||||
|
{
|
||||||
|
new DataProperty( PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_CEMI_SERVER ),
|
||||||
|
new DataProperty( PID_MEDIUM_TYPE, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0, (uint16_t)0),
|
||||||
|
new DataProperty( PID_COMM_MODE, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint16_t)0),
|
||||||
|
new DataProperty( PID_COMM_MODES_SUPPORTED, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0, (uint16_t)0x100),
|
||||||
|
new DataProperty( PID_MEDIUM_AVAILABILITY, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0, (uint16_t)0),
|
||||||
|
// cEMI additional info types supported by this cEMI server: only 0x02 (RF Control Octet and Serial Number or DoA)
|
||||||
|
new DataProperty( PID_ADD_INFO_TYPES, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint8_t)0x02)
|
||||||
|
};
|
||||||
|
initializeProperties(sizeof(properties), properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiServerObject::setMediumTypeAsSupported(DptMedium dptMedium)
|
||||||
|
{
|
||||||
|
uint16_t mediaTypesSupported;
|
||||||
|
property(PID_MEDIUM_TYPE)->read(mediaTypesSupported);
|
||||||
|
|
||||||
|
switch (dptMedium)
|
||||||
|
{
|
||||||
|
case DptMedium::KNX_IP:
|
||||||
|
mediaTypesSupported |= 1 << 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DptMedium::KNX_RF:
|
||||||
|
mediaTypesSupported |= 1 << 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DptMedium::KNX_TP1:
|
||||||
|
mediaTypesSupported |= 1 << 5;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DptMedium::KNX_PL110:
|
||||||
|
mediaTypesSupported |= 1 << 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
property(PID_MEDIUM_TYPE)->write(mediaTypesSupported);
|
||||||
|
// We also set the medium as available too
|
||||||
|
property(PID_MEDIUM_AVAILABILITY)->write(mediaTypesSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiServerObject::clearSupportedMediaTypes()
|
||||||
|
{
|
||||||
|
property(PID_MEDIUM_TYPE)->write((uint16_t) 0);
|
||||||
|
// We also set the medium as not available too
|
||||||
|
property(PID_MEDIUM_AVAILABILITY)->write((uint16_t) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
17
components/knx/src/knx/cemi_server_object.h
Normal file
17
components/knx/src/knx/cemi_server_object.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
|
||||||
|
#include "interface_object.h"
|
||||||
|
|
||||||
|
class CemiServerObject: public InterfaceObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CemiServerObject();
|
||||||
|
|
||||||
|
void setMediumTypeAsSupported(DptMedium dptMedium);
|
||||||
|
void clearSupportedMediaTypes();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
84
components/knx/src/knx/config.h
Normal file
84
components/knx/src/knx/config.h
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NO_KNX_CONFIG
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_SAMD
|
||||||
|
#define SPI_SS_PIN 10
|
||||||
|
#define GPIO_GDO2_PIN 9
|
||||||
|
#define GPIO_GDO0_PIN 7
|
||||||
|
#else // Linux Platform (Raspberry Pi)
|
||||||
|
#define SPI_SS_PIN 8 // GPIO 8 (SPI_CE0_N) -> WiringPi: 10 -> Pin number on header: 24
|
||||||
|
#define GPIO_GDO2_PIN 25 // GPIO 25 (GPIO_GEN6) -> WiringPi: 6 -> Pin number on header: 22
|
||||||
|
#define GPIO_GDO0_PIN 24 // GPIO 24 (GPIO_GEN5) -> WiringPi: 5 -> Pin number on header: 18
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Normal devices
|
||||||
|
// TP1: 0x07B0
|
||||||
|
// RF: 0x27B0
|
||||||
|
// IP: 0x57B0
|
||||||
|
//#define MASK_VERSION 0x07B0
|
||||||
|
//#define MASK_VERSION 0x27B0
|
||||||
|
//#define MASK_VERSION 0x57B0
|
||||||
|
|
||||||
|
// Couplers
|
||||||
|
// IP/TP1: 0x091A
|
||||||
|
// TP1/RF: 0x2920
|
||||||
|
//#define MASK_VERSION 0x091A
|
||||||
|
//#define MASK_VERSION 0x2920
|
||||||
|
|
||||||
|
// Data Linklayer Driver Options
|
||||||
|
#if MASK_VERSION == 0x07B0
|
||||||
|
#define USE_TP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MASK_VERSION == 0x27B0
|
||||||
|
#define USE_RF
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MASK_VERSION == 0x57B0
|
||||||
|
#define USE_IP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MASK_VERSION == 0x091A
|
||||||
|
#define USE_TP
|
||||||
|
#define USE_IP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MASK_VERSION == 0x2920
|
||||||
|
#define USE_TP
|
||||||
|
#define USE_RF
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// cEMI options
|
||||||
|
//#define USE_USB
|
||||||
|
//#define USE_CEMI_SERVER
|
||||||
|
#if defined(USE_USB) || defined(KNX_TUNNELING)
|
||||||
|
#define USE_CEMI_SERVER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// KNX Data Secure Options
|
||||||
|
// Define via a compiler -D flag if required
|
||||||
|
// #define USE_DATASECURE
|
||||||
|
|
||||||
|
// option to have GroupObjects (KO in German) use 8 bytes mangement information RAM instead of 19 bytes
|
||||||
|
// see knx-demo-small-go for example
|
||||||
|
// this option might be also set via compiler flag -DSMALL_GROUPOBJECT if required
|
||||||
|
//#define SMALL_GROUPOBJECT
|
||||||
|
|
||||||
|
// Some defines to reduce footprint
|
||||||
|
// Do not perform conversion from KNXValue(const char*) to other types, it mainly avoids the expensive strtod
|
||||||
|
//#define KNX_NO_STRTOx_CONVERSION
|
||||||
|
// Do not print messages
|
||||||
|
//#define KNX_NO_PRINT
|
||||||
|
// Do not use SPI (Arduino variants)
|
||||||
|
//#define KNX_NO_SPI
|
||||||
|
// Do not use the default UART (Arduino variants), it must be defined by ArduinoPlatform::knxUart
|
||||||
|
// (combined with other flags (HWSERIAL_NONE for stm32) - avoid allocation of RX/TX buffers for all serial lines)
|
||||||
|
//#define KNX_NO_DEFAULT_UART
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(MASK_VERSION)
|
||||||
|
#error MASK_VERSION must be defined! See config.h for possible values!
|
||||||
|
#endif
|
||||||
|
|
||||||
309
components/knx/src/knx/data_link_layer.cpp
Normal file
309
components/knx/src/knx/data_link_layer.cpp
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
#include "data_link_layer.h"
|
||||||
|
|
||||||
|
#include "bits.h"
|
||||||
|
#include "platform.h"
|
||||||
|
#include "device_object.h"
|
||||||
|
#include "cemi_server.h"
|
||||||
|
#include "cemi_frame.h"
|
||||||
|
|
||||||
|
|
||||||
|
void DataLinkLayerCallbacks::activity(uint8_t info)
|
||||||
|
{
|
||||||
|
if (_activityCallback)
|
||||||
|
_activityCallback(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataLinkLayerCallbacks::setActivityCallback(ActivityCallback activityCallback)
|
||||||
|
{
|
||||||
|
_activityCallback = activityCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataLinkLayer::DataLinkLayer(DeviceObject& devObj, NetworkLayerEntity& netLayerEntity, Platform& platform) :
|
||||||
|
_deviceObject(devObj), _networkLayerEntity(netLayerEntity), _platform(platform)
|
||||||
|
{
|
||||||
|
#ifdef KNX_ACTIVITYCALLBACK
|
||||||
|
_netIndex = netLayerEntity.getEntityIndex();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
|
||||||
|
void DataLinkLayer::cemiServer(CemiServer& cemiServer)
|
||||||
|
{
|
||||||
|
_cemiServer = &cemiServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
void DataLinkLayer::dataRequestToTunnel(CemiFrame& frame)
|
||||||
|
{
|
||||||
|
println("default dataRequestToTunnel");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataLinkLayer::dataConfirmationToTunnel(CemiFrame& frame)
|
||||||
|
{
|
||||||
|
println("default dataConfirmationToTunnel");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataLinkLayer::dataIndicationToTunnel(CemiFrame& frame)
|
||||||
|
{
|
||||||
|
println("default dataIndicationToTunnel");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DataLinkLayer::isTunnelAddress(uint16_t addr)
|
||||||
|
{
|
||||||
|
println("default IsTunnelAddress");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void DataLinkLayer::dataRequestFromTunnel(CemiFrame& frame)
|
||||||
|
{
|
||||||
|
_cemiServer->dataConfirmationToTunnel(frame);
|
||||||
|
|
||||||
|
frame.messageCode(L_data_ind);
|
||||||
|
|
||||||
|
// Send to local stack ( => cemiServer for potential other tunnel and network layer for routing)
|
||||||
|
frameReceived(frame);
|
||||||
|
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
// TunnelOpti
|
||||||
|
// Optimize performance when receiving unicast data over tunnel wich is not meant to be used on the physical TP line
|
||||||
|
// dont send to knx when
|
||||||
|
// frame is individual adressed AND
|
||||||
|
// destionation == PA of Tunnel-Server OR
|
||||||
|
// destination == PA of a Tunnel OR (TODO)
|
||||||
|
// destination is not the TP/secondary line/segment but IP/primary (TODO)
|
||||||
|
|
||||||
|
if (frame.addressType() == AddressType::IndividualAddress)
|
||||||
|
{
|
||||||
|
if (frame.destinationAddress() == _deviceObject.individualAddress())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (isRoutedPA(frame.destinationAddress()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (isTunnelingPA(frame.destinationAddress()))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Send to KNX medium
|
||||||
|
sendFrame(frame);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void DataLinkLayer::dataRequest(AckType ack, AddressType addrType, uint16_t destinationAddr, uint16_t sourceAddr, FrameFormat format, Priority priority, NPDU& npdu)
|
||||||
|
{
|
||||||
|
// Normal data requests and broadcasts will always be transmitted as (domain) broadcast with domain address for open media (e.g. RF medium)
|
||||||
|
// The domain address "simulates" a closed medium (such as TP) on an open medium (such as RF or PL)
|
||||||
|
// See 3.2.5 p.22
|
||||||
|
sendTelegram(npdu, ack, destinationAddr, addrType, sourceAddr, format, priority, Broadcast);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataLinkLayer::systemBroadcastRequest(AckType ack, FrameFormat format, Priority priority, NPDU& npdu, uint16_t sourceAddr)
|
||||||
|
{
|
||||||
|
// System Broadcast requests will always be transmitted as broadcast with KNX serial number for open media (e.g. RF medium)
|
||||||
|
// See 3.2.5 p.22
|
||||||
|
sendTelegram(npdu, ack, 0, GroupAddress, sourceAddr, format, priority, SysBroadcast);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataLinkLayer::dataConReceived(CemiFrame& frame, bool success)
|
||||||
|
{
|
||||||
|
MessageCode backupMsgCode = frame.messageCode();
|
||||||
|
frame.messageCode(L_data_con);
|
||||||
|
frame.confirm(success ? ConfirmNoError : ConfirmError);
|
||||||
|
AckType ack = frame.ack();
|
||||||
|
AddressType addrType = frame.addressType();
|
||||||
|
uint16_t destination = frame.destinationAddress();
|
||||||
|
uint16_t source = frame.sourceAddress();
|
||||||
|
FrameFormat type = frame.frameType();
|
||||||
|
Priority priority = frame.priority();
|
||||||
|
NPDU& npdu = frame.npdu();
|
||||||
|
SystemBroadcast systemBroadcast = frame.systemBroadcast();
|
||||||
|
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
|
||||||
|
// if the confirmation was caused by a tunnel request then
|
||||||
|
// do not send it to the local stack
|
||||||
|
if (frame.sourceAddress() == _cemiServer->clientAddress())
|
||||||
|
{
|
||||||
|
// Stop processing here and do NOT send it the local network layer
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (addrType == GroupAddress && destination == 0)
|
||||||
|
if (systemBroadcast == SysBroadcast)
|
||||||
|
_networkLayerEntity.systemBroadcastConfirm(ack, type, priority, source, npdu, success);
|
||||||
|
else
|
||||||
|
_networkLayerEntity.broadcastConfirm(ack, type, priority, source, npdu, success);
|
||||||
|
else
|
||||||
|
_networkLayerEntity.dataConfirm(ack, addrType, destination, type, priority, source, npdu, success);
|
||||||
|
|
||||||
|
frame.messageCode(backupMsgCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataLinkLayer::frameReceived(CemiFrame& frame)
|
||||||
|
{
|
||||||
|
AckType ack = frame.ack();
|
||||||
|
AddressType addrType = frame.addressType();
|
||||||
|
uint16_t destination = frame.destinationAddress();
|
||||||
|
uint16_t source = frame.sourceAddress();
|
||||||
|
FrameFormat type = frame.frameType();
|
||||||
|
Priority priority = frame.priority();
|
||||||
|
NPDU& npdu = frame.npdu();
|
||||||
|
uint16_t ownAddr = _deviceObject.individualAddress();
|
||||||
|
SystemBroadcast systemBroadcast = frame.systemBroadcast();
|
||||||
|
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
// Do not send our own message back to the tunnel
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
|
||||||
|
//we dont need to check it here
|
||||||
|
// send inbound frames to the tunnel if we are the secondary (TP) interface
|
||||||
|
if ( _networkLayerEntity.getEntityIndex() == 1)
|
||||||
|
_cemiServer->dataIndicationToTunnel(frame);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
if (frame.sourceAddress() != _cemiServer->clientAddress())
|
||||||
|
{
|
||||||
|
_cemiServer->dataIndicationToTunnel(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// print("Frame received destination: ");
|
||||||
|
// print(destination, 16);
|
||||||
|
// println();
|
||||||
|
// print("frameReceived: frame valid? :");
|
||||||
|
// println(npdu.frame().valid() ? "true" : "false");
|
||||||
|
if (source == ownAddr)
|
||||||
|
_deviceObject.individualAddressDuplication(true);
|
||||||
|
|
||||||
|
if (addrType == GroupAddress && destination == 0)
|
||||||
|
{
|
||||||
|
if (systemBroadcast == SysBroadcast)
|
||||||
|
_networkLayerEntity.systemBroadcastIndication(ack, type, npdu, priority, source);
|
||||||
|
else
|
||||||
|
_networkLayerEntity.broadcastIndication(ack, type, npdu, priority, source);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_networkLayerEntity.dataIndication(ack, addrType, destination, type, npdu, priority, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DataLinkLayer::sendTelegram(NPDU& npdu, AckType ack, uint16_t destinationAddr, AddressType addrType, uint16_t sourceAddr, FrameFormat format, Priority priority, SystemBroadcast systemBroadcast, bool doNotRepeat)
|
||||||
|
{
|
||||||
|
CemiFrame& frame = npdu.frame();
|
||||||
|
// print("Send telegram frame valid ?: ");
|
||||||
|
// println(frame.valid()?"true":"false");
|
||||||
|
frame.messageCode(L_data_ind);
|
||||||
|
frame.destinationAddress(destinationAddr);
|
||||||
|
frame.sourceAddress(sourceAddr);
|
||||||
|
frame.addressType(addrType);
|
||||||
|
frame.priority(priority);
|
||||||
|
frame.repetition(doNotRepeat ? NoRepitiion : RepetitionAllowed);
|
||||||
|
frame.systemBroadcast(systemBroadcast);
|
||||||
|
|
||||||
|
if (npdu.octetCount() <= 15)
|
||||||
|
frame.frameType(StandardFrame);
|
||||||
|
else
|
||||||
|
frame.frameType(format);
|
||||||
|
|
||||||
|
|
||||||
|
if (!frame.valid())
|
||||||
|
{
|
||||||
|
println("invalid frame");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (frame.npdu().octetCount() > 0)
|
||||||
|
// {
|
||||||
|
// _print("<- DLL ");
|
||||||
|
// frame.apdu().printPDU();
|
||||||
|
// }
|
||||||
|
|
||||||
|
bool sendTheFrame = true;
|
||||||
|
bool success = true;
|
||||||
|
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
// TunnelOpti
|
||||||
|
// Optimize performance when sending unicast data over tunnel wich is not meant to be used on the physical TP line
|
||||||
|
// dont send to knx when
|
||||||
|
// a) we are the secondary interface (e.g. TP) AND
|
||||||
|
// b) destination == PA of a Tunnel (TODO)
|
||||||
|
|
||||||
|
if (_networkLayerEntity.getEntityIndex() == 1 && addrType == AddressType::IndividualAddress) // don't send to tp if we are the secondary (TP) interface AND the destination is a tunnel-PA
|
||||||
|
{
|
||||||
|
if (isTunnelingPA(destinationAddr))
|
||||||
|
sendTheFrame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The data link layer might be an open media link layer
|
||||||
|
// and will setup rfSerialOrDoA, rfInfo and rfLfn that we also
|
||||||
|
// have to send through the cEMI server tunnel
|
||||||
|
// Thus, reuse the modified cEMI frame as "frame" is only passed by reference here!
|
||||||
|
if (sendTheFrame)
|
||||||
|
success = sendFrame(frame);
|
||||||
|
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
CemiFrame tmpFrame(frame.data(), frame.totalLenght());
|
||||||
|
// We can just copy the pointer for rfSerialOrDoA as sendFrame() sets
|
||||||
|
// a pointer to const uint8_t data in either device object (serial) or
|
||||||
|
// RF medium object (domain address)
|
||||||
|
#ifdef USE_RF
|
||||||
|
tmpFrame.rfSerialOrDoA(frame.rfSerialOrDoA());
|
||||||
|
tmpFrame.rfInfo(frame.rfInfo());
|
||||||
|
tmpFrame.rfLfn(frame.rfLfn());
|
||||||
|
#endif
|
||||||
|
tmpFrame.confirm(ConfirmNoError);
|
||||||
|
|
||||||
|
if (_networkLayerEntity.getEntityIndex() == 1) // only send to tunnel if we are the secondary (TP) interface
|
||||||
|
_cemiServer->dataIndicationToTunnel(tmpFrame);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* DataLinkLayer::frameData(CemiFrame& frame)
|
||||||
|
{
|
||||||
|
return frame._data;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
bool DataLinkLayer::isTunnelingPA(uint16_t pa)
|
||||||
|
{
|
||||||
|
uint8_t numAddresses = 0;
|
||||||
|
uint16_t* addresses = _ipParameters->additionalIndivualAddresses(numAddresses);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < numAddresses; i++)
|
||||||
|
{
|
||||||
|
if (pa == addresses[i])
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DataLinkLayer::isRoutedPA(uint16_t pa)
|
||||||
|
{
|
||||||
|
uint16_t ownpa = _deviceObject.individualAddress();
|
||||||
|
uint16_t own_sm;
|
||||||
|
|
||||||
|
if ((ownpa & 0x0F00) == 0x0)
|
||||||
|
own_sm = 0xF000;
|
||||||
|
else
|
||||||
|
own_sm = 0xFF00;
|
||||||
|
|
||||||
|
return (pa & own_sm) != ownpa;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
77
components/knx/src/knx/data_link_layer.h
Normal file
77
components/knx/src/knx/data_link_layer.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "device_object.h"
|
||||||
|
#include "knx_types.h"
|
||||||
|
#include "network_layer_entity.h"
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
#include "ip_parameter_object.h"
|
||||||
|
#endif
|
||||||
|
#include "cemi_server.h"
|
||||||
|
#include "bau.h"
|
||||||
|
|
||||||
|
class Platform;
|
||||||
|
|
||||||
|
typedef void (*ActivityCallback)(uint8_t info);
|
||||||
|
|
||||||
|
class DataLinkLayerCallbacks
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
ActivityCallback _activityCallback = nullptr;
|
||||||
|
public:
|
||||||
|
virtual ~DataLinkLayerCallbacks() = default;
|
||||||
|
virtual void activity(uint8_t info);
|
||||||
|
virtual void setActivityCallback(ActivityCallback activityCallback);
|
||||||
|
};
|
||||||
|
|
||||||
|
class DataLinkLayer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DataLinkLayer(DeviceObject& devObj, NetworkLayerEntity& netLayerEntity,
|
||||||
|
Platform& platform);
|
||||||
|
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
// from tunnel
|
||||||
|
void cemiServer(CemiServer& cemiServer);
|
||||||
|
void dataRequestFromTunnel(CemiFrame& frame);
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
virtual void dataRequestToTunnel(CemiFrame& frame);
|
||||||
|
virtual void dataConfirmationToTunnel(CemiFrame& frame);
|
||||||
|
virtual void dataIndicationToTunnel(CemiFrame& frame);
|
||||||
|
virtual bool isTunnelAddress(uint16_t addr);
|
||||||
|
void ipParameterObject(IpParameterObject* object);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// from network layer
|
||||||
|
void dataRequest(AckType ack, AddressType addrType, uint16_t destinationAddr, uint16_t sourceAddr, FrameFormat format,
|
||||||
|
Priority priority, NPDU& npdu);
|
||||||
|
void systemBroadcastRequest(AckType ack, FrameFormat format, Priority priority, NPDU& npdu, uint16_t sourceAddr);
|
||||||
|
virtual void loop() = 0;
|
||||||
|
virtual void enabled(bool value) = 0;
|
||||||
|
virtual bool enabled() const = 0;
|
||||||
|
virtual DptMedium mediumType() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void frameReceived(CemiFrame& frame);
|
||||||
|
void dataConReceived(CemiFrame& frame, bool success);
|
||||||
|
bool sendTelegram(NPDU& npdu, AckType ack, uint16_t destinationAddr, AddressType addrType, uint16_t sourceAddr, FrameFormat format, Priority priority, SystemBroadcast systemBroadcast, bool doNotRepeat = false);
|
||||||
|
virtual bool sendFrame(CemiFrame& frame) = 0;
|
||||||
|
uint8_t* frameData(CemiFrame& frame);
|
||||||
|
DeviceObject& _deviceObject;
|
||||||
|
NetworkLayerEntity& _networkLayerEntity;
|
||||||
|
Platform& _platform;
|
||||||
|
#ifdef USE_CEMI_SERVER
|
||||||
|
CemiServer* _cemiServer;
|
||||||
|
#endif
|
||||||
|
#ifdef KNX_ACTIVITYCALLBACK
|
||||||
|
uint8_t _netIndex = 0;
|
||||||
|
#endif
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
bool isTunnelingPA(uint16_t pa);
|
||||||
|
bool isRoutedPA(uint16_t pa);
|
||||||
|
IpParameterObject* _ipParameters;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
168
components/knx/src/knx/data_property.cpp
Normal file
168
components/knx/src/knx/data_property.cpp
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
#include "data_property.h"
|
||||||
|
#include "bits.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
uint8_t DataProperty::read(uint16_t start, uint8_t count, uint8_t* data) const
|
||||||
|
{
|
||||||
|
if (start == 0)
|
||||||
|
{
|
||||||
|
pushWord(_currentElements, data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0 || _currentElements == 0 || start > _currentElements || count > _currentElements - start + 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
|
// we start counting with zero
|
||||||
|
start -= 1;
|
||||||
|
|
||||||
|
// data is already big enough to hold the data
|
||||||
|
memcpy(data, _data + (start * ElementSize()), count * ElementSize());
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t DataProperty::write(uint16_t start, uint8_t count, const uint8_t* data)
|
||||||
|
{
|
||||||
|
if (count == 0 || start > _maxElements || start + count > _maxElements + 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (start == 0)
|
||||||
|
{
|
||||||
|
if (count == 1 && data[0] == 0 && data[1] == 0)
|
||||||
|
{
|
||||||
|
// reset _data
|
||||||
|
_currentElements = 0;
|
||||||
|
|
||||||
|
if (_data)
|
||||||
|
{
|
||||||
|
delete[] _data;
|
||||||
|
_data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we start counting with zero
|
||||||
|
start -= 1;
|
||||||
|
|
||||||
|
if (start + count > _currentElements)
|
||||||
|
{
|
||||||
|
// reallocate memory for _data
|
||||||
|
uint8_t* oldData = _data;
|
||||||
|
size_t oldDataSize = _currentElements * ElementSize();
|
||||||
|
|
||||||
|
size_t newDataSize = (start + count) * ElementSize();
|
||||||
|
_data = new uint8_t[newDataSize];
|
||||||
|
memset(_data, 0, newDataSize);
|
||||||
|
|
||||||
|
if (oldData != nullptr)
|
||||||
|
{
|
||||||
|
memcpy(_data, oldData, oldDataSize);
|
||||||
|
delete[] oldData;
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentElements = start + count;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(_data + (start * ElementSize()), data, count * ElementSize());
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type,
|
||||||
|
uint16_t maxElements, uint8_t access)
|
||||||
|
: Property(id, writeEnable, type, maxElements, access)
|
||||||
|
{}
|
||||||
|
|
||||||
|
DataProperty::~DataProperty()
|
||||||
|
{
|
||||||
|
if (_data)
|
||||||
|
delete[] _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type,
|
||||||
|
uint16_t maxElements, uint8_t access, uint16_t value)
|
||||||
|
: Property(id, writeEnable, type, maxElements, access)
|
||||||
|
{
|
||||||
|
Property::write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type,
|
||||||
|
uint16_t maxElements, uint8_t access, uint32_t value)
|
||||||
|
: Property(id, writeEnable, type, maxElements, access)
|
||||||
|
{
|
||||||
|
Property::write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type,
|
||||||
|
uint16_t maxElements, uint8_t access, uint8_t value)
|
||||||
|
: Property(id, writeEnable, type, maxElements, access)
|
||||||
|
{
|
||||||
|
Property::write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type,
|
||||||
|
uint16_t maxElements, uint8_t access, const uint8_t* value)
|
||||||
|
: Property(id, writeEnable, type, maxElements, access)
|
||||||
|
{
|
||||||
|
Property::write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t DataProperty::saveSize()
|
||||||
|
{
|
||||||
|
return sizeof(_currentElements) + _maxElements * ElementSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t* DataProperty::restore(const uint8_t* buffer)
|
||||||
|
{
|
||||||
|
uint16_t elements = 0;
|
||||||
|
buffer = popWord(elements, buffer);
|
||||||
|
|
||||||
|
if (elements != _currentElements)
|
||||||
|
{
|
||||||
|
if (_data != nullptr)
|
||||||
|
delete[] _data;
|
||||||
|
|
||||||
|
_data = new uint8_t[elements * ElementSize()];
|
||||||
|
_currentElements = elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elements > 0)
|
||||||
|
buffer = popByteArray(_data, elements * ElementSize(), buffer);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t* DataProperty::save(uint8_t* buffer)
|
||||||
|
{
|
||||||
|
buffer = pushWord(_currentElements, buffer);
|
||||||
|
|
||||||
|
if (_currentElements > 0)
|
||||||
|
buffer = pushByteArray(_data, _currentElements * ElementSize(), buffer);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t* DataProperty::data()
|
||||||
|
{
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* DataProperty::data(uint16_t elementIndex)
|
||||||
|
{
|
||||||
|
if ((elementIndex == 0) || (elementIndex > _currentElements))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
elementIndex -= 1; // Starting from 0
|
||||||
|
uint16_t offset = elementIndex * ElementSize();
|
||||||
|
return _data + offset;
|
||||||
|
}
|
||||||
25
components/knx/src/knx/data_property.h
Normal file
25
components/knx/src/knx/data_property.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "property.h"
|
||||||
|
|
||||||
|
class DataProperty : public Property
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access);
|
||||||
|
DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, uint8_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, const uint8_t* value);
|
||||||
|
~DataProperty() override;
|
||||||
|
uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const override;
|
||||||
|
uint8_t write(uint16_t start, uint8_t count, const uint8_t* data) override;
|
||||||
|
uint8_t* save(uint8_t* buffer) override;
|
||||||
|
const uint8_t* restore(const uint8_t* buffer) override;
|
||||||
|
uint16_t saveSize() override;
|
||||||
|
const uint8_t* data();
|
||||||
|
const uint8_t* data(uint16_t elementIndex);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t _currentElements = 0;
|
||||||
|
uint8_t* _data = nullptr;
|
||||||
|
};
|
||||||
64
components/knx/src/knx/datapoint_types.cpp
Normal file
64
components/knx/src/knx/datapoint_types.cpp
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* datapoint_types.h - Conversion functions for datapoint types.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Stefan Taferner <stefan.taferner@gmx.at>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 3 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "datapoint_types.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// Sign for a negative DPT9 float value
|
||||||
|
#define DPT_FLOAT_NEG_SIGN 0x8000
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t dptToFloat(int32_t value)
|
||||||
|
{
|
||||||
|
uint16_t exp = 0;
|
||||||
|
|
||||||
|
if (value < -67108864 || value > 67076096)
|
||||||
|
return 0x7fff;
|
||||||
|
|
||||||
|
if (value < 0)
|
||||||
|
{
|
||||||
|
while (value < -2048)
|
||||||
|
{
|
||||||
|
value >>= 1;
|
||||||
|
++exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DPT_FLOAT_NEG_SIGN | (((int32_t) value) & 2047) | (exp << 11);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (value > 2047)
|
||||||
|
{
|
||||||
|
value >>= 1;
|
||||||
|
++exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value | (exp << 11);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t dptFromFloat(uint16_t dptValue)
|
||||||
|
{
|
||||||
|
uint16_t exp = (dptValue >> 11) & 15;
|
||||||
|
int32_t value;
|
||||||
|
|
||||||
|
if (dptValue == 0x7fff)
|
||||||
|
return INVALID_DPT_FLOAT;
|
||||||
|
|
||||||
|
if (dptValue >= 0x8000)
|
||||||
|
value = dptValue | (-1L & ~2047);
|
||||||
|
else
|
||||||
|
value = dptValue & 2047;
|
||||||
|
|
||||||
|
for (; exp; --exp)
|
||||||
|
value <<= 1;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
37
components/knx/src/knx/datapoint_types.h
Normal file
37
components/knx/src/knx/datapoint_types.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* datapoint_types.h - Conversion functions for datapoint types.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Stefan Taferner <stefan.taferner@gmx.at>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 3 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An invalid 2 uint8_t float (DPT9/EIS5).
|
||||||
|
* To be used for dptToFloat() and dptFromFloat().
|
||||||
|
*/
|
||||||
|
#define INVALID_DPT_FLOAT 2147483647U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a value from uint32_t to 2 uint8_t float (DPT9/EIS5). The possible range
|
||||||
|
* of the values is -67108864 to 67076096.
|
||||||
|
*
|
||||||
|
* @param value - the value to convert.
|
||||||
|
* Use INVALID_DPT_FLOAT for the DPT9 "invalid data" value.
|
||||||
|
* @return The 2 uint8_t float (DPT9/EIS5).
|
||||||
|
*/
|
||||||
|
uint16_t dptToFloat(int32_t value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a value from 2 uint8_t float (DPT9/EIS5) to integer.
|
||||||
|
*
|
||||||
|
* @param dptValue - the 2 uint8_t float (DPT9/EIS5) to convert
|
||||||
|
* @return The value as integer, or INVALID_DPT_FLOAT for the
|
||||||
|
* DPT9 "invalid data" value.
|
||||||
|
*/
|
||||||
|
int32_t dptFromFloat(uint16_t dptValue);
|
||||||
294
components/knx/src/knx/device_object.cpp
Normal file
294
components/knx/src/knx/device_object.cpp
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
#include <cstring>
|
||||||
|
#include "device_object.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include "data_property.h"
|
||||||
|
#include "callback_property.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#define LEN_KNX_SERIAL 6
|
||||||
|
|
||||||
|
DeviceObject::DeviceObject()
|
||||||
|
{
|
||||||
|
// Default to KNXA (0xFA)
|
||||||
|
// Note: ETS does not accept a SN 00FA00000000 in data secure mode.
|
||||||
|
// ETS says that 00FA00000000 looks "suspicious" in the log file.
|
||||||
|
uint8_t serialNumber[] = {0x00, 0xFA, 0x01, 0x02, 0x03, 0x04};
|
||||||
|
uint8_t hardwareType[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
|
Property* properties[] =
|
||||||
|
{
|
||||||
|
new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_DEVICE),
|
||||||
|
new DataProperty(PID_SERIAL_NUMBER, false, PDT_GENERIC_06, 1, ReadLv3 | WriteLv0, serialNumber),
|
||||||
|
new CallbackProperty<DeviceObject>(this, PID_MANUFACTURER_ID, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0,
|
||||||
|
[](DeviceObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t
|
||||||
|
{
|
||||||
|
if (start == 0)
|
||||||
|
{
|
||||||
|
uint16_t currentNoOfElements = 1;
|
||||||
|
pushWord(currentNoOfElements, data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pushByteArray(io->propertyData(PID_SERIAL_NUMBER), 2, data);
|
||||||
|
return 1;
|
||||||
|
}),
|
||||||
|
new DataProperty(PID_DEVICE_CONTROL, true, PDT_BITSET8, 1, ReadLv3 | WriteLv3, (uint8_t)0),
|
||||||
|
new DataProperty(PID_ORDER_INFO, false, PDT_GENERIC_10, 1, ReadLv3 | WriteLv0),
|
||||||
|
new DataProperty(PID_VERSION, false, PDT_VERSION, 1, ReadLv3 | WriteLv0, (uint16_t)3),
|
||||||
|
new DataProperty(PID_ROUTING_COUNT, true, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv3, (uint8_t)(6 << 4)),
|
||||||
|
new CallbackProperty<DeviceObject>(this, PID_PROG_MODE, true, PDT_BITSET8, 1, ReadLv3 | WriteLv3,
|
||||||
|
[](DeviceObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t
|
||||||
|
{
|
||||||
|
if (start == 0)
|
||||||
|
{
|
||||||
|
uint16_t currentNoOfElements = 1;
|
||||||
|
pushWord(currentNoOfElements, data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*data = io->_prgMode;
|
||||||
|
return 1;
|
||||||
|
},
|
||||||
|
[](DeviceObject * io, uint16_t start, uint8_t count, const uint8_t* data) -> uint8_t
|
||||||
|
{
|
||||||
|
if (start == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
io->_prgMode = *data;
|
||||||
|
return 1;
|
||||||
|
}),
|
||||||
|
new DataProperty(PID_MAX_APDU_LENGTH, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)254),
|
||||||
|
new CallbackProperty<DeviceObject>(this, PID_SUBNET_ADDR, false, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv0,
|
||||||
|
[](DeviceObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t
|
||||||
|
{
|
||||||
|
if (start == 0)
|
||||||
|
{
|
||||||
|
uint16_t currentNoOfElements = 1;
|
||||||
|
pushWord(currentNoOfElements, data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*data = ((io->_ownAddress >> 8) & 0xff);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}),
|
||||||
|
new CallbackProperty<DeviceObject>(this, PID_DEVICE_ADDR, false, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv0,
|
||||||
|
[](DeviceObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t
|
||||||
|
{
|
||||||
|
if (start == 0)
|
||||||
|
{
|
||||||
|
uint16_t currentNoOfElements = 1;
|
||||||
|
pushWord(currentNoOfElements, data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*data = (io->_ownAddress & 0xff);
|
||||||
|
return 1;
|
||||||
|
}),
|
||||||
|
new DataProperty(PID_IO_LIST, false, PDT_UNSIGNED_INT, 8, ReadLv3 | WriteLv0),
|
||||||
|
new DataProperty(PID_HARDWARE_TYPE, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv3, hardwareType),
|
||||||
|
new DataProperty(PID_DEVICE_DESCRIPTOR, false, PDT_GENERIC_02, 1, ReadLv3 | WriteLv0),
|
||||||
|
#ifdef USE_RF
|
||||||
|
new DataProperty(PID_RF_DOMAIN_ADDRESS_CEMI_SERVER, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv3),
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
initializeProperties(sizeof(properties), properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* DeviceObject::save(uint8_t* buffer)
|
||||||
|
{
|
||||||
|
buffer = pushWord(_ownAddress, buffer);
|
||||||
|
return InterfaceObject::save(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* DeviceObject::restore(const uint8_t* buffer)
|
||||||
|
{
|
||||||
|
buffer = popWord(_ownAddress, buffer);
|
||||||
|
return InterfaceObject::restore(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t DeviceObject::saveSize()
|
||||||
|
{
|
||||||
|
return 2 + InterfaceObject::saveSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t DeviceObject::individualAddress()
|
||||||
|
{
|
||||||
|
return _ownAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceObject::individualAddress(uint16_t value)
|
||||||
|
{
|
||||||
|
_ownAddress = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define USER_STOPPED 0x1
|
||||||
|
#define OWN_ADDR_DUPL 0x2
|
||||||
|
#define VERIFY_MODE 0x4
|
||||||
|
#define SAFE_STATE 0x8
|
||||||
|
|
||||||
|
|
||||||
|
void DeviceObject::individualAddressDuplication(bool value)
|
||||||
|
{
|
||||||
|
Property* prop = property(PID_DEVICE_CONTROL);
|
||||||
|
uint8_t data;
|
||||||
|
prop->read(data);
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
data |= OWN_ADDR_DUPL;
|
||||||
|
else
|
||||||
|
data &= ~OWN_ADDR_DUPL;
|
||||||
|
|
||||||
|
prop->write(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceObject::verifyMode()
|
||||||
|
{
|
||||||
|
Property* prop = property(PID_DEVICE_CONTROL);
|
||||||
|
uint8_t data;
|
||||||
|
prop->read(data);
|
||||||
|
return (data & VERIFY_MODE) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceObject::verifyMode(bool value)
|
||||||
|
{
|
||||||
|
Property* prop = property(PID_DEVICE_CONTROL);
|
||||||
|
uint8_t data;
|
||||||
|
prop->read(data);
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
data |= VERIFY_MODE;
|
||||||
|
else
|
||||||
|
data &= ~VERIFY_MODE;
|
||||||
|
|
||||||
|
prop->write(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceObject::progMode()
|
||||||
|
{
|
||||||
|
return _prgMode == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceObject::progMode(bool value)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
_prgMode = 1;
|
||||||
|
else
|
||||||
|
_prgMode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t DeviceObject::manufacturerId()
|
||||||
|
{
|
||||||
|
uint16_t manufacturerId;
|
||||||
|
popWord(manufacturerId, propertyData(PID_SERIAL_NUMBER));
|
||||||
|
return manufacturerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceObject::manufacturerId(uint16_t value)
|
||||||
|
{
|
||||||
|
uint8_t data[LEN_KNX_SERIAL];
|
||||||
|
memcpy(data, propertyData(PID_SERIAL_NUMBER), LEN_KNX_SERIAL);
|
||||||
|
pushWord(value, data);
|
||||||
|
propertyValue(PID_SERIAL_NUMBER, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DeviceObject::bauNumber()
|
||||||
|
{
|
||||||
|
uint32_t bauNumber;
|
||||||
|
popInt(bauNumber, propertyData(PID_SERIAL_NUMBER) + 2);
|
||||||
|
return bauNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceObject::bauNumber(uint32_t value)
|
||||||
|
{
|
||||||
|
uint8_t data[LEN_KNX_SERIAL];
|
||||||
|
memcpy(data, propertyData(PID_SERIAL_NUMBER), LEN_KNX_SERIAL);
|
||||||
|
pushInt(value, data + 2);
|
||||||
|
propertyValue(PID_SERIAL_NUMBER, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* DeviceObject::orderNumber()
|
||||||
|
{
|
||||||
|
DataProperty* prop = (DataProperty*)property(PID_ORDER_INFO);
|
||||||
|
return prop->data();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceObject::orderNumber(const uint8_t* value)
|
||||||
|
{
|
||||||
|
Property* prop = property(PID_ORDER_INFO);
|
||||||
|
prop->write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* DeviceObject::hardwareType()
|
||||||
|
{
|
||||||
|
DataProperty* prop = (DataProperty*)property(PID_HARDWARE_TYPE);
|
||||||
|
return prop->data();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceObject::hardwareType(const uint8_t* value)
|
||||||
|
{
|
||||||
|
Property* prop = property(PID_HARDWARE_TYPE);
|
||||||
|
prop->write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t DeviceObject::version()
|
||||||
|
{
|
||||||
|
Property* prop = property(PID_VERSION);
|
||||||
|
uint16_t value;
|
||||||
|
prop->read(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceObject::version(uint16_t value)
|
||||||
|
{
|
||||||
|
Property* prop = property(PID_VERSION);
|
||||||
|
prop->write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t DeviceObject::maskVersion()
|
||||||
|
{
|
||||||
|
Property* prop = property(PID_DEVICE_DESCRIPTOR);
|
||||||
|
uint16_t value;
|
||||||
|
prop->read(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceObject::maskVersion(uint16_t value)
|
||||||
|
{
|
||||||
|
Property* prop = property(PID_DEVICE_DESCRIPTOR);
|
||||||
|
prop->write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t DeviceObject::maxApduLength()
|
||||||
|
{
|
||||||
|
Property* prop = property(PID_MAX_APDU_LENGTH);
|
||||||
|
uint16_t value;
|
||||||
|
prop->read(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceObject::maxApduLength(uint16_t value)
|
||||||
|
{
|
||||||
|
Property* prop = property(PID_MAX_APDU_LENGTH);
|
||||||
|
prop->write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* DeviceObject::rfDomainAddress()
|
||||||
|
{
|
||||||
|
DataProperty* prop = (DataProperty*)property(PID_RF_DOMAIN_ADDRESS_CEMI_SERVER);
|
||||||
|
return prop->data();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceObject::rfDomainAddress(uint8_t* value)
|
||||||
|
{
|
||||||
|
Property* prop = property(PID_RF_DOMAIN_ADDRESS_CEMI_SERVER);
|
||||||
|
prop->write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t DeviceObject::defaultHopCount()
|
||||||
|
{
|
||||||
|
Property* prop = property(PID_ROUTING_COUNT);
|
||||||
|
uint8_t value;
|
||||||
|
prop->read(value);
|
||||||
|
return (value >> 4) & 0x07;
|
||||||
|
}
|
||||||
51
components/knx/src/knx/device_object.h
Normal file
51
components/knx/src/knx/device_object.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "interface_object.h"
|
||||||
|
|
||||||
|
#define LEN_HARDWARE_TYPE 6
|
||||||
|
|
||||||
|
class DeviceObject: public InterfaceObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// increase this version anytime DeviceObject-API changes
|
||||||
|
// the following value represents the serialized representation of DeviceObject.
|
||||||
|
const uint16_t apiVersion = 1;
|
||||||
|
|
||||||
|
DeviceObject();
|
||||||
|
uint8_t* save(uint8_t* buffer) override;
|
||||||
|
const uint8_t* restore(const uint8_t* buffer) override;
|
||||||
|
uint16_t saveSize() override;
|
||||||
|
|
||||||
|
uint16_t individualAddress();
|
||||||
|
void individualAddress(uint16_t value);
|
||||||
|
|
||||||
|
void individualAddressDuplication(bool value);
|
||||||
|
bool verifyMode();
|
||||||
|
void verifyMode(bool value);
|
||||||
|
bool progMode();
|
||||||
|
void progMode(bool value);
|
||||||
|
uint16_t manufacturerId();
|
||||||
|
void manufacturerId(uint16_t value);
|
||||||
|
uint32_t bauNumber();
|
||||||
|
void bauNumber(uint32_t value);
|
||||||
|
const uint8_t* orderNumber();
|
||||||
|
void orderNumber(const uint8_t* value);
|
||||||
|
const uint8_t* hardwareType();
|
||||||
|
void hardwareType(const uint8_t* value);
|
||||||
|
uint16_t version();
|
||||||
|
void version(uint16_t value);
|
||||||
|
uint16_t maskVersion();
|
||||||
|
void maskVersion(uint16_t value);
|
||||||
|
uint16_t maxApduLength();
|
||||||
|
void maxApduLength(uint16_t value);
|
||||||
|
const uint8_t* rfDomainAddress();
|
||||||
|
void rfDomainAddress(uint8_t* value);
|
||||||
|
uint8_t defaultHopCount();
|
||||||
|
private:
|
||||||
|
uint8_t _prgMode = 0;
|
||||||
|
#if MASK_VERSION == 0x091A || MASK_VERSION == 0x2920
|
||||||
|
uint16_t _ownAddress = 0xFF00; // 15.15.0; couplers have 15.15.0 as default PA
|
||||||
|
#else
|
||||||
|
uint16_t _ownAddress = 0xFFFF; // 15.15.255;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
23
components/knx/src/knx/dpt.cpp
Normal file
23
components/knx/src/knx/dpt.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include "dpt.h"
|
||||||
|
|
||||||
|
#include "bits.h"
|
||||||
|
|
||||||
|
Dpt::Dpt()
|
||||||
|
{}
|
||||||
|
|
||||||
|
Dpt::Dpt(short mainGroup, short subGroup, short index /* = 0 */)
|
||||||
|
: mainGroup(mainGroup), subGroup(subGroup), index(index)
|
||||||
|
{
|
||||||
|
if (subGroup == 0 && (mainGroup < 14 || mainGroup > 16))
|
||||||
|
println("WARNING: You used an invalid Dpt *.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Dpt::operator==(const Dpt& other) const
|
||||||
|
{
|
||||||
|
return other.mainGroup == mainGroup && other.subGroup == subGroup && other.index == index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Dpt::operator!=(const Dpt& other) const
|
||||||
|
{
|
||||||
|
return !(other == *this);
|
||||||
|
}
|
||||||
373
components/knx/src/knx/dpt.h
Normal file
373
components/knx/src/knx/dpt.h
Normal file
@ -0,0 +1,373 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define DPT_Switch Dpt(1, 1)
|
||||||
|
#define DPT_Bool Dpt(1, 2)
|
||||||
|
#define DPT_Enable Dpt(1, 3)
|
||||||
|
#define DPT_Ramp Dpt(1, 4)
|
||||||
|
#define DPT_Alarm Dpt(1, 5)
|
||||||
|
#define DPT_BinaryValue Dpt(1, 6)
|
||||||
|
#define DPT_Step Dpt(1, 7)
|
||||||
|
#define DPT_UpDown Dpt(1, 8)
|
||||||
|
#define DPT_OpenClose Dpt(1, 9)
|
||||||
|
#define DPT_Start Dpt(1, 10)
|
||||||
|
#define DPT_State Dpt(1, 11)
|
||||||
|
#define DPT_Invert Dpt(1, 12)
|
||||||
|
#define DPT_DimSendStyle Dpt(1, 13)
|
||||||
|
#define DPT_InputSource Dpt(1, 14)
|
||||||
|
#define DPT_Reset Dpt(1, 15)
|
||||||
|
#define DPT_Ack Dpt(1, 16)
|
||||||
|
#define DPT_Trigger Dpt(1, 17)
|
||||||
|
#define DPT_Occupancy Dpt(1, 18)
|
||||||
|
#define DPT_Window_Door Dpt(1, 19)
|
||||||
|
#define DPT_LogicalFunction Dpt(1, 21)
|
||||||
|
#define DPT_Scene_AB Dpt(1, 22)
|
||||||
|
#define DPT_ShutterBlinds_Mode Dpt(1, 23)
|
||||||
|
#define DPT_Heat_Cool Dpt(1, 100)
|
||||||
|
#define DPT_Switch_Control Dpt(2, 1)
|
||||||
|
#define DPT_Bool_Control Dpt(2, 2)
|
||||||
|
#define DPT_Enable_Control Dpt(2, 3)
|
||||||
|
#define DPT_Ramp_Control Dpt(2, 4)
|
||||||
|
#define DPT_Alarm_Control Dpt(2, 5)
|
||||||
|
#define DPT_BinaryValue_Control Dpt(2, 6)
|
||||||
|
#define DPT_Step_Control Dpt(2, 7)
|
||||||
|
#define DPT_Direction1_Control Dpt(2, 8)
|
||||||
|
#define DPT_Direction2_Control Dpt(2, 9)
|
||||||
|
#define DPT_Start_Control Dpt(2, 10)
|
||||||
|
#define DPT_State_Control Dpt(2, 11)
|
||||||
|
#define DPT_Invert_Control Dpt(2, 12)
|
||||||
|
#define DPT_Control_Dimming Dpt(3, 7)
|
||||||
|
#define DPT_Control_Blinds Dpt(3, 8)
|
||||||
|
#define DPT_Char_ASCII Dpt(4, 1)
|
||||||
|
#define DPT_Char_8859_1 Dpt(4, 2)
|
||||||
|
#define DPT_Scaling Dpt(5, 1)
|
||||||
|
#define DPT_Angle Dpt(5, 3)
|
||||||
|
#define DPT_Percent_U8 Dpt(5, 4)
|
||||||
|
#define DPT_DecimalFactor Dpt(5, 5)
|
||||||
|
#define DPT_Tariff Dpt(5, 6)
|
||||||
|
#define DPT_Value_1_Ucount Dpt(5, 10)
|
||||||
|
#define DPT_Percent_V8 Dpt(6, 1)
|
||||||
|
#define DPT_Value_1_Count Dpt(6, 10)
|
||||||
|
#define DPT_Status_Mode3 Dpt(6, 20)
|
||||||
|
#define DPT_Value_2_Ucount Dpt(7, 1)
|
||||||
|
#define DPT_TimePeriodMsec Dpt(7, 2)
|
||||||
|
#define DPT_TimePeriod10MSec Dpt(7, 3)
|
||||||
|
#define DPT_TimePeriod100MSec Dpt(7, 4)
|
||||||
|
#define DPT_TimePeriodSec Dpt(7, 5)
|
||||||
|
#define DPT_TimePeriodMin Dpt(7, 6)
|
||||||
|
#define DPT_TimePeriodHrs Dpt(7, 7)
|
||||||
|
#define DPT_PropDataType Dpt(7, 10)
|
||||||
|
#define DPT_Length_mm Dpt(7, 11)
|
||||||
|
#define DPT_UElCurrentmA Dpt(7, 12)
|
||||||
|
#define DPT_Brightness Dpt(7, 13)
|
||||||
|
#define DPT_Value_2_Count Dpt(8, 1)
|
||||||
|
#define DPT_DeltaTimeMsec Dpt(8, 2)
|
||||||
|
#define DPT_DeltaTime10MSec Dpt(8, 3)
|
||||||
|
#define DPT_DeltaTime100MSec Dpt(8, 4)
|
||||||
|
#define DPT_DeltaTimeSec Dpt(8, 5)
|
||||||
|
#define DPT_DeltaTimeMin Dpt(8, 6)
|
||||||
|
#define DPT_DeltaTimeHrs Dpt(8, 7)
|
||||||
|
#define DPT_Percent_V16 Dpt(8, 10)
|
||||||
|
#define DPT_Rotation_Angle Dpt(8, 11)
|
||||||
|
#define DPT_Value_Temp Dpt(9, 1)
|
||||||
|
#define DPT_Value_Tempd Dpt(9, 2)
|
||||||
|
#define DPT_Value_Tempa Dpt(9, 3)
|
||||||
|
#define DPT_Value_Lux Dpt(9, 4)
|
||||||
|
#define DPT_Value_Wsp Dpt(9, 5)
|
||||||
|
#define DPT_Value_Pres Dpt(9, 6)
|
||||||
|
#define DPT_Value_Humidity Dpt(9, 7)
|
||||||
|
#define DPT_Value_AirQuality Dpt(9, 8)
|
||||||
|
#define DPT_Value_Time1 Dpt(9, 10)
|
||||||
|
#define DPT_Value_Time2 Dpt(9, 11)
|
||||||
|
#define DPT_Value_Volt Dpt(9, 20)
|
||||||
|
#define DPT_Value_Curr Dpt(9, 21)
|
||||||
|
#define DPT_PowerDensity Dpt(9, 22)
|
||||||
|
#define DPT_KelvinPerPercent Dpt(9, 23)
|
||||||
|
#define DPT_Power Dpt(9, 24)
|
||||||
|
#define DPT_Value_Volume_Flow Dpt(9, 25)
|
||||||
|
#define DPT_Rain_Amount Dpt(9, 26)
|
||||||
|
#define DPT_Value_Temp_F Dpt(9, 27)
|
||||||
|
#define DPT_Value_Wsp_kmh Dpt(9, 28)
|
||||||
|
#define DPT_TimeOfDay Dpt(10, 1, 1)
|
||||||
|
#define DPT_Date Dpt(11, 1)
|
||||||
|
#define DPT_Value_4_Ucount Dpt(12, 1)
|
||||||
|
#define DPT_Value_4_Count Dpt(13, 1)
|
||||||
|
#define DPT_FlowRate_m3_per_h Dpt(13, 2)
|
||||||
|
#define DPT_ActiveEnergy Dpt(13, 10)
|
||||||
|
#define DPT_ApparantEnergy Dpt(13, 11)
|
||||||
|
#define DPT_ReactiveEnergy Dpt(13, 12)
|
||||||
|
#define DPT_ActiveEnergy_kWh Dpt(13, 13)
|
||||||
|
#define DPT_ApparantEnergy_kVAh Dpt(13, 14)
|
||||||
|
#define DPT_ReactiveEnergy_kVARh Dpt(13, 15)
|
||||||
|
#define DPT_LongDeltaTimeSec Dpt(13, 100)
|
||||||
|
#define DPT_Value_Acceleration Dpt(14, 0)
|
||||||
|
#define DPT_Value_Acceleration_Angular Dpt(14, 1)
|
||||||
|
#define DPT_Value_Activation_Energy Dpt(14, 2)
|
||||||
|
#define DPT_Value_Activity Dpt(14, 3)
|
||||||
|
#define DPT_Value_Mol Dpt(14, 4)
|
||||||
|
#define DPT_Value_Amplitude Dpt(14, 5)
|
||||||
|
#define DPT_Value_AngleRad Dpt(14, 6)
|
||||||
|
#define DPT_Value_AngleDeg Dpt(14, 7)
|
||||||
|
#define DPT_Value_Angular_Momentum Dpt(14, 8)
|
||||||
|
#define DPT_Value_Angular_Velocity Dpt(14, 9)
|
||||||
|
#define DPT_Value_Area Dpt(14, 10)
|
||||||
|
#define DPT_Value_Capacitance Dpt(14, 11)
|
||||||
|
#define DPT_Value_Charge_DensitySurface Dpt(14, 12)
|
||||||
|
#define DPT_Value_Charge_DensityVolume Dpt(14, 13)
|
||||||
|
#define DPT_Value_Compressibility Dpt(14, 14)
|
||||||
|
#define DPT_Value_Conductance Dpt(14, 15)
|
||||||
|
#define DPT_Value_Electrical_Conductivity Dpt(14, 16)
|
||||||
|
#define DPT_Value_Density Dpt(14, 17)
|
||||||
|
#define DPT_Value_Electric_Charge Dpt(14, 18)
|
||||||
|
#define DPT_Value_Electric_Current Dpt(14, 19)
|
||||||
|
#define DPT_Value_Electric_CurrentDensity Dpt(14, 20)
|
||||||
|
#define DPT_Value_Electric_DipoleMoment Dpt(14, 21)
|
||||||
|
#define DPT_Value_Electric_Displacement Dpt(14, 22)
|
||||||
|
#define DPT_Value_Electric_FieldStrength Dpt(14, 23)
|
||||||
|
#define DPT_Value_Electric_Flux Dpt(14, 24)
|
||||||
|
#define DPT_Value_Electric_FluxDensity Dpt(14, 25)
|
||||||
|
#define DPT_Value_Electric_Polarization Dpt(14, 26)
|
||||||
|
#define DPT_Value_Electric_Potential Dpt(14, 27)
|
||||||
|
#define DPT_Value_Electric_PotentialDifference Dpt(14, 28)
|
||||||
|
#define DPT_Value_ElectromagneticMoment Dpt(14, 29)
|
||||||
|
#define DPT_Value_Electromotive_Force Dpt(14, 30)
|
||||||
|
#define DPT_Value_Energy Dpt(14, 31)
|
||||||
|
#define DPT_Value_Force Dpt(14, 32)
|
||||||
|
#define DPT_Value_Frequency Dpt(14, 33)
|
||||||
|
#define DPT_Value_Angular_Frequency Dpt(14, 34)
|
||||||
|
#define DPT_Value_Heat_Capacity Dpt(14, 35)
|
||||||
|
#define DPT_Value_Heat_FlowRate Dpt(14, 36)
|
||||||
|
#define DPT_Value_Heat_Quantity Dpt(14, 37)
|
||||||
|
#define DPT_Value_Impedance Dpt(14, 38)
|
||||||
|
#define DPT_Value_Length Dpt(14, 39)
|
||||||
|
#define DPT_Value_Light_Quantity Dpt(14, 40)
|
||||||
|
#define DPT_Value_Luminance Dpt(14, 41)
|
||||||
|
#define DPT_Value_Luminous_Flux Dpt(14, 42)
|
||||||
|
#define DPT_Value_Luminous_Intensity Dpt(14, 43)
|
||||||
|
#define DPT_Value_Magnetic_FieldStrength Dpt(14, 44)
|
||||||
|
#define DPT_Value_Magnetic_Flux Dpt(14, 45)
|
||||||
|
#define DPT_Value_Magnetic_FluxDensity Dpt(14, 46)
|
||||||
|
#define DPT_Value_Magnetic_Moment Dpt(14, 47)
|
||||||
|
#define DPT_Value_Magnetic_Polarization Dpt(14, 48)
|
||||||
|
#define DPT_Value_Magnetization Dpt(14, 49)
|
||||||
|
#define DPT_Value_MagnetomotiveForce Dpt(14, 50)
|
||||||
|
#define DPT_Value_Mass Dpt(14, 51)
|
||||||
|
#define DPT_Value_MassFlux Dpt(14, 52)
|
||||||
|
#define DPT_Value_Momentum Dpt(14, 53)
|
||||||
|
#define DPT_Value_Phase_AngleRad Dpt(14, 54)
|
||||||
|
#define DPT_Value_Phase_AngleDeg Dpt(14, 55)
|
||||||
|
#define DPT_Value_Power Dpt(14, 56)
|
||||||
|
#define DPT_Value_Power_Factor Dpt(14, 57)
|
||||||
|
#define DPT_Value_Pressure Dpt(14, 58)
|
||||||
|
#define DPT_Value_Reactance Dpt(14, 59)
|
||||||
|
#define DPT_Value_Resistance Dpt(14, 60)
|
||||||
|
#define DPT_Value_Resistivity Dpt(14, 61)
|
||||||
|
#define DPT_Value_SelfInductance Dpt(14, 62)
|
||||||
|
#define DPT_Value_SolidAngle Dpt(14, 63)
|
||||||
|
#define DPT_Value_Sound_Intensity Dpt(14, 64)
|
||||||
|
#define DPT_Value_Speed Dpt(14, 65)
|
||||||
|
#define DPT_Value_Stress Dpt(14, 66)
|
||||||
|
#define DPT_Value_Surface_Tension Dpt(14, 67)
|
||||||
|
#define DPT_Value_Common_Temperature Dpt(14, 68)
|
||||||
|
#define DPT_Value_Absolute_Temperature Dpt(14, 69)
|
||||||
|
#define DPT_Value_TemperatureDifference Dpt(14, 70)
|
||||||
|
#define DPT_Value_Thermal_Capacity Dpt(14, 71)
|
||||||
|
#define DPT_Value_Thermal_Conductivity Dpt(14, 72)
|
||||||
|
#define DPT_Value_ThermoelectricPower Dpt(14, 73)
|
||||||
|
#define DPT_Value_Time Dpt(14, 74)
|
||||||
|
#define DPT_Value_Torque Dpt(14, 75)
|
||||||
|
#define DPT_Value_Volume Dpt(14, 76)
|
||||||
|
#define DPT_Value_Volume_Flux Dpt(14, 77)
|
||||||
|
#define DPT_Value_Weight Dpt(14, 78)
|
||||||
|
#define DPT_Value_Work Dpt(14, 79)
|
||||||
|
#define DPT_Value_ApparentPower Dpt(14, 80)
|
||||||
|
#define DPT_Access_Data Dpt(15, 0)
|
||||||
|
#define DPT_String_ASCII Dpt(16, 0)
|
||||||
|
#define DPT_String_8859_1 Dpt(16, 1)
|
||||||
|
#define DPT_SceneNumber Dpt(17, 1)
|
||||||
|
#define DPT_SceneControl Dpt(18, 1)
|
||||||
|
#define DPT_DateTime Dpt(19, 1)
|
||||||
|
#define DPT_SCLOMode Dpt(20, 1)
|
||||||
|
#define DPT_BuildingMode Dpt(20, 2)
|
||||||
|
#define DPT_OccMode Dpt(20, 3)
|
||||||
|
#define DPT_Priority Dpt(20, 4)
|
||||||
|
#define DPT_LightApplicationMode Dpt(20, 5)
|
||||||
|
#define DPT_ApplicationArea Dpt(20, 6)
|
||||||
|
#define DPT_AlarmClassType Dpt(20, 7)
|
||||||
|
#define DPT_PSUMode Dpt(20, 8)
|
||||||
|
#define DPT_ErrorClass_System Dpt(20, 11)
|
||||||
|
#define DPT_ErrorClass_HVAC Dpt(20, 12)
|
||||||
|
#define DPT_Time_Delay Dpt(20, 13)
|
||||||
|
#define DPT_Beaufort_Wind_Force_Scale Dpt(20, 14)
|
||||||
|
#define DPT_SensorSelect Dpt(20, 17)
|
||||||
|
#define DPT_ActuatorConnectType Dpt(20, 20)
|
||||||
|
#define DPT_FuelType Dpt(20, 100)
|
||||||
|
#define DPT_BurnerType Dpt(20, 101)
|
||||||
|
#define DPT_HVACMode Dpt(20, 102)
|
||||||
|
#define DPT_DHWMode Dpt(20, 103)
|
||||||
|
#define DPT_LoadPriority Dpt(20, 104)
|
||||||
|
#define DPT_HVACContrMode Dpt(20, 105)
|
||||||
|
#define DPT_HVACEmergMode Dpt(20, 106)
|
||||||
|
#define DPT_ChangeoverMode Dpt(20, 107)
|
||||||
|
#define DPT_ValveMode Dpt(20, 108)
|
||||||
|
#define DPT_DamperMode Dpt(20, 109)
|
||||||
|
#define DPT_HeaterMode Dpt(20, 110)
|
||||||
|
#define DPT_FanMode Dpt(20, 111)
|
||||||
|
#define DPT_MasterSlaveMode Dpt(20, 112)
|
||||||
|
#define DPT_StatusRoomSetp Dpt(20, 113)
|
||||||
|
#define DPT_ADAType Dpt(20, 120)
|
||||||
|
#define DPT_BackupMode Dpt(20, 121)
|
||||||
|
#define DPT_StartSynchronization Dpt(20, 122)
|
||||||
|
#define DPT_Behaviour_Lock_Unlock Dpt(20, 600)
|
||||||
|
#define DPT_Behaviour_Bus_Power_Up_Down Dpt(20, 601)
|
||||||
|
#define DPT_DALI_Fade_Time Dpt(20, 602)
|
||||||
|
#define DPT_BlinkingMode Dpt(20, 603)
|
||||||
|
#define DPT_LightControlMode Dpt(20, 604)
|
||||||
|
#define DPT_SwitchPBModel Dpt(20, 605)
|
||||||
|
#define DPT_PBAction Dpt(20, 606)
|
||||||
|
#define DPT_DimmPBModel Dpt(20, 607)
|
||||||
|
#define DPT_SwitchOnMode Dpt(20, 608)
|
||||||
|
#define DPT_LoadTypeSet Dpt(20, 609)
|
||||||
|
#define DPT_LoadTypeDetected Dpt(20, 610)
|
||||||
|
#define DPT_SABExceptBehaviour Dpt(20, 801)
|
||||||
|
#define DPT_SABBehaviour_Lock_Unlock Dpt(20, 802)
|
||||||
|
#define DPT_SSSBMode Dpt(20, 803)
|
||||||
|
#define DPT_BlindsControlMode Dpt(20, 804)
|
||||||
|
#define DPT_CommMode Dpt(20, 1000)
|
||||||
|
#define DPT_AddInfoTypes Dpt(20, 1001)
|
||||||
|
#define DPT_RF_ModeSelect Dpt(20, 1002)
|
||||||
|
#define DPT_RF_FilterSelect Dpt(20, 1003)
|
||||||
|
#define DPT_StatusGen Dpt(21, 1)
|
||||||
|
#define DPT_Device_Control Dpt(21, 2)
|
||||||
|
#define DPT_ForceSign Dpt(21, 100)
|
||||||
|
#define DPT_ForceSignCool Dpt(21, 101)
|
||||||
|
#define DPT_StatusRHC Dpt(21, 102)
|
||||||
|
#define DPT_StatusSDHWC Dpt(21, 103)
|
||||||
|
#define DPT_FuelTypeSet Dpt(21, 104)
|
||||||
|
#define DPT_StatusRCC Dpt(21, 105)
|
||||||
|
#define DPT_StatusAHU Dpt(21, 106)
|
||||||
|
#define DPT_LightActuatorErrorInfo Dpt(21, 601)
|
||||||
|
#define DPT_RF_ModeInfo Dpt(21, 1000)
|
||||||
|
#define DPT_RF_FilterInfo Dpt(21, 1001)
|
||||||
|
#define DPT_Channel_Activation_8 Dpt(21, 1010)
|
||||||
|
#define DPT_StatusDHWC Dpt(22, 100)
|
||||||
|
#define DPT_StatusRHCC Dpt(22, 101)
|
||||||
|
#define DPT_Media Dpt(22, 1000)
|
||||||
|
#define DPT_Channel_Activation_16 Dpt(22, 1010)
|
||||||
|
#define DPT_OnOff_Action Dpt(23, 1)
|
||||||
|
#define DPT_Alarm_Reaction Dpt(23, 2)
|
||||||
|
#define DPT_UpDown_Action Dpt(23, 3)
|
||||||
|
#define DPT_HVAC_PB_Action Dpt(23, 102)
|
||||||
|
#define DPT_VarString_8859_1 Dpt(24, 1)
|
||||||
|
#define DPT_DoubleNibble Dpt(25, 1000)
|
||||||
|
#define DPT_SceneInfo Dpt(26, 1)
|
||||||
|
#define DPT_CombinedInfoOnOff Dpt(27, 1)
|
||||||
|
#define DPT_UTF_8 Dpt(28, 1)
|
||||||
|
#define DPT_ActiveEnergy_V64 Dpt(29, 10)
|
||||||
|
#define DPT_ApparantEnergy_V64 Dpt(29, 11)
|
||||||
|
#define DPT_ReactiveEnergy_V64 Dpt(29, 12)
|
||||||
|
#define DPT_Channel_Activation_24 Dpt(30, 1010)
|
||||||
|
#define DPT_PB_Action_HVAC_Extended Dpt(31, 101)
|
||||||
|
#define DPT_Heat_Cool_Z Dpt(200, 100)
|
||||||
|
#define DPT_BinaryValue_Z Dpt(200, 101)
|
||||||
|
#define DPT_HVACMode_Z Dpt(201, 100)
|
||||||
|
#define DPT_DHWMode_Z Dpt(201, 102)
|
||||||
|
#define DPT_HVACContrMode_Z Dpt(201, 104)
|
||||||
|
#define DPT_EnablH_Cstage_Z Dpt(201, 105)
|
||||||
|
#define DPT_BuildingMode_Z Dpt(201, 107)
|
||||||
|
#define DPT_OccMode_Z Dpt(201, 108)
|
||||||
|
#define DPT_HVACEmergMode_Z Dpt(201, 109)
|
||||||
|
#define DPT_RelValue_Z Dpt(202, 1)
|
||||||
|
#define DPT_UCountValue8_Z Dpt(202, 2)
|
||||||
|
#define DPT_TimePeriodMsec_Z Dpt(203, 2)
|
||||||
|
#define DPT_TimePeriod10Msec_Z Dpt(203, 3)
|
||||||
|
#define DPT_TimePeriod100Msec_Z Dpt(203, 4)
|
||||||
|
#define DPT_TimePeriodSec_Z Dpt(203, 5)
|
||||||
|
#define DPT_TimePeriodMin_Z Dpt(203, 6)
|
||||||
|
#define DPT_TimePeriodHrs_Z Dpt(203, 7)
|
||||||
|
#define DPT_UFlowRateLiter_per_h_Z Dpt(203, 11)
|
||||||
|
#define DPT_UCountValue16_Z Dpt(203, 12)
|
||||||
|
#define DPT_UElCurrent_Z Dpt(203, 13)
|
||||||
|
#define DPT_PowerKW_Z Dpt(203, 14)
|
||||||
|
#define DPT_AtmPressureAbs_Z Dpt(203, 15)
|
||||||
|
#define DPT_PercentU16_Z Dpt(203, 17)
|
||||||
|
#define DPT_HVACAirQual_Z Dpt(203, 100)
|
||||||
|
#define DPT_WindSpeed_Z Dpt(203, 101)
|
||||||
|
#define DPT_SunIntensity_Z Dpt(203, 102)
|
||||||
|
#define DPT_HVACAirFlowAbs_Z Dpt(203, 104)
|
||||||
|
#define DPT_RelSignedValue_Z Dpt(204, 1)
|
||||||
|
#define DPT_DeltaTimeMsec_Z Dpt(205, 2)
|
||||||
|
#define DPT_DeltaTime10Msec_Z Dpt(205, 3)
|
||||||
|
#define DPT_DeltaTime100Msec_Z Dpt(205, 4)
|
||||||
|
#define DPT_DeltaTimeSec_Z Dpt(205, 5)
|
||||||
|
#define DPT_DeltaTimeMin_Z Dpt(205, 6)
|
||||||
|
#define DPT_DeltaTimeHrs_Z Dpt(205, 7)
|
||||||
|
#define DPT_Percent_V16_Z Dpt(205, 17)
|
||||||
|
#define DPT_TempHVACAbs_Z Dpt(205, 100)
|
||||||
|
#define DPT_TempHVACRel_Z Dpt(205, 101)
|
||||||
|
#define DPT_HVACAirFlowRel_Z Dpt(205, 102)
|
||||||
|
#define DPT_HVACModeNext Dpt(206, 100)
|
||||||
|
#define DPT_DHWModeNext Dpt(206, 102)
|
||||||
|
#define DPT_OccModeNext Dpt(206, 104)
|
||||||
|
#define DPT_BuildingModeNext Dpt(206, 105)
|
||||||
|
#define DPT_StatusBUC Dpt(207, 100)
|
||||||
|
#define DPT_LockSign Dpt(207, 101)
|
||||||
|
#define DPT_ValueDemBOC Dpt(207, 102)
|
||||||
|
#define DPT_ActPosDemAbs Dpt(207, 104)
|
||||||
|
#define DPT_StatusAct Dpt(207, 105)
|
||||||
|
#define DPT_StatusLightingActuator Dpt(207, 600)
|
||||||
|
#define DPT_StatusHPM Dpt(209, 100)
|
||||||
|
#define DPT_TempRoomDemAbs Dpt(209, 101)
|
||||||
|
#define DPT_StatusCPM Dpt(209, 102)
|
||||||
|
#define DPT_StatusWTC Dpt(209, 103)
|
||||||
|
#define DPT_TempFlowWaterDemAbs Dpt(210, 100)
|
||||||
|
#define DPT_EnergyDemWater Dpt(211, 100)
|
||||||
|
#define DPT_TempRoomSetpSetShift_3 Dpt(212, 100)
|
||||||
|
#define DPT_TempRoomSetpSet_3 Dpt(212, 101)
|
||||||
|
#define DPT_TempRoomSetpSet_4 Dpt(213, 100)
|
||||||
|
#define DPT_TempDHWSetpSet_4 Dpt(213, 101)
|
||||||
|
#define DPT_TempRoomSetpSetShift_4 Dpt(213, 102)
|
||||||
|
#define DPT_PowerFlowWaterDemHPM Dpt(214, 100)
|
||||||
|
#define DPT_PowerFlowWaterDemCPM Dpt(214, 101)
|
||||||
|
#define DPT_StatusBOC Dpt(215, 100)
|
||||||
|
#define DPT_StatusCC Dpt(215, 101)
|
||||||
|
#define DPT_SpecHeatProd Dpt(216, 100)
|
||||||
|
#define DPT_Version Dpt(217, 1)
|
||||||
|
#define DPT_VolumeLiter_Z Dpt(218, 1)
|
||||||
|
#define DPT_FlowRate_m3_per_h_Z Dpt(218, 2)
|
||||||
|
#define DPT_AlarmInfo Dpt(219, 1)
|
||||||
|
#define DPT_TempHVACAbsNext Dpt(220, 100)
|
||||||
|
#define DPT_SerNum Dpt(221, 1)
|
||||||
|
#define DPT_TempRoomSetpSetF16_3 Dpt(222, 100)
|
||||||
|
#define DPT_TempRoomSetpSetShiftF16_3 Dpt(222, 101)
|
||||||
|
#define DPT_EnergyDemAir Dpt(223, 100)
|
||||||
|
#define DPT_TempSupplyAirSetpSet Dpt(224, 100)
|
||||||
|
#define DPT_ScalingSpeed Dpt(225, 1)
|
||||||
|
#define DPT_Scaling_Step_Time Dpt(225, 2)
|
||||||
|
#define DPT_TariffNext Dpt(225, 3)
|
||||||
|
#define DPT_MeteringValue Dpt(229, 1)
|
||||||
|
#define DPT_MBus_Address Dpt(230, 1000)
|
||||||
|
#define DPT_Locale_ASCII Dpt(231, 1)
|
||||||
|
#define DPT_Colour_RGB Dpt(232, 600)
|
||||||
|
#define DPT_LanguageCodeAlpha2_ASCII Dpt(234, 1)
|
||||||
|
#define DPT_RegionCodeAlpha2_ASCII Dpt(234, 2)
|
||||||
|
#define DPT_Tariff_ActiveEnergy Dpt(235, 1)
|
||||||
|
#define DPT_Prioritised_Mode_Control Dpt(236, 1)
|
||||||
|
#define DPT_DALI_Control_Gear_Diagnostic Dpt(237, 600)
|
||||||
|
#define DPT_SceneConfig Dpt(238, 1)
|
||||||
|
#define DPT_DALI_Diagnostics Dpt(238, 600)
|
||||||
|
#define DPT_FlaggedScaling Dpt(239, 1)
|
||||||
|
#define DPT_CombinedPosition Dpt(240, 800)
|
||||||
|
#define DPT_StatusSAB Dpt(241, 800)
|
||||||
|
#define DPT_Colour_RGBW Dpt(251, 600)
|
||||||
|
|
||||||
|
class Dpt
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Dpt();
|
||||||
|
Dpt(short mainGroup, short subGroup, short index = 0);
|
||||||
|
unsigned short mainGroup;
|
||||||
|
unsigned short subGroup;
|
||||||
|
unsigned short index;
|
||||||
|
bool operator==(const Dpt& other) const;
|
||||||
|
bool operator!=(const Dpt& other) const;
|
||||||
|
};
|
||||||
2008
components/knx/src/knx/dptconvert.cpp
Normal file
2008
components/knx/src/knx/dptconvert.cpp
Normal file
File diff suppressed because it is too large
Load Diff
149
components/knx/src/knx/dptconvert.h
Normal file
149
components/knx/src/knx/dptconvert.h
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
KNX client library - internals
|
||||||
|
Copyright (C) 2005-2011 Martin Koegler <mkoegler@auto.tuwien.ac.at>
|
||||||
|
Copyright (C) 2014 Patrik Pfaffenbauer <patrik.pfaffenbauer@p3.co.at>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
In addition to the permissions in the GNU General Public License,
|
||||||
|
you may link the compiled version of this file into combinations
|
||||||
|
with other programs, and distribute those combinations without any
|
||||||
|
restriction coming from the use of this file. (The General Public
|
||||||
|
License restrictions do apply in other respects; for example, they
|
||||||
|
cover modification of the file, and distribution when not linked into
|
||||||
|
a combine executable.)
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "dpt.h"
|
||||||
|
#include "knx_value.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the KNX Payload given by the specific DPT and puts the value in the KNXValue struc
|
||||||
|
*/
|
||||||
|
bool KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the KNXValue struct to the KNX Payload as the specific DPT
|
||||||
|
*/
|
||||||
|
bool KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
|
||||||
|
//KNX to internal
|
||||||
|
bool busValueToBinary(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToBinaryControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToStepControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToCharacter(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToUnsigned8(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToSigned8(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToStatusAndMode(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToUnsigned16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToTimePeriod(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToSigned16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToTimeDelta(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToFloat16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToTime(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToDate(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToUnsigned32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToSigned32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToLongTimePeriod(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToFloat32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToAccess(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToString(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToScene(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToSceneControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToSceneInfo(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToSceneConfig(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToDateTime(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToUnicode(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToSigned64(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToAlarmInfo(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToSerialNumber(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToVersion(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToTariff(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToLocale(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToRGB(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToRGBW(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToFlaggedScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
bool busValueToActiveEnergy(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
|
||||||
|
|
||||||
|
//Internal to KNX
|
||||||
|
bool valueToBusValueBinary(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueBinaryControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueStepControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueCharacter(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueUnsigned8(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueSigned8(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueStatusAndMode(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueUnsigned16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueTimePeriod(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueSigned16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueTimeDelta(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueFloat16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueTime(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueDate(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueUnsigned32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueSigned32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueLongTimePeriod(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueFloat32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueAccess(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueString(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueScene(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueSceneControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueSceneInfo(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueSceneConfig(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueDateTime(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueUnicode(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueSigned64(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueAlarmInfo(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueSerialNumber(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueVersion(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueTariff(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueLocale(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueRGB(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueRGBW(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueFlaggedScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
bool valueToBusValueActiveEnergy(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
|
||||||
|
|
||||||
|
//Payload manipulation
|
||||||
|
bool bitFromPayload(const uint8_t* payload, int index);
|
||||||
|
uint8_t unsigned8FromPayload(const uint8_t* payload, int index);
|
||||||
|
int8_t signed8FromPayload(const uint8_t* payload, int index);
|
||||||
|
uint16_t unsigned16FromPayload(const uint8_t* payload, int index);
|
||||||
|
int16_t signed16FromPayload(const uint8_t* payload, int index);
|
||||||
|
uint32_t unsigned32FromPayload(const uint8_t* payload, int index);
|
||||||
|
int32_t signed32FromPayload(const uint8_t* payload, int index);
|
||||||
|
uint64_t unsigned64FromPayload(const uint8_t* payload, int index);
|
||||||
|
double float16FromPayload(const uint8_t* payload, int index);
|
||||||
|
float float32FromPayload(const uint8_t* payload, int index);
|
||||||
|
double float64FromPayload(const uint8_t* payload, int index);
|
||||||
|
int64_t signed64FromPayload(const uint8_t* payload, int index);
|
||||||
|
uint8_t bcdFromPayload(const uint8_t* payload, int index);
|
||||||
|
|
||||||
|
void bitToPayload(uint8_t* payload, size_t payload_length, int index, bool value);
|
||||||
|
void unsigned8ToPayload(uint8_t* payload, size_t payload_length, int index, uint8_t value, uint8_t mask); //mask 0xFF
|
||||||
|
void signed8ToPayload(uint8_t* payload, size_t payload_length, int index, int8_t value, uint8_t mask); //mask 0xFF
|
||||||
|
void unsigned16ToPayload(uint8_t* payload, size_t payload_length, int index, uint16_t value, uint16_t mask); //mask 0xFFFF
|
||||||
|
void signed16ToPayload(uint8_t* payload, size_t payload_length, int index, int16_t value, uint16_t mask); //mask 0xFFFF
|
||||||
|
void unsigned32ToPayload(uint8_t* payload, size_t payload_length, int index, uint32_t value, uint32_t mask); //mask = 0xFFFFFFFF
|
||||||
|
void signed32ToPayload(uint8_t* payload, size_t payload_length, int index, int32_t value, uint32_t mask); //mask = 0xFFFFFFFF
|
||||||
|
void float16ToPayload(uint8_t* payload, size_t payload_length, int index, double value, uint16_t mask); //mask = 0xFFFF
|
||||||
|
void float32ToPayload(uint8_t* payload, size_t payload_length, int index, double value, uint32_t mask); //mask = 0xFFFFFFFF
|
||||||
|
void signed64ToPayload(uint8_t* payload, size_t payload_length, int index, int64_t value, uint64_t mask); //mask = UINT64_C(0xFFFFFFFFFFFFFFFF)
|
||||||
|
void bcdToPayload(uint8_t* payload, size_t payload_length, int index, uint8_t value);
|
||||||
53
components/knx/src/knx/function_property.h
Normal file
53
components/knx/src/knx/function_property.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "property.h"
|
||||||
|
|
||||||
|
class InterfaceObject;
|
||||||
|
|
||||||
|
template <class T> class FunctionProperty : public Property
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FunctionProperty(T* io, PropertyID id,
|
||||||
|
void (*commandCallback)(T*, uint8_t*, uint8_t, uint8_t*, uint8_t&),
|
||||||
|
void (*stateCallback)(T*, uint8_t*, uint8_t, uint8_t*, uint8_t&))
|
||||||
|
: Property(id, false, PDT_FUNCTION, 1, ReadLv0 | WriteLv0), _interfaceObject(io), _commandCallback(commandCallback), _stateCallback(stateCallback)
|
||||||
|
/* max_elements is set to 1, read and write level any value so we use Lv0, see 3.3.7 Application Layer p.68 */
|
||||||
|
{}
|
||||||
|
|
||||||
|
uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const override
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t write(uint16_t start, uint8_t count, const uint8_t* data) override
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void command(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) override
|
||||||
|
{
|
||||||
|
if (length == 0 || _commandCallback == nullptr )
|
||||||
|
{
|
||||||
|
resultLength = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_commandCallback(_interfaceObject, data, length, resultData, resultLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
void state(uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) override
|
||||||
|
{
|
||||||
|
if (length == 0 || _stateCallback == nullptr )
|
||||||
|
{
|
||||||
|
resultLength = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_stateCallback(_interfaceObject, data, length, resultData, resultLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T* _interfaceObject = nullptr;
|
||||||
|
void (*_commandCallback)(T*, uint8_t*, uint8_t, uint8_t*, uint8_t&) = nullptr;
|
||||||
|
void (*_stateCallback)(T*, uint8_t*, uint8_t, uint8_t*, uint8_t&) = nullptr;
|
||||||
|
};
|
||||||
356
components/knx/src/knx/group_object.cpp
Normal file
356
components/knx/src/knx/group_object.cpp
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
#include "group_object.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "datapoint_types.h"
|
||||||
|
#include "group_object_table_object.h"
|
||||||
|
|
||||||
|
#ifdef SMALL_GROUPOBJECT
|
||||||
|
GroupObjectUpdatedHandler GroupObject::_updateHandlerStatic = 0;
|
||||||
|
#endif
|
||||||
|
GroupObjectTableObject* GroupObject::_table = 0;
|
||||||
|
|
||||||
|
GroupObject::GroupObject()
|
||||||
|
{
|
||||||
|
_data = 0;
|
||||||
|
_uninitialized = true;
|
||||||
|
_commFlag = Uninitialized;
|
||||||
|
_dataLength = 0;
|
||||||
|
#ifndef SMALL_GROUPOBJECT
|
||||||
|
_updateHandler = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupObject::~GroupObject()
|
||||||
|
{
|
||||||
|
if (_data)
|
||||||
|
delete[] _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GroupObject::responseUpdateEnable()
|
||||||
|
{
|
||||||
|
if (!_table)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return bitRead(ntohs(_table->_tableData[_asap]), 15) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GroupObject::transmitEnable()
|
||||||
|
{
|
||||||
|
if (!_table)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return bitRead(ntohs(_table->_tableData[_asap]), 14) > 0 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GroupObject::valueReadOnInit()
|
||||||
|
{
|
||||||
|
if (!_table)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return bitRead(ntohs(_table->_tableData[_asap]), 13) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GroupObject::writeEnable()
|
||||||
|
{
|
||||||
|
if (!_table)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return bitRead(ntohs(_table->_tableData[_asap]), 12) > 0 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GroupObject::readEnable()
|
||||||
|
{
|
||||||
|
if (!_table)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// we forbid reading of new (uninitialized) go
|
||||||
|
if (_uninitialized)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return bitRead(ntohs(_table->_tableData[_asap]), 11) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GroupObject::communicationEnable()
|
||||||
|
{
|
||||||
|
if (!_table)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return bitRead(ntohs(_table->_tableData[_asap]), 10) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Priority GroupObject::priority()
|
||||||
|
{
|
||||||
|
if (!_table)
|
||||||
|
return LowPriority;
|
||||||
|
|
||||||
|
return (Priority)((ntohs(_table->_tableData[_asap]) >> 6) & (3 << 2)) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* GroupObject::valueRef()
|
||||||
|
{
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t GroupObject::asap()
|
||||||
|
{
|
||||||
|
return _asap;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GroupObject::goSize()
|
||||||
|
{
|
||||||
|
size_t size = sizeInTelegram();
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// see knxspec 3.5.1 p. 178
|
||||||
|
size_t GroupObject::asapValueSize(uint8_t code) const
|
||||||
|
{
|
||||||
|
if (code < 7)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (code < 8)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (code < 11 || (code > 20 && code < 255))
|
||||||
|
return code - 6;
|
||||||
|
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
case 11:
|
||||||
|
return 6;
|
||||||
|
|
||||||
|
case 12:
|
||||||
|
return 8;
|
||||||
|
|
||||||
|
case 13:
|
||||||
|
return 10;
|
||||||
|
|
||||||
|
case 14:
|
||||||
|
return 14;
|
||||||
|
|
||||||
|
case 15:
|
||||||
|
return 5;
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
return 7;
|
||||||
|
|
||||||
|
case 17:
|
||||||
|
return 9;
|
||||||
|
|
||||||
|
case 18:
|
||||||
|
return 11;
|
||||||
|
|
||||||
|
case 19:
|
||||||
|
return 12;
|
||||||
|
|
||||||
|
case 20:
|
||||||
|
return 13;
|
||||||
|
|
||||||
|
case 255:
|
||||||
|
return 252;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ComFlag GroupObject::commFlag()
|
||||||
|
{
|
||||||
|
return _commFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupObject::commFlag(ComFlag value)
|
||||||
|
{
|
||||||
|
_commFlag = value;
|
||||||
|
|
||||||
|
if (value == WriteRequest || value == Updated || value == Ok)
|
||||||
|
_uninitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GroupObject::initialized()
|
||||||
|
{
|
||||||
|
return !_uninitialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupObject::requestObjectRead()
|
||||||
|
{
|
||||||
|
commFlag(ReadRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupObject::objectWritten()
|
||||||
|
{
|
||||||
|
commFlag(WriteRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GroupObject::valueSize()
|
||||||
|
{
|
||||||
|
return _dataLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GroupObject::sizeInTelegram()
|
||||||
|
{
|
||||||
|
uint8_t code = lowByte(ntohs(_table->_tableData[_asap]));
|
||||||
|
return asapValueSize(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GroupObject::sizeInMemory() const
|
||||||
|
{
|
||||||
|
uint8_t code = lowByte(ntohs(_table->_tableData[_asap]));
|
||||||
|
size_t result = asapValueSize(code);
|
||||||
|
|
||||||
|
if (result == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (code == 14)
|
||||||
|
return 14 + 1;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SMALL_GROUPOBJECT
|
||||||
|
GroupObjectUpdatedHandler GroupObject::classCallback()
|
||||||
|
{
|
||||||
|
return _updateHandlerStatic;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupObject::classCallback(GroupObjectUpdatedHandler handler)
|
||||||
|
{
|
||||||
|
_updateHandlerStatic = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupObject::processClassCallback(GroupObject& ko)
|
||||||
|
{
|
||||||
|
if (_updateHandlerStatic != 0)
|
||||||
|
_updateHandlerStatic(ko);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
void GroupObject::callback(GroupObjectUpdatedHandler handler)
|
||||||
|
{
|
||||||
|
_updateHandler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GroupObjectUpdatedHandler GroupObject::callback()
|
||||||
|
{
|
||||||
|
return _updateHandler;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool GroupObject::value(const KNXValue& value, const Dpt& type)
|
||||||
|
{
|
||||||
|
if (valueNoSend(value, type))
|
||||||
|
{
|
||||||
|
// write on successful conversion/setting value only
|
||||||
|
objectWritten();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
KNXValue GroupObject::value(const Dpt& type)
|
||||||
|
{
|
||||||
|
KNXValue value = "";
|
||||||
|
KNX_Decode_Value(_data, _dataLength, type, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GroupObject::tryValue(KNXValue& value, const Dpt& type)
|
||||||
|
{
|
||||||
|
return KNX_Decode_Value(_data, _dataLength, type, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef SMALL_GROUPOBJECT
|
||||||
|
void GroupObject::dataPointType(Dpt value)
|
||||||
|
{
|
||||||
|
_datapointType = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Dpt GroupObject::dataPointType()
|
||||||
|
{
|
||||||
|
return _datapointType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GroupObject::tryValue(KNXValue& value)
|
||||||
|
{
|
||||||
|
return tryValue(value, _datapointType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GroupObject::value(const KNXValue& value)
|
||||||
|
{
|
||||||
|
return this->value(value, _datapointType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
KNXValue GroupObject::value()
|
||||||
|
{
|
||||||
|
return value(_datapointType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GroupObject::valueNoSend(const KNXValue& value)
|
||||||
|
{
|
||||||
|
return valueNoSend(value, _datapointType);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool GroupObject::valueNoSend(const KNXValue& value, const Dpt& type)
|
||||||
|
{
|
||||||
|
const bool encodingDone = KNX_Encode_Value(value, _data, _dataLength, type);
|
||||||
|
|
||||||
|
// initialize on succesful conversion only
|
||||||
|
if (encodingDone && _uninitialized)
|
||||||
|
commFlag(Ok);
|
||||||
|
|
||||||
|
return encodingDone;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GroupObject::valueNoSendCompare(const KNXValue& value, const Dpt& type)
|
||||||
|
{
|
||||||
|
if (_uninitialized)
|
||||||
|
{
|
||||||
|
// always set first value
|
||||||
|
return valueNoSend(value, type);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// convert new value to given DPT
|
||||||
|
uint8_t newData[_dataLength];
|
||||||
|
memset(newData, 0, _dataLength);
|
||||||
|
const bool encodingDone = KNX_Encode_Value(value, newData, _dataLength, type);
|
||||||
|
if (!encodingDone)
|
||||||
|
{
|
||||||
|
// value conversion to DPT failed
|
||||||
|
// do NOT update the value of the KO!
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for change in converted value / update value on change only
|
||||||
|
const bool dataChanged = memcmp(_data, newData, _dataLength);
|
||||||
|
|
||||||
|
if (dataChanged)
|
||||||
|
memcpy(_data, newData, _dataLength);
|
||||||
|
|
||||||
|
return dataChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GroupObject::valueCompare(const KNXValue& value, const Dpt& type)
|
||||||
|
{
|
||||||
|
if (valueNoSendCompare(value, type))
|
||||||
|
{
|
||||||
|
objectWritten();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
287
components/knx/src/knx/group_object.h
Normal file
287
components/knx/src/knx/group_object.h
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "knx_types.h"
|
||||||
|
#include "dptconvert.h"
|
||||||
|
|
||||||
|
class GroupObjectTableObject;
|
||||||
|
|
||||||
|
enum ComFlag : uint8_t
|
||||||
|
{
|
||||||
|
Updated = 0, //!< Group object was updated
|
||||||
|
ReadRequest = 1, //!< Read 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)
|
||||||
|
Ok = 4, //!< read or write request were send successfully
|
||||||
|
Error = 5, //!< there was an error on processing a request
|
||||||
|
Uninitialized = 6 //!< uninitialized Group Object, its value is not valid
|
||||||
|
};
|
||||||
|
|
||||||
|
class GroupObject;
|
||||||
|
|
||||||
|
#ifndef HAS_FUNCTIONAL
|
||||||
|
#if defined(__linux__) || defined(ARDUINO_ARCH_ESP32) || defined(ESP_PLATFORM) || defined(ARDUINO_ARCH_STM32) || defined (ARDUINO_ARCH_SAMD) || defined (ARDUINO_ARCH_RP2040) || defined(LIBRETINY)
|
||||||
|
#define HAS_FUNCTIONAL 1
|
||||||
|
#else
|
||||||
|
#define HAS_FUNCTIONAL 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAS_FUNCTIONAL
|
||||||
|
#include <functional>
|
||||||
|
typedef std::function<void(GroupObject&)> GroupObjectUpdatedHandler;
|
||||||
|
#else
|
||||||
|
typedef void (*GroupObjectUpdatedHandler)(GroupObject& go);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents a single group object. In german they are called "Kommunikationsobjekt" or "KO".
|
||||||
|
*/
|
||||||
|
class GroupObject
|
||||||
|
{
|
||||||
|
friend class GroupObjectTableObject;
|
||||||
|
GroupObject(const GroupObject& other) = delete;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* The constructor.
|
||||||
|
*/
|
||||||
|
GroupObject();
|
||||||
|
/**
|
||||||
|
* The destructor.
|
||||||
|
*/
|
||||||
|
virtual ~GroupObject();
|
||||||
|
// config flags from ETS
|
||||||
|
/**
|
||||||
|
* Check if the update flag (U) was set. (A-flag in german)
|
||||||
|
*/
|
||||||
|
bool responseUpdateEnable();
|
||||||
|
/**
|
||||||
|
* Check if the transmit flag (T) was set. (UE-flag in german)
|
||||||
|
*/
|
||||||
|
bool transmitEnable();
|
||||||
|
/**
|
||||||
|
* Check if the initialisation flag (I) was set.
|
||||||
|
*/
|
||||||
|
bool valueReadOnInit();
|
||||||
|
/**
|
||||||
|
* Check if the write flag (W) was set. (S-flag in german)
|
||||||
|
*/
|
||||||
|
bool writeEnable();
|
||||||
|
/**
|
||||||
|
* Check if the read flag (R) was set. (L-flag in german)
|
||||||
|
*/
|
||||||
|
bool readEnable();
|
||||||
|
/**
|
||||||
|
* Check if the communication flag (C) was set. (K-flag in german)
|
||||||
|
*/
|
||||||
|
bool communicationEnable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the priority of the group object.
|
||||||
|
*/
|
||||||
|
Priority priority();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current state of the group object. See ::ComFlag
|
||||||
|
*/
|
||||||
|
ComFlag commFlag();
|
||||||
|
/**
|
||||||
|
* Set the current state of the group object. Application code should only use this to set the state to ::Ok after
|
||||||
|
* reading a ::Updated to mark the changed group object as processed. This is optional.
|
||||||
|
*/
|
||||||
|
void commFlag(ComFlag value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the group object contains a valid value assigned from bus or from application program
|
||||||
|
*/
|
||||||
|
bool initialized();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request the read of a communication object. Calling this function triggers the
|
||||||
|
* sending of a read-group-value telegram, to read the value of the communication
|
||||||
|
* object from the bus.
|
||||||
|
*
|
||||||
|
* When the answer is received, the communication object's value will be updated.
|
||||||
|
*
|
||||||
|
* This sets the state of the group objecte to ::ReadRequest
|
||||||
|
*/
|
||||||
|
void requestObjectRead();
|
||||||
|
/**
|
||||||
|
* Mark a communication object as written. Calling this
|
||||||
|
* function triggers the sending of a write-group-value telegram.
|
||||||
|
*
|
||||||
|
* This sets the state of the group object to ::WriteRequest
|
||||||
|
*/
|
||||||
|
void objectWritten();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the size of the group object in Byte. For Group objects with size smaller than 1 byte (for example Dpt 1) this method
|
||||||
|
* will return 1.
|
||||||
|
*/
|
||||||
|
size_t valueSize();
|
||||||
|
/**
|
||||||
|
* returns the size of the group object in Byte as it is in a telegram. For Group objects with size smaller than 1 byte (for example Dpt 1) this method
|
||||||
|
* will return 0.
|
||||||
|
*/
|
||||||
|
size_t sizeInTelegram();
|
||||||
|
/**
|
||||||
|
* returns the size of the group object in the heap memory of the group object. The function returns the same value as goSize(),
|
||||||
|
* exept fot the 14 byte string type to reserve one byte of a \0 terminator character.
|
||||||
|
*/
|
||||||
|
size_t sizeInMemory() const;
|
||||||
|
/**
|
||||||
|
* returns the pointer to the value of the group object. This can be used if a datapoint type is not supported or if you want do
|
||||||
|
* your own conversion.
|
||||||
|
*/
|
||||||
|
uint8_t* valueRef();
|
||||||
|
/**
|
||||||
|
* returns the Application Service Access Point of the group object. In reality this is just the number of the group object.
|
||||||
|
* (in german "KO-Nr")
|
||||||
|
*/
|
||||||
|
uint16_t asap();
|
||||||
|
|
||||||
|
#ifndef SMALL_GROUPOBJECT
|
||||||
|
/**
|
||||||
|
* register a callback for this group object. The registered callback will be called if the group object was changed from the bus.
|
||||||
|
*/
|
||||||
|
void callback(GroupObjectUpdatedHandler handler);
|
||||||
|
/**
|
||||||
|
* returns the registered callback
|
||||||
|
*/
|
||||||
|
GroupObjectUpdatedHandler callback();
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* return the current value of the group object.
|
||||||
|
* @param type the datapoint type used for the conversion. If this doesn't fit to the group object the returned value is invalid.
|
||||||
|
*/
|
||||||
|
KNXValue value(const Dpt& type);
|
||||||
|
/**
|
||||||
|
* set the current value of the group object and changes the state of the group object to ::WriteRequest.
|
||||||
|
* @param value the value the group object is set to
|
||||||
|
* @param type the datapoint type used for the conversion.
|
||||||
|
*
|
||||||
|
* The parameters must fit the group object. Otherwise it will stay unchanged.
|
||||||
|
*
|
||||||
|
* @returns true if the value was converted successfully to the datapoint type and the group object was updated.
|
||||||
|
*/
|
||||||
|
bool value(const KNXValue& value, const Dpt& type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the value (after conversion to dpt) will differ from current value of the group object and changes the state of the group object to ::WriteRequest if different.
|
||||||
|
* Use this method only, when the value should not be sent if it was not changed, otherwise value(const KNXValue&, const Dpt&) will do the same (without overhead for comparing)
|
||||||
|
* @param value the value the group object is set to
|
||||||
|
* @param type the datapoint type used for the conversion.
|
||||||
|
*
|
||||||
|
* The parameters must fit the group object. Otherwise it will stay unchanged.
|
||||||
|
*
|
||||||
|
* @returns true if the value of the group object has changed, false if conversion results in same value as stored in group object or failed.
|
||||||
|
*/
|
||||||
|
bool valueCompare(const KNXValue& value, const Dpt& type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the current value of the group objectand show success.
|
||||||
|
* @param value the value the group object is set to
|
||||||
|
* @param type the datapoint type used for the conversion.
|
||||||
|
*
|
||||||
|
* The parameters must fit the group object. Otherwise it will stay unchanged.
|
||||||
|
*
|
||||||
|
* @returns true if value was converted successfully to the datapoint type and the group object was updated.
|
||||||
|
*/
|
||||||
|
bool valueNoSend(const KNXValue& value, const Dpt& type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the value (after conversion to dpt) will differ from current value of the group object and update if necessary.
|
||||||
|
* Use this method only, when the value change is relevant, otherwise valueNoSend(const KNXValue&, const Dpt&) will do the same (without overhead for comparing)
|
||||||
|
* @param value the value the group object is set to
|
||||||
|
* @param type the datapoint type used for the conversion.
|
||||||
|
*
|
||||||
|
* The parameters must fit the group object. Otherwise it will stay unchanged.
|
||||||
|
*
|
||||||
|
* @returns true if the value of the group object has changed, false if conversion results in same value as stored in group object or failed.
|
||||||
|
*/
|
||||||
|
bool valueNoSendCompare(const KNXValue& value, const Dpt& type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the current value of the group object.
|
||||||
|
* @param value the value the group object is set to
|
||||||
|
* @param type the datapoint type used for the conversion.
|
||||||
|
*
|
||||||
|
* The parameters must fit the group object. Otherwise it will stay unchanged.
|
||||||
|
*
|
||||||
|
* @returns true if the value of the group object was changed successfully.
|
||||||
|
*/
|
||||||
|
bool tryValue(KNXValue& value, const Dpt& type);
|
||||||
|
|
||||||
|
#ifndef SMALL_GROUPOBJECT
|
||||||
|
/**
|
||||||
|
* return the current value of the group object. The datapoint type must be set with dataPointType(). Otherwise the returned
|
||||||
|
* value is invalid.
|
||||||
|
*/
|
||||||
|
KNXValue value();
|
||||||
|
/**
|
||||||
|
* set the current value of the group object and changes the state of the group object to ::WriteRequest.
|
||||||
|
* @param value the value the group object is set to
|
||||||
|
*
|
||||||
|
* The parameters must fit the group object and dhe datapoint type must be set with dataPointType(). Otherwise it will stay unchanged.
|
||||||
|
*
|
||||||
|
* @returns true if the value was converted successfully to the datapoint type and the group object was updated.
|
||||||
|
*/
|
||||||
|
bool value(const KNXValue& value);
|
||||||
|
/**
|
||||||
|
* set the current value of the group object.
|
||||||
|
* @param value the value the group object is set to
|
||||||
|
*
|
||||||
|
* The parameters must fit the group object and the datapoint type must be set with dataPointType(). Otherwise it will stay unchanged.
|
||||||
|
*
|
||||||
|
* @returns true if the value was converted successfully to the datapoint type and the group object was updated.
|
||||||
|
*/
|
||||||
|
bool valueNoSend(const KNXValue& value);
|
||||||
|
/**
|
||||||
|
* set the current value of the group object.
|
||||||
|
* @param value the value the group object is set to
|
||||||
|
*
|
||||||
|
* The parameters must fit the group object and dhe datapoint type must be set with dataPointType(). Otherwise it will stay unchanged.
|
||||||
|
*
|
||||||
|
* @returns true if the value of the group object was changed successfully.
|
||||||
|
*/
|
||||||
|
bool tryValue(KNXValue& value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the currently configured datapoint type.
|
||||||
|
*/
|
||||||
|
Dpt dataPointType();
|
||||||
|
/**
|
||||||
|
* sets the datapoint type of the group object.
|
||||||
|
*/
|
||||||
|
void dataPointType(Dpt value);
|
||||||
|
#else
|
||||||
|
/**
|
||||||
|
* Alternative callback processing: register one global callback for all group object.
|
||||||
|
* The registered callback will be called if any group object was changed from the bus.
|
||||||
|
* The callback method has to dispatch to the correct handler for this group object.
|
||||||
|
*/
|
||||||
|
static GroupObjectUpdatedHandler classCallback();
|
||||||
|
static void classCallback(GroupObjectUpdatedHandler handler);
|
||||||
|
static void processClassCallback(GroupObject& ko);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
// class members
|
||||||
|
static GroupObjectTableObject* _table;
|
||||||
|
#ifdef SMALL_GROUPOBJECT
|
||||||
|
static GroupObjectUpdatedHandler _updateHandlerStatic;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t asapValueSize(uint8_t code) const;
|
||||||
|
size_t goSize();
|
||||||
|
uint16_t _asap = 0;
|
||||||
|
bool _uninitialized : 1;
|
||||||
|
ComFlag _commFlag : 7;
|
||||||
|
uint8_t* _data = 0;
|
||||||
|
uint8_t _dataLength = 0;
|
||||||
|
#ifndef SMALL_GROUPOBJECT
|
||||||
|
GroupObjectUpdatedHandler _updateHandler;
|
||||||
|
Dpt _datapointType;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
131
components/knx/src/knx/group_object_table_object.cpp
Normal file
131
components/knx/src/knx/group_object_table_object.cpp
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "group_object_table_object.h"
|
||||||
|
#include "group_object.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include "data_property.h"
|
||||||
|
|
||||||
|
GroupObjectTableObject::GroupObjectTableObject(Memory& memory)
|
||||||
|
: TableObject(memory)
|
||||||
|
{
|
||||||
|
Property* properties[]
|
||||||
|
{
|
||||||
|
new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_GRP_OBJ_TABLE)
|
||||||
|
};
|
||||||
|
TableObject::initializeProperties(sizeof(properties), properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupObjectTableObject::~GroupObjectTableObject()
|
||||||
|
{
|
||||||
|
freeGroupObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t GroupObjectTableObject::entryCount()
|
||||||
|
{
|
||||||
|
if (loadState() != LS_LOADED)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return ntohs(_tableData[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupObject& GroupObjectTableObject::get(uint16_t asap)
|
||||||
|
{
|
||||||
|
return _groupObjects[asap - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* GroupObjectTableObject::restore(const uint8_t* buffer)
|
||||||
|
{
|
||||||
|
buffer = TableObject::restore(buffer);
|
||||||
|
|
||||||
|
_tableData = (uint16_t*)data();
|
||||||
|
initGroupObjects();
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupObject& GroupObjectTableObject::nextUpdatedObject(bool& valid)
|
||||||
|
{
|
||||||
|
static uint16_t startIdx = 1;
|
||||||
|
|
||||||
|
uint16_t objCount = entryCount();
|
||||||
|
|
||||||
|
for (uint16_t asap = startIdx; asap <= objCount; asap++)
|
||||||
|
{
|
||||||
|
GroupObject& go = get(asap);
|
||||||
|
|
||||||
|
if (go.commFlag() == Updated)
|
||||||
|
{
|
||||||
|
go.commFlag(Ok);
|
||||||
|
startIdx = asap + 1;
|
||||||
|
valid = true;
|
||||||
|
return go;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
startIdx = 1;
|
||||||
|
valid = false;
|
||||||
|
return get(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupObjectTableObject::groupObjects(GroupObject* objs, uint16_t size)
|
||||||
|
{
|
||||||
|
freeGroupObjects();
|
||||||
|
_groupObjects = objs;
|
||||||
|
_groupObjectCount = size;
|
||||||
|
initGroupObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupObjectTableObject::beforeStateChange(LoadState& newState)
|
||||||
|
{
|
||||||
|
TableObject::beforeStateChange(newState);
|
||||||
|
|
||||||
|
if (newState != LS_LOADED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_tableData = (uint16_t*)data();
|
||||||
|
|
||||||
|
if (!initGroupObjects())
|
||||||
|
{
|
||||||
|
newState = LS_ERROR;
|
||||||
|
TableObject::errorCode(E_SOFTWARE_FAULT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GroupObjectTableObject::initGroupObjects()
|
||||||
|
{
|
||||||
|
if (!_tableData)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
freeGroupObjects();
|
||||||
|
|
||||||
|
uint16_t goCount = ntohs(_tableData[0]);
|
||||||
|
|
||||||
|
_groupObjects = new GroupObject[goCount];
|
||||||
|
_groupObjectCount = goCount;
|
||||||
|
|
||||||
|
for (uint16_t asap = 1; asap <= goCount; asap++)
|
||||||
|
{
|
||||||
|
GroupObject& go = _groupObjects[asap - 1];
|
||||||
|
go._asap = asap;
|
||||||
|
go._table = this;
|
||||||
|
|
||||||
|
go._dataLength = go.goSize();
|
||||||
|
size_t sizeInMemory = go.sizeInMemory();
|
||||||
|
go._data = new uint8_t[sizeInMemory];
|
||||||
|
memset(go._data, 0, sizeInMemory);
|
||||||
|
|
||||||
|
if (go.valueReadOnInit())
|
||||||
|
go.requestObjectRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupObjectTableObject::freeGroupObjects()
|
||||||
|
{
|
||||||
|
if (_groupObjects)
|
||||||
|
delete[] _groupObjects;
|
||||||
|
|
||||||
|
_groupObjectCount = 0;
|
||||||
|
_groupObjects = 0;
|
||||||
|
}
|
||||||
29
components/knx/src/knx/group_object_table_object.h
Normal file
29
components/knx/src/knx/group_object_table_object.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "table_object.h"
|
||||||
|
#include "group_object.h"
|
||||||
|
|
||||||
|
class GroupObjectTableObject : public TableObject
|
||||||
|
{
|
||||||
|
friend class GroupObject;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GroupObjectTableObject(Memory& memory);
|
||||||
|
virtual ~GroupObjectTableObject();
|
||||||
|
uint16_t entryCount();
|
||||||
|
GroupObject& get(uint16_t asap);
|
||||||
|
GroupObject& nextUpdatedObject(bool& valid);
|
||||||
|
void groupObjects(GroupObject* objs, uint16_t size);
|
||||||
|
|
||||||
|
const uint8_t* restore(const uint8_t* buffer) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void beforeStateChange(LoadState& newState) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void freeGroupObjects();
|
||||||
|
bool initGroupObjects();
|
||||||
|
uint16_t* _tableData = 0;
|
||||||
|
GroupObject* _groupObjects = 0;
|
||||||
|
uint16_t _groupObjectCount = 0;
|
||||||
|
};
|
||||||
232
components/knx/src/knx/interface_object.cpp
Normal file
232
components/knx/src/knx/interface_object.cpp
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "interface_object.h"
|
||||||
|
#include "data_property.h"
|
||||||
|
|
||||||
|
InterfaceObject::~InterfaceObject()
|
||||||
|
{
|
||||||
|
if (_properties != nullptr)
|
||||||
|
delete[] _properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterfaceObject::readPropertyDescription(uint8_t& propertyId, uint8_t& propertyIndex, bool& writeEnable, uint8_t& type, uint16_t& numberOfElements, uint8_t& access)
|
||||||
|
{
|
||||||
|
uint8_t count = _propertyCount;
|
||||||
|
|
||||||
|
numberOfElements = 0;
|
||||||
|
|
||||||
|
if (_properties == nullptr || count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Property* prop = nullptr;
|
||||||
|
|
||||||
|
// from KNX spec. 03.03.07 Application Layer (page 56) - 3.4.3.3 A_PropertyDescription_Read-service
|
||||||
|
// Summary: either propertyId OR propertyIndex, but not both at the same time
|
||||||
|
if (propertyId != 0)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
Property* p = _properties[i];
|
||||||
|
|
||||||
|
if (p->Id() != propertyId)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
prop = p;
|
||||||
|
propertyIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If propertyId is zero, propertyIndex shall be used.
|
||||||
|
// Response: propertyIndex of received A_PropertyDescription_Read
|
||||||
|
if (propertyIndex < count)
|
||||||
|
{
|
||||||
|
prop = _properties[propertyIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prop != nullptr)
|
||||||
|
{
|
||||||
|
propertyId = prop->Id();
|
||||||
|
writeEnable = prop->WriteEnable();
|
||||||
|
type = prop->Type();
|
||||||
|
numberOfElements = prop->MaxElements();
|
||||||
|
access = prop->Access();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterfaceObject::masterReset(EraseCode eraseCode, uint8_t channel)
|
||||||
|
{
|
||||||
|
// every interface object shall implement this
|
||||||
|
// However, for the time being we provide an empty default implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterfaceObject::readPropertyLength(PropertyID id, uint16_t& length)
|
||||||
|
{
|
||||||
|
uint8_t count = 1;
|
||||||
|
uint16_t propval = 0;
|
||||||
|
readProperty(id, 0, count, (uint8_t*)&propval);
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
length = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
length = ntohs(propval);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterfaceObject::readProperty(PropertyID id, uint16_t start, uint8_t& count, uint8_t* data)
|
||||||
|
{
|
||||||
|
Property* prop = property(id);
|
||||||
|
|
||||||
|
if (prop == nullptr)
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = prop->read(start, count, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterfaceObject::writeProperty(PropertyID id, uint16_t start, uint8_t* data, uint8_t& count)
|
||||||
|
{
|
||||||
|
Property* prop = property(id);
|
||||||
|
|
||||||
|
if (prop == nullptr)
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = prop->write(start, count, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t InterfaceObject::propertySize(PropertyID id)
|
||||||
|
{
|
||||||
|
Property* prop = property(id);
|
||||||
|
|
||||||
|
if (prop == nullptr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return prop->ElementSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterfaceObject::command(PropertyID id, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength)
|
||||||
|
{
|
||||||
|
Property* prop = property(id);
|
||||||
|
|
||||||
|
if (prop == nullptr)
|
||||||
|
{
|
||||||
|
resultLength = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
prop->command(data, length, resultData, resultLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterfaceObject::state(PropertyID id, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength)
|
||||||
|
{
|
||||||
|
Property* prop = property(id);
|
||||||
|
|
||||||
|
if (prop == nullptr)
|
||||||
|
{
|
||||||
|
resultLength = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
prop->state(data, length, resultData, resultLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterfaceObject::initializeProperties(size_t propertiesSize, Property** properties)
|
||||||
|
{
|
||||||
|
_propertyCount = propertiesSize / sizeof(Property*);
|
||||||
|
_properties = new Property*[_propertyCount];
|
||||||
|
memcpy(_properties, properties, propertiesSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Property* InterfaceObject::property(PropertyID id)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _propertyCount; i++)
|
||||||
|
if (_properties[i]->Id() == id)
|
||||||
|
return _properties[i];
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t* InterfaceObject::save(uint8_t* buffer)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _propertyCount; i++)
|
||||||
|
{
|
||||||
|
Property* prop = _properties[i];
|
||||||
|
|
||||||
|
if (!prop->WriteEnable())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
buffer = prop->save(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t* InterfaceObject::restore(const uint8_t* buffer)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _propertyCount; i++)
|
||||||
|
{
|
||||||
|
Property* prop = _properties[i];
|
||||||
|
|
||||||
|
if (!prop->WriteEnable())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
buffer = prop->restore(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t InterfaceObject::saveSize()
|
||||||
|
{
|
||||||
|
uint16_t size = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < _propertyCount; i++)
|
||||||
|
{
|
||||||
|
Property* prop = _properties[i];
|
||||||
|
|
||||||
|
if (!prop->WriteEnable())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
size += prop->saveSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Property* InterfaceObject::property(PropertyID id) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _propertyCount; i++)
|
||||||
|
if (_properties[i]->Id() == id)
|
||||||
|
return _properties[i];
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t* InterfaceObject::propertyData(PropertyID id)
|
||||||
|
{
|
||||||
|
DataProperty* prop = (DataProperty*)property(id);
|
||||||
|
return prop->data();
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* InterfaceObject::propertyData(PropertyID id, uint16_t elementIndex)
|
||||||
|
{
|
||||||
|
DataProperty* prop = (DataProperty*)property(id);
|
||||||
|
return prop->data(elementIndex);
|
||||||
|
}
|
||||||
210
components/knx/src/knx/interface_object.h
Normal file
210
components/knx/src/knx/interface_object.h
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "property.h"
|
||||||
|
#include "save_restore.h"
|
||||||
|
#include "knx_types.h"
|
||||||
|
#include "bits.h"
|
||||||
|
|
||||||
|
/** Enum for the type of an interface object. See Section 2.2 of knx:3/7/3 */
|
||||||
|
enum ObjectType
|
||||||
|
{
|
||||||
|
/** Device object. */
|
||||||
|
OT_DEVICE = 0,
|
||||||
|
|
||||||
|
/** Address table object. */
|
||||||
|
OT_ADDR_TABLE = 1,
|
||||||
|
|
||||||
|
/** Association table object. */
|
||||||
|
OT_ASSOC_TABLE = 2,
|
||||||
|
|
||||||
|
/** Application program object. */
|
||||||
|
OT_APPLICATION_PROG = 3,
|
||||||
|
|
||||||
|
/** Interface program object. */
|
||||||
|
OT_INTERFACE_PROG = 4,
|
||||||
|
|
||||||
|
/** KNX - Object Associationtable. */
|
||||||
|
OT_OJB_ASSOC_TABLE = 5,
|
||||||
|
|
||||||
|
/** Router Object */
|
||||||
|
OT_ROUTER = 6,
|
||||||
|
|
||||||
|
/** LTE Address Routing Table Object */
|
||||||
|
OT_LTE_ADDR_ROUTING_TABLE = 7,
|
||||||
|
|
||||||
|
/** cEMI Server Object */
|
||||||
|
OT_CEMI_SERVER = 8,
|
||||||
|
|
||||||
|
/** Group Object Table Object */
|
||||||
|
OT_GRP_OBJ_TABLE = 9,
|
||||||
|
|
||||||
|
/** Polling Master */
|
||||||
|
OT_POLLING_MASTER = 10,
|
||||||
|
|
||||||
|
/** KNXnet/IP Parameter Object */
|
||||||
|
OT_IP_PARAMETER = 11,
|
||||||
|
|
||||||
|
/** Reserved. Shall not be used. */
|
||||||
|
OT_RESERVED = 12,
|
||||||
|
|
||||||
|
/** File Server Object */
|
||||||
|
OT_FILE_SERVER = 13,
|
||||||
|
|
||||||
|
/** Security Interface Object */
|
||||||
|
OT_SECURITY = 17,
|
||||||
|
|
||||||
|
/** RF Medium Object */
|
||||||
|
OT_RF_MEDIUM = 19,
|
||||||
|
|
||||||
|
/** Dummy so this enum is 16bit */
|
||||||
|
OT_DUMMY = 0xFFFF
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents and interface object. See section 4 of @cite knx:3/4/1.
|
||||||
|
*/
|
||||||
|
class InterfaceObject : public SaveRestore
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Destructor
|
||||||
|
*/
|
||||||
|
virtual ~InterfaceObject();
|
||||||
|
/**
|
||||||
|
* Read length of a property of the interface object. See section 4.8.4.2 of @cite knx:3/4/1.
|
||||||
|
*
|
||||||
|
* @param id id of the property to read
|
||||||
|
*
|
||||||
|
* @param[out] length length of the requested property
|
||||||
|
*/
|
||||||
|
virtual void readPropertyLength(PropertyID id, uint16_t& length);
|
||||||
|
/**
|
||||||
|
* Read a property of the interface object. See section 4.8.4.2 of @cite knx:3/4/1.
|
||||||
|
*
|
||||||
|
* @param id id of the property to read
|
||||||
|
*
|
||||||
|
* @param start (for properties with multiple values) at which element should we start
|
||||||
|
*
|
||||||
|
* @param[in, out] count how many values should be read. If there is a problem (e.g. property does not exist)
|
||||||
|
* this value is set to 0.
|
||||||
|
*
|
||||||
|
* @param[out] data The requested data of the property.
|
||||||
|
*/
|
||||||
|
virtual void readProperty(PropertyID id, uint16_t start, uint8_t& count, uint8_t* data);
|
||||||
|
/**
|
||||||
|
* Write property of the interface object. If the interface object does not have the property this
|
||||||
|
* method does nothing. See section 4.8.4.4 of @cite knx:3/4/1.
|
||||||
|
*
|
||||||
|
* @param id id of the property to write
|
||||||
|
*
|
||||||
|
* @param start (for properties with multiple values) at which element should we start
|
||||||
|
*
|
||||||
|
* @param[in, out] count how many values should be written. If there is a problem (e.g. property does not exist)
|
||||||
|
* this value is set to 0.
|
||||||
|
*
|
||||||
|
* @param[in] data The data that should be written.
|
||||||
|
*/
|
||||||
|
virtual void writeProperty(PropertyID id, uint16_t start, uint8_t* data, uint8_t& count);
|
||||||
|
/**
|
||||||
|
* Gets the size of of property in bytes.
|
||||||
|
*
|
||||||
|
* @param id of the property to get the size of
|
||||||
|
*
|
||||||
|
* @returns the size in byte or 0 if the interface object does not have the property
|
||||||
|
*/
|
||||||
|
virtual uint8_t propertySize(PropertyID id);
|
||||||
|
/**
|
||||||
|
* Call command of a function property of the interface object. Property type must be PDT_FUNCTION
|
||||||
|
*
|
||||||
|
* @param id id of the property to call
|
||||||
|
*
|
||||||
|
* @param[in] length The size of the data buffer
|
||||||
|
*
|
||||||
|
* @param[in] data The argument data for the function
|
||||||
|
*
|
||||||
|
* @param[out] resultLength The size of the result data buffer
|
||||||
|
*
|
||||||
|
* @param[out] resultData The result data for the function
|
||||||
|
*/
|
||||||
|
virtual void command(PropertyID id, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength);
|
||||||
|
/**
|
||||||
|
* Get state of a function property of the interface object. Property type must be PDT_FUNCTION
|
||||||
|
*
|
||||||
|
* @param id id of the property to call
|
||||||
|
*
|
||||||
|
* @param[in] length The size of the data buffer
|
||||||
|
*
|
||||||
|
* @param[in] data The argument data for the function
|
||||||
|
*
|
||||||
|
* @param[out] resultLength The size of the result data buffer
|
||||||
|
*
|
||||||
|
* @param[out] resultData The result data for the function
|
||||||
|
*/
|
||||||
|
virtual void state(PropertyID id, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength);
|
||||||
|
/**
|
||||||
|
* Read the Description of a property of the interface object. The output parameters are only valid if nuberOfElements is not zero.
|
||||||
|
*
|
||||||
|
* @param[in,out] propertyId The id of the property of which to read the description of. If this parameter is not zero
|
||||||
|
* propertyIndex paramter is ignored as input and the corrrect index of the property is written to it. If this
|
||||||
|
* parameter is zero the ::PropertyID of the property specified by propertyIndex is written to it.
|
||||||
|
*
|
||||||
|
* @param[in,out] propertyIndex The index of the property of the interface object of which to read the description of.
|
||||||
|
* only used for input if propertyId is not set. Otherwise the index of the property specified by propertyId is written to it.
|
||||||
|
*
|
||||||
|
* @param[out] writeEnable Can the property be written to.
|
||||||
|
*
|
||||||
|
* @param[out] type the ::PropertyDataType of the property
|
||||||
|
*
|
||||||
|
* @param[out] numberOfElements the number of elements of the property. Zero if the interface object does not have the requested property.
|
||||||
|
*
|
||||||
|
* @param[out] access the ::AccessLevel necessary to read/write the property.
|
||||||
|
*/
|
||||||
|
void readPropertyDescription(uint8_t& propertyId, uint8_t& propertyIndex, bool& writeEnable, uint8_t& type, uint16_t& numberOfElements, uint8_t& access);
|
||||||
|
|
||||||
|
// every interface object shall implement this
|
||||||
|
// However, for the time being we provide an empty default implementation
|
||||||
|
virtual void masterReset(EraseCode eraseCode, uint8_t channel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets property with PropertyID id if it exists and nullptr otherwise.
|
||||||
|
*/
|
||||||
|
Property* property(PropertyID id);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T propertyValue(PropertyID id)
|
||||||
|
{
|
||||||
|
const Property* prop = property(id);
|
||||||
|
|
||||||
|
T value = 0;
|
||||||
|
prop->read(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void propertyValue(PropertyID id, T value)
|
||||||
|
{
|
||||||
|
Property* prop = property(id);
|
||||||
|
prop->write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* propertyData(PropertyID id);
|
||||||
|
const uint8_t* propertyData(PropertyID id, uint16_t elementIndex);
|
||||||
|
/**
|
||||||
|
* Gets const property with PropertyID id if it exists and nullptr otherwise.
|
||||||
|
*/
|
||||||
|
const Property* property(PropertyID id) const;
|
||||||
|
|
||||||
|
uint8_t* save(uint8_t* buffer) override;
|
||||||
|
const uint8_t* restore(const uint8_t* buffer) override;
|
||||||
|
uint16_t saveSize() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Intializes the Property-array the the supplied values.
|
||||||
|
*/
|
||||||
|
virtual void initializeProperties(size_t propertiesSize, Property** properties);
|
||||||
|
|
||||||
|
Property** _properties = nullptr;
|
||||||
|
uint8_t _propertyCount = 0;
|
||||||
|
};
|
||||||
1191
components/knx/src/knx/ip_data_link_layer.cpp
Normal file
1191
components/knx/src/knx/ip_data_link_layer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
59
components/knx/src/knx/ip_data_link_layer.h
Normal file
59
components/knx/src/knx/ip_data_link_layer.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "data_link_layer.h"
|
||||||
|
#include "ip_parameter_object.h"
|
||||||
|
#include "knx_ip_tunnel_connection.h"
|
||||||
|
#include "service_families.h"
|
||||||
|
|
||||||
|
class IpDataLinkLayer : public DataLinkLayer
|
||||||
|
{
|
||||||
|
using DataLinkLayer::_deviceObject;
|
||||||
|
|
||||||
|
public:
|
||||||
|
IpDataLinkLayer(DeviceObject& devObj, IpParameterObject& ipParam, NetworkLayerEntity& netLayerEntity,
|
||||||
|
Platform& platform, DataLinkLayerCallbacks* dllcb = nullptr);
|
||||||
|
|
||||||
|
void loop();
|
||||||
|
void enabled(bool value);
|
||||||
|
bool enabled() const;
|
||||||
|
DptMedium mediumType() const override;
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
void dataRequestToTunnel(CemiFrame& frame) override;
|
||||||
|
void dataConfirmationToTunnel(CemiFrame& frame) override;
|
||||||
|
void dataIndicationToTunnel(CemiFrame& frame) override;
|
||||||
|
bool isTunnelAddress(uint16_t addr) override;
|
||||||
|
bool isSentToTunnel(uint16_t address, bool isGrpAddr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _enabled = false;
|
||||||
|
uint8_t _frameCount[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
uint8_t _frameCountBase = 0;
|
||||||
|
uint32_t _frameCountTimeBase = 0;
|
||||||
|
bool sendFrame(CemiFrame& frame);
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
void sendFrameToTunnel(KnxIpTunnelConnection* tunnel, CemiFrame& frame);
|
||||||
|
void loopHandleConnectRequest(uint8_t* buffer, uint16_t length, uint32_t& src_addr, uint16_t& src_port);
|
||||||
|
void loopHandleConnectionStateRequest(uint8_t* buffer, uint16_t length);
|
||||||
|
void loopHandleDisconnectRequest(uint8_t* buffer, uint16_t length);
|
||||||
|
void loopHandleDescriptionRequest(uint8_t* buffer, uint16_t length);
|
||||||
|
void loopHandleDeviceConfigurationRequest(uint8_t* buffer, uint16_t length);
|
||||||
|
void loopHandleTunnelingRequest(uint8_t* buffer, uint16_t length);
|
||||||
|
#endif
|
||||||
|
#if KNX_SERVICE_FAMILY_CORE >= 2
|
||||||
|
void loopHandleSearchRequestExtended(uint8_t* buffer, uint16_t length);
|
||||||
|
#endif
|
||||||
|
bool sendBytes(uint8_t* buffer, uint16_t length);
|
||||||
|
bool isSendLimitReached();
|
||||||
|
IpParameterObject& _ipParameters;
|
||||||
|
DataLinkLayerCallbacks* _dllcb;
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
KnxIpTunnelConnection tunnels[KNX_TUNNELING];
|
||||||
|
uint8_t _lastChannelId = 0;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
#endif
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
#include "ip_host_protocol_address_information.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
IpHostProtocolAddressInformation::IpHostProtocolAddressInformation(uint8_t* data)
|
||||||
|
: _data(data)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t IpHostProtocolAddressInformation::length() const
|
||||||
|
{
|
||||||
|
return *_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IpHostProtocolAddressInformation::length(uint8_t value)
|
||||||
|
{
|
||||||
|
*_data = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
HostProtocolCode IpHostProtocolAddressInformation::code() const
|
||||||
|
{
|
||||||
|
return (HostProtocolCode)_data[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void IpHostProtocolAddressInformation::code(HostProtocolCode value)
|
||||||
|
{
|
||||||
|
_data[1] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t IpHostProtocolAddressInformation::ipAddress() const
|
||||||
|
{
|
||||||
|
return getInt(_data + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IpHostProtocolAddressInformation::ipAddress(uint32_t value)
|
||||||
|
{
|
||||||
|
pushInt(value, _data + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t IpHostProtocolAddressInformation::ipPortNumber() const
|
||||||
|
{
|
||||||
|
return getWord(_data + 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IpHostProtocolAddressInformation::ipPortNumber(uint16_t value)
|
||||||
|
{
|
||||||
|
pushWord(value, _data + 6);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
enum HostProtocolCode : uint8_t
|
||||||
|
{
|
||||||
|
IPV4_UDP = 1,
|
||||||
|
IPV4_TCP = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef USE_IP
|
||||||
|
|
||||||
|
#define LEN_IPHPAI 8
|
||||||
|
#define LEN_CRD 4
|
||||||
|
|
||||||
|
class IpHostProtocolAddressInformation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IpHostProtocolAddressInformation(uint8_t* data);
|
||||||
|
uint8_t length() const;
|
||||||
|
void length(uint8_t value);
|
||||||
|
HostProtocolCode code() const;
|
||||||
|
void code(HostProtocolCode value);
|
||||||
|
uint32_t ipAddress() const;
|
||||||
|
void ipAddress(uint32_t value);
|
||||||
|
uint16_t ipPortNumber() const;
|
||||||
|
void ipPortNumber(uint16_t value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t* _data;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
143
components/knx/src/knx/ip_parameter_object.cpp
Normal file
143
components/knx/src/knx/ip_parameter_object.cpp
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#include "ip_parameter_object.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
#include "device_object.h"
|
||||||
|
#include "platform.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include "data_property.h"
|
||||||
|
#include "callback_property.h"
|
||||||
|
|
||||||
|
// 224.0.23.12
|
||||||
|
#define DEFAULT_MULTICAST_ADDR ((uint32_t)0xE000170C)
|
||||||
|
|
||||||
|
IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platform): _deviceObject(deviceObject),
|
||||||
|
_platform(platform)
|
||||||
|
{
|
||||||
|
Property* properties[] =
|
||||||
|
{
|
||||||
|
new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_IP_PARAMETER),
|
||||||
|
new DataProperty(PID_PROJECT_INSTALLATION_ID, true, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv3),
|
||||||
|
new CallbackProperty<IpParameterObject>(this, PID_KNX_INDIVIDUAL_ADDRESS, true, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv3,
|
||||||
|
[](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t
|
||||||
|
{
|
||||||
|
if (start == 0)
|
||||||
|
{
|
||||||
|
uint16_t currentNoOfElements = 1;
|
||||||
|
pushWord(currentNoOfElements, data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// TODO: get property of deviceobject and use it
|
||||||
|
pushWord(io->_deviceObject.individualAddress(), data);
|
||||||
|
return 1;
|
||||||
|
},
|
||||||
|
[](IpParameterObject * io, uint16_t start, uint8_t count, const uint8_t* data) -> uint8_t
|
||||||
|
{
|
||||||
|
io->_deviceObject.individualAddress(getWord(data));
|
||||||
|
return 1;
|
||||||
|
}),
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
new DataProperty(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES, true, PDT_UNSIGNED_INT, KNX_TUNNELING, ReadLv3 | WriteLv3),
|
||||||
|
new DataProperty(PID_CUSTOM_RESERVED_TUNNELS_CTRL, true, PDT_UNSIGNED_CHAR, KNX_TUNNELING, ReadLv3 | WriteLv3), // custom propertiy to control the stacks behaviour for reserverd tunnels, not in Spec (PID >= 200)
|
||||||
|
new DataProperty(PID_CUSTOM_RESERVED_TUNNELS_IP, true, PDT_UNSIGNED_LONG, KNX_TUNNELING, ReadLv3 | WriteLv3), // custom propertiy to control the stacks behaviour for reserverd tunnels, not in Spec (PID >= 200)
|
||||||
|
#endif
|
||||||
|
new DataProperty(PID_CURRENT_IP_ASSIGNMENT_METHOD, false, PDT_UNSIGNED_CHAR, 0, ReadLv3 | WriteLv3),
|
||||||
|
new DataProperty(PID_IP_ASSIGNMENT_METHOD, true, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv3),
|
||||||
|
new DataProperty(PID_IP_CAPABILITIES, true, PDT_BITSET8, 0, ReadLv3 | WriteLv1), // must be set by application due to capabilities of the used ip stack
|
||||||
|
new CallbackProperty<IpParameterObject>(this, PID_CURRENT_IP_ADDRESS, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0,
|
||||||
|
[](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t
|
||||||
|
{
|
||||||
|
if (start == 0)
|
||||||
|
{
|
||||||
|
uint16_t currentNoOfElements = 1;
|
||||||
|
pushWord(currentNoOfElements, data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pushInt(htonl(io->_platform.currentIpAddress()), data);
|
||||||
|
return 1;
|
||||||
|
}),
|
||||||
|
new CallbackProperty<IpParameterObject>(this, PID_CURRENT_SUBNET_MASK, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0,
|
||||||
|
[](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t
|
||||||
|
{
|
||||||
|
if (start == 0)
|
||||||
|
{
|
||||||
|
uint16_t currentNoOfElements = 1;
|
||||||
|
pushWord(currentNoOfElements, data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pushInt(htonl(io->_platform.currentSubnetMask()), data);
|
||||||
|
return 1;
|
||||||
|
}),
|
||||||
|
new CallbackProperty<IpParameterObject>(this, PID_CURRENT_DEFAULT_GATEWAY, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0,
|
||||||
|
[](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t
|
||||||
|
{
|
||||||
|
if (start == 0)
|
||||||
|
{
|
||||||
|
uint16_t currentNoOfElements = 1;
|
||||||
|
pushWord(currentNoOfElements, data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pushInt(htonl(io->_platform.currentDefaultGateway()), data);
|
||||||
|
return 1;
|
||||||
|
}),
|
||||||
|
new DataProperty(PID_IP_ADDRESS, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3),
|
||||||
|
new DataProperty(PID_SUBNET_MASK, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3),
|
||||||
|
new DataProperty(PID_DEFAULT_GATEWAY, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3),
|
||||||
|
new CallbackProperty<IpParameterObject>(this, PID_MAC_ADDRESS, false, PDT_GENERIC_06, 1, ReadLv3 | WriteLv0,
|
||||||
|
[](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t
|
||||||
|
{
|
||||||
|
if (start == 0)
|
||||||
|
{
|
||||||
|
uint16_t currentNoOfElements = 1;
|
||||||
|
pushWord(currentNoOfElements, data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
io->_platform.macAddress(data);
|
||||||
|
return 1;
|
||||||
|
}),
|
||||||
|
new CallbackProperty<IpParameterObject>(this, PID_SYSTEM_SETUP_MULTICAST_ADDRESS, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0,
|
||||||
|
[](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t
|
||||||
|
{
|
||||||
|
if (start == 0)
|
||||||
|
{
|
||||||
|
uint16_t currentNoOfElements = 1;
|
||||||
|
pushWord(currentNoOfElements, data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pushInt(DEFAULT_MULTICAST_ADDR, data);
|
||||||
|
return 1;
|
||||||
|
}),
|
||||||
|
new DataProperty(PID_ROUTING_MULTICAST_ADDRESS, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3, DEFAULT_MULTICAST_ADDR),
|
||||||
|
new DataProperty(PID_TTL, true, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv3, (uint8_t)16),
|
||||||
|
new CallbackProperty<IpParameterObject>(this, PID_KNXNETIP_DEVICE_CAPABILITIES, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0,
|
||||||
|
[](IpParameterObject * io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t
|
||||||
|
{
|
||||||
|
if (start == 0)
|
||||||
|
{
|
||||||
|
uint16_t currentNoOfElements = 1;
|
||||||
|
pushWord(currentNoOfElements, data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pushWord(0x1, data);
|
||||||
|
return 1;
|
||||||
|
}),
|
||||||
|
new DataProperty(PID_FRIENDLY_NAME, true, PDT_UNSIGNED_CHAR, 30, ReadLv3 | WriteLv3)
|
||||||
|
};
|
||||||
|
initializeProperties(sizeof(properties), properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t* IpParameterObject::additionalIndivualAddresses(uint8_t& numAddresses)
|
||||||
|
{
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
numAddresses = KNX_TUNNELING;
|
||||||
|
#else
|
||||||
|
numAddresses = 0;
|
||||||
|
#endif
|
||||||
|
return (uint16_t*) propertyData(PID_ADDITIONAL_INDIVIDUAL_ADDRESSES);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
20
components/knx/src/knx/ip_parameter_object.h
Normal file
20
components/knx/src/knx/ip_parameter_object.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
#include "interface_object.h"
|
||||||
|
#include "device_object.h"
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
#define KNXIP_MULTICAST_PORT 3671
|
||||||
|
|
||||||
|
class IpParameterObject : public InterfaceObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IpParameterObject(DeviceObject& deviceObject, Platform& platform);
|
||||||
|
uint16_t* additionalIndivualAddresses(uint8_t& numAddresses);
|
||||||
|
private:
|
||||||
|
DeviceObject& _deviceObject;
|
||||||
|
Platform& _platform;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
48
components/knx/src/knx/knx_ip_ch.cpp
Normal file
48
components/knx/src/knx/knx_ip_ch.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "knx_ip_ch.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
KnxIpCH::KnxIpCH(uint8_t* data) : _data(data)
|
||||||
|
{}
|
||||||
|
|
||||||
|
KnxIpCH::~KnxIpCH()
|
||||||
|
{}
|
||||||
|
|
||||||
|
uint8_t KnxIpCH::length() const
|
||||||
|
{
|
||||||
|
return *_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpCH::length(uint8_t value)
|
||||||
|
{
|
||||||
|
*_data = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpCH::channelId(uint8_t value)
|
||||||
|
{
|
||||||
|
_data[1] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t KnxIpCH::channelId() const
|
||||||
|
{
|
||||||
|
return _data[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpCH::sequenceCounter(uint8_t value)
|
||||||
|
{
|
||||||
|
_data[2] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t KnxIpCH::sequenceCounter() const
|
||||||
|
{
|
||||||
|
return _data[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpCH::status(uint8_t value)
|
||||||
|
{
|
||||||
|
_data[3] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t KnxIpCH::status() const
|
||||||
|
{
|
||||||
|
return _data[3];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
28
components/knx/src/knx/knx_ip_ch.h
Normal file
28
components/knx/src/knx/knx_ip_ch.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef USE_IP
|
||||||
|
|
||||||
|
#define LEN_CH 4
|
||||||
|
|
||||||
|
// Connection Header
|
||||||
|
class KnxIpCH
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KnxIpCH(uint8_t* data);
|
||||||
|
virtual ~KnxIpCH();
|
||||||
|
void channelId(uint8_t channelId);
|
||||||
|
uint8_t channelId() const;
|
||||||
|
void sequenceCounter(uint8_t sequenceCounter);
|
||||||
|
uint8_t sequenceCounter() const;
|
||||||
|
void status(uint8_t status);
|
||||||
|
uint8_t status() const;
|
||||||
|
void length(uint8_t value);
|
||||||
|
uint8_t length() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t* _data = 0;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
95
components/knx/src/knx/knx_ip_config_dib.cpp
Normal file
95
components/knx/src/knx/knx_ip_config_dib.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#include "knx_ip_config_dib.h"
|
||||||
|
|
||||||
|
#ifdef USE_IP
|
||||||
|
KnxIpConfigDIB::KnxIpConfigDIB(uint8_t* data, bool isCurrent) : KnxIpDIB(data)
|
||||||
|
{
|
||||||
|
_isCurrent = isCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t KnxIpConfigDIB::address()
|
||||||
|
{
|
||||||
|
uint32_t addr = 0;
|
||||||
|
popInt(addr, _data + 2);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpConfigDIB::address(uint32_t addr)
|
||||||
|
{
|
||||||
|
pushInt(addr, _data + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t KnxIpConfigDIB::subnet()
|
||||||
|
{
|
||||||
|
uint32_t addr = 0;
|
||||||
|
popInt(addr, _data + 6);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpConfigDIB::subnet(uint32_t addr)
|
||||||
|
{
|
||||||
|
pushInt(addr, _data + 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t KnxIpConfigDIB::gateway()
|
||||||
|
{
|
||||||
|
uint32_t addr = 0;
|
||||||
|
popInt(addr, _data + 10);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpConfigDIB::gateway(uint32_t addr)
|
||||||
|
{
|
||||||
|
pushInt(addr, _data + 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t KnxIpConfigDIB::dhcp()
|
||||||
|
{
|
||||||
|
if (!_isCurrent)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint32_t addr = 0;
|
||||||
|
popInt(addr, _data + 14);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpConfigDIB::dhcp(uint32_t addr)
|
||||||
|
{
|
||||||
|
if (!_isCurrent)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pushInt(addr, _data + 14);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t KnxIpConfigDIB::info1()
|
||||||
|
{
|
||||||
|
if (_isCurrent)
|
||||||
|
return _data[14];
|
||||||
|
else
|
||||||
|
return _data[18];
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpConfigDIB::info1(uint8_t addr)
|
||||||
|
{
|
||||||
|
if (_isCurrent)
|
||||||
|
_data[14] = addr;
|
||||||
|
else
|
||||||
|
_data[18] = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t KnxIpConfigDIB::info2()
|
||||||
|
{
|
||||||
|
if (_isCurrent)
|
||||||
|
return _data[15];
|
||||||
|
else
|
||||||
|
return _data[19];
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpConfigDIB::info2(uint8_t addr)
|
||||||
|
{
|
||||||
|
if (_isCurrent)
|
||||||
|
_data[15] = addr;
|
||||||
|
else
|
||||||
|
_data[19] = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
28
components/knx/src/knx/knx_ip_config_dib.h
Normal file
28
components/knx/src/knx/knx_ip_config_dib.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "knx_ip_dib.h"
|
||||||
|
#include "bits.h"
|
||||||
|
|
||||||
|
#ifdef USE_IP
|
||||||
|
#define LEN_IP_CONFIG_DIB 16
|
||||||
|
#define LEN_IP_CURRENT_CONFIG_DIB 20
|
||||||
|
|
||||||
|
class KnxIpConfigDIB : public KnxIpDIB
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KnxIpConfigDIB(uint8_t* data, bool isCurrent = false);
|
||||||
|
uint32_t address();
|
||||||
|
void address(uint32_t addr);
|
||||||
|
uint32_t subnet();
|
||||||
|
void subnet(uint32_t addr);
|
||||||
|
uint32_t gateway();
|
||||||
|
void gateway(uint32_t addr);
|
||||||
|
uint32_t dhcp();
|
||||||
|
void dhcp(uint32_t addr);
|
||||||
|
uint8_t info1();
|
||||||
|
void info1(uint8_t addr);
|
||||||
|
uint8_t info2();
|
||||||
|
void info2(uint8_t addr);
|
||||||
|
private:
|
||||||
|
bool _isCurrent = false;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
17
components/knx/src/knx/knx_ip_config_request.cpp
Normal file
17
components/knx/src/knx/knx_ip_config_request.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include "knx_ip_config_request.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
KnxIpConfigRequest::KnxIpConfigRequest(uint8_t* data, uint16_t length)
|
||||||
|
: KnxIpFrame(data, length), _frame(data + LEN_KNXIP_HEADER + LEN_CH, length - LEN_KNXIP_HEADER - LEN_CH), _ch(data + LEN_KNXIP_HEADER)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CemiFrame& KnxIpConfigRequest::frame()
|
||||||
|
{
|
||||||
|
return _frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
KnxIpCH& KnxIpConfigRequest::connectionHeader()
|
||||||
|
{
|
||||||
|
return _ch;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
17
components/knx/src/knx/knx_ip_config_request.h
Normal file
17
components/knx/src/knx/knx_ip_config_request.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "knx_ip_frame.h"
|
||||||
|
#include "knx_ip_ch.h"
|
||||||
|
#include "ip_host_protocol_address_information.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
class KnxIpConfigRequest : public KnxIpFrame
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KnxIpConfigRequest(uint8_t* data, uint16_t length);
|
||||||
|
CemiFrame& frame();
|
||||||
|
KnxIpCH& connectionHeader();
|
||||||
|
private:
|
||||||
|
CemiFrame _frame;
|
||||||
|
KnxIpCH _ch;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
21
components/knx/src/knx/knx_ip_connect_request.cpp
Normal file
21
components/knx/src/knx/knx_ip_connect_request.cpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#include "knx_ip_connect_request.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
KnxIpConnectRequest::KnxIpConnectRequest(uint8_t* data, uint16_t length)
|
||||||
|
: KnxIpFrame(data, length), _hpaiCtrl(data + LEN_KNXIP_HEADER), _hpaiData(data + LEN_KNXIP_HEADER + LEN_IPHPAI), _cri(data + LEN_KNXIP_HEADER + 2 * LEN_IPHPAI)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
IpHostProtocolAddressInformation& KnxIpConnectRequest::hpaiCtrl()
|
||||||
|
{
|
||||||
|
return _hpaiCtrl;
|
||||||
|
}
|
||||||
|
IpHostProtocolAddressInformation& KnxIpConnectRequest::hpaiData()
|
||||||
|
{
|
||||||
|
return _hpaiData;
|
||||||
|
}
|
||||||
|
KnxIpCRI& KnxIpConnectRequest::cri()
|
||||||
|
{
|
||||||
|
return _cri;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
19
components/knx/src/knx/knx_ip_connect_request.h
Normal file
19
components/knx/src/knx/knx_ip_connect_request.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "knx_ip_frame.h"
|
||||||
|
#include "knx_ip_cri.h"
|
||||||
|
#include "ip_host_protocol_address_information.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
class KnxIpConnectRequest : public KnxIpFrame
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KnxIpConnectRequest(uint8_t* data, uint16_t length);
|
||||||
|
IpHostProtocolAddressInformation& hpaiCtrl();
|
||||||
|
IpHostProtocolAddressInformation& hpaiData();
|
||||||
|
KnxIpCRI& cri();
|
||||||
|
private:
|
||||||
|
IpHostProtocolAddressInformation _hpaiCtrl;
|
||||||
|
IpHostProtocolAddressInformation _hpaiData;
|
||||||
|
KnxIpCRI _cri;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
46
components/knx/src/knx/knx_ip_connect_response.cpp
Normal file
46
components/knx/src/knx/knx_ip_connect_response.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include "knx_ip_connect_response.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
|
||||||
|
KnxIpConnectResponse::KnxIpConnectResponse(IpParameterObject& parameters, uint16_t address, uint16_t port, uint8_t channel, uint8_t type)
|
||||||
|
: KnxIpFrame(LEN_KNXIP_HEADER + 1 /*Channel*/ + 1 /*Status*/ + LEN_IPHPAI + ((type == 4) ? 4 : 2)),
|
||||||
|
_controlEndpoint(_data + LEN_KNXIP_HEADER + 1 /*Channel*/ + 1 /*Status*/),
|
||||||
|
_crd(_data + LEN_KNXIP_HEADER + 1 /*Channel*/ + 1 /*Status*/ + LEN_IPHPAI)
|
||||||
|
{
|
||||||
|
serviceTypeIdentifier(ConnectResponse);
|
||||||
|
|
||||||
|
_data[LEN_KNXIP_HEADER] = channel;
|
||||||
|
|
||||||
|
_controlEndpoint.length(LEN_IPHPAI);
|
||||||
|
_controlEndpoint.code(IPV4_UDP);
|
||||||
|
_controlEndpoint.ipAddress(parameters.propertyValue<uint32_t>(PID_CURRENT_IP_ADDRESS));
|
||||||
|
_controlEndpoint.ipPortNumber(KNXIP_MULTICAST_PORT);
|
||||||
|
|
||||||
|
_crd.length((type == 4) ? 4 : 2); //TunnelConnectionResponse length = 4; ConfigConnectionResponse length = 2;
|
||||||
|
_crd.type(type);
|
||||||
|
if(type == 4) // only fill address when it is a TunnelConnectionResponse
|
||||||
|
_crd.address(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
KnxIpConnectResponse::KnxIpConnectResponse(uint8_t channel, uint8_t errorCode)
|
||||||
|
: KnxIpFrame(LEN_KNXIP_HEADER + 1 /*Channel*/ + 1 /*Status*/),
|
||||||
|
_controlEndpoint(nullptr),
|
||||||
|
_crd(nullptr)
|
||||||
|
{
|
||||||
|
serviceTypeIdentifier(ConnectResponse);
|
||||||
|
|
||||||
|
_data[LEN_KNXIP_HEADER] = channel;
|
||||||
|
_data[LEN_KNXIP_HEADER + 1] = errorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
IpHostProtocolAddressInformation& KnxIpConnectResponse::controlEndpoint()
|
||||||
|
{
|
||||||
|
return _controlEndpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
KnxIpCRD& KnxIpConnectResponse::crd()
|
||||||
|
{
|
||||||
|
return _crd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
45
components/knx/src/knx/knx_ip_connect_response.h
Normal file
45
components/knx/src/knx/knx_ip_connect_response.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "knx_ip_frame.h"
|
||||||
|
#include "knx_ip_crd.h"
|
||||||
|
#include "ip_host_protocol_address_information.h"
|
||||||
|
#include "knx_ip_device_information_dib.h"
|
||||||
|
#include "knx_ip_supported_service_dib.h"
|
||||||
|
#include "ip_parameter_object.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
|
||||||
|
enum KnxIpConnectionRequestErrorCodes
|
||||||
|
{
|
||||||
|
E_NO_ERROR = 0,
|
||||||
|
|
||||||
|
E_HOST_PROTOCOL_TYPE = 0x01,
|
||||||
|
E_VERSION_NOT_SUPPORTED = 0x02,
|
||||||
|
E_SEQUENCE_NUMBER = 0x04,
|
||||||
|
|
||||||
|
E_ERROR = 0x0F,
|
||||||
|
|
||||||
|
E_CONNECTION_ID = 0x21,
|
||||||
|
E_CONNECTION_TYPE = 0x22,
|
||||||
|
E_CONNECTION_OPTION = 0x23,
|
||||||
|
E_NO_MORE_CONNECTIONS = 0x24,
|
||||||
|
E_DATA_CONNECTION = 0x26,
|
||||||
|
E_KNX_CONNECTION = 0x27,
|
||||||
|
E_AUTHORISATION_ERROR = 0x28,
|
||||||
|
E_TUNNELING_LAYER = 0x29,
|
||||||
|
E_NO_TUNNELLING_ADDRESS = 0x2D,
|
||||||
|
E_CONNECTION_IN_USE = 0x2E
|
||||||
|
};
|
||||||
|
|
||||||
|
class KnxIpConnectResponse : public KnxIpFrame
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KnxIpConnectResponse(IpParameterObject& parameters, uint16_t address, uint16_t port, uint8_t channel, uint8_t type);
|
||||||
|
KnxIpConnectResponse(uint8_t channel, uint8_t errorCode);
|
||||||
|
IpHostProtocolAddressInformation& controlEndpoint();
|
||||||
|
KnxIpCRD& crd();
|
||||||
|
private:
|
||||||
|
IpHostProtocolAddressInformation _controlEndpoint;
|
||||||
|
KnxIpCRD _crd;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
41
components/knx/src/knx/knx_ip_crd.cpp
Normal file
41
components/knx/src/knx/knx_ip_crd.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "knx_ip_crd.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
KnxIpCRD::KnxIpCRD(uint8_t* data) : _data(data)
|
||||||
|
{}
|
||||||
|
|
||||||
|
KnxIpCRD::~KnxIpCRD()
|
||||||
|
{}
|
||||||
|
|
||||||
|
uint8_t KnxIpCRD::length() const
|
||||||
|
{
|
||||||
|
return *_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpCRD::length(uint8_t value)
|
||||||
|
{
|
||||||
|
*_data = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t KnxIpCRD::type() const
|
||||||
|
{
|
||||||
|
return _data[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpCRD::type(uint8_t value)
|
||||||
|
{
|
||||||
|
_data[1] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t KnxIpCRD::address() const
|
||||||
|
{
|
||||||
|
uint16_t addr = _data[3];
|
||||||
|
addr |= _data[2] << 8;
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpCRD::address(uint16_t value)
|
||||||
|
{
|
||||||
|
_data[2] = value >> 8;
|
||||||
|
_data[3] = value & 0xFF;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
23
components/knx/src/knx/knx_ip_crd.h
Normal file
23
components/knx/src/knx/knx_ip_crd.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef USE_IP
|
||||||
|
|
||||||
|
class KnxIpCRD
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KnxIpCRD(uint8_t* data);
|
||||||
|
virtual ~KnxIpCRD();
|
||||||
|
void address(uint16_t addr);
|
||||||
|
uint16_t address() const;
|
||||||
|
void type(uint8_t addr);
|
||||||
|
uint8_t type() const;
|
||||||
|
uint8_t length() const;
|
||||||
|
void length(uint8_t value);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t* _data = 0;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
38
components/knx/src/knx/knx_ip_cri.cpp
Normal file
38
components/knx/src/knx/knx_ip_cri.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include "knx_ip_cri.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
KnxIpCRI::KnxIpCRI(uint8_t* data) : _data(data)
|
||||||
|
{}
|
||||||
|
|
||||||
|
KnxIpCRI::~KnxIpCRI()
|
||||||
|
{}
|
||||||
|
|
||||||
|
uint8_t KnxIpCRI::length() const
|
||||||
|
{
|
||||||
|
return *_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpCRI::length(uint8_t value)
|
||||||
|
{
|
||||||
|
*_data = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionType KnxIpCRI::type() const
|
||||||
|
{
|
||||||
|
return (ConnectionType)_data[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpCRI::type(ConnectionType value)
|
||||||
|
{
|
||||||
|
_data[1] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t KnxIpCRI::layer() const
|
||||||
|
{
|
||||||
|
return _data[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpCRI::layer(uint8_t value)
|
||||||
|
{
|
||||||
|
_data[2] = value;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
36
components/knx/src/knx/knx_ip_cri.h
Normal file
36
components/knx/src/knx/knx_ip_cri.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef USE_IP
|
||||||
|
|
||||||
|
#define LEN_CRI 4
|
||||||
|
|
||||||
|
//TODO vervollständigen
|
||||||
|
enum ConnectionType : uint8_t
|
||||||
|
{
|
||||||
|
DEVICE_MGMT_CONNECTION = 3,
|
||||||
|
TUNNEL_CONNECTION = 4,
|
||||||
|
REMLOG_CONNECTION = 6,
|
||||||
|
REMCONF_CONNECTION = 7,
|
||||||
|
OBJSVR_CONNECTION = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
// Connection Request Information
|
||||||
|
class KnxIpCRI
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KnxIpCRI(uint8_t* data);
|
||||||
|
virtual ~KnxIpCRI();
|
||||||
|
ConnectionType type() const;
|
||||||
|
void type(ConnectionType value);
|
||||||
|
void layer(uint8_t layer);
|
||||||
|
uint8_t layer() const;
|
||||||
|
uint8_t length() const;
|
||||||
|
void length(uint8_t value);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t* _data = 0;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
13
components/knx/src/knx/knx_ip_description_request.cpp
Normal file
13
components/knx/src/knx/knx_ip_description_request.cpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#include "knx_ip_description_request.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
KnxIpDescriptionRequest::KnxIpDescriptionRequest(uint8_t* data, uint16_t length)
|
||||||
|
: KnxIpFrame(data, length), _hpaiCtrl(data + LEN_KNXIP_HEADER)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
IpHostProtocolAddressInformation& KnxIpDescriptionRequest::hpaiCtrl()
|
||||||
|
{
|
||||||
|
return _hpaiCtrl;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
15
components/knx/src/knx/knx_ip_description_request.h
Normal file
15
components/knx/src/knx/knx_ip_description_request.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "knx_ip_frame.h"
|
||||||
|
#include "knx_ip_cri.h"
|
||||||
|
#include "ip_host_protocol_address_information.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
class KnxIpDescriptionRequest : public KnxIpFrame
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KnxIpDescriptionRequest(uint8_t* data, uint16_t length);
|
||||||
|
IpHostProtocolAddressInformation& hpaiCtrl();
|
||||||
|
private:
|
||||||
|
IpHostProtocolAddressInformation _hpaiCtrl;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
72
components/knx/src/knx/knx_ip_description_response.cpp
Normal file
72
components/knx/src/knx/knx_ip_description_response.cpp
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#include "knx_ip_description_response.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
|
||||||
|
#define LEN_SERVICE_FAMILIES 2
|
||||||
|
#if MASK_VERSION == 0x091A
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
#define LEN_SERVICE_DIB (2 + 4 * LEN_SERVICE_FAMILIES)
|
||||||
|
#else
|
||||||
|
#define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
#define LEN_SERVICE_DIB (2 + 3 * LEN_SERVICE_FAMILIES)
|
||||||
|
#else
|
||||||
|
#define LEN_SERVICE_DIB (2 + 2 * LEN_SERVICE_FAMILIES)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
KnxIpDescriptionResponse::KnxIpDescriptionResponse(IpParameterObject& parameters, DeviceObject& deviceObject)
|
||||||
|
: KnxIpFrame(LEN_KNXIP_HEADER + LEN_DEVICE_INFORMATION_DIB + LEN_SERVICE_DIB),
|
||||||
|
_deviceInfo(_data + LEN_KNXIP_HEADER),
|
||||||
|
_supportedServices(_data + LEN_KNXIP_HEADER + LEN_DEVICE_INFORMATION_DIB)
|
||||||
|
{
|
||||||
|
serviceTypeIdentifier(DescriptionResponse);
|
||||||
|
|
||||||
|
_deviceInfo.length(LEN_DEVICE_INFORMATION_DIB);
|
||||||
|
_deviceInfo.code(DEVICE_INFO);
|
||||||
|
#if MASK_VERSION == 0x57B0
|
||||||
|
_deviceInfo.medium(0x20); //MediumType is IP (for IP-Only Devices)
|
||||||
|
#else
|
||||||
|
_deviceInfo.medium(0x02); //MediumType is TP
|
||||||
|
#endif
|
||||||
|
_deviceInfo.status(deviceObject.progMode());
|
||||||
|
_deviceInfo.individualAddress(parameters.propertyValue<uint16_t>(PID_KNX_INDIVIDUAL_ADDRESS));
|
||||||
|
_deviceInfo.projectInstallationIdentifier(parameters.propertyValue<uint16_t>(PID_PROJECT_INSTALLATION_ID));
|
||||||
|
_deviceInfo.serialNumber(deviceObject.propertyData(PID_SERIAL_NUMBER));
|
||||||
|
_deviceInfo.routingMulticastAddress(parameters.propertyValue<uint32_t>(PID_ROUTING_MULTICAST_ADDRESS));
|
||||||
|
//_deviceInfo.routingMulticastAddress(0);
|
||||||
|
|
||||||
|
uint8_t mac_address[LEN_MAC_ADDRESS] = {0};
|
||||||
|
Property* prop = parameters.property(PID_MAC_ADDRESS);
|
||||||
|
prop->read(mac_address);
|
||||||
|
_deviceInfo.macAddress(mac_address);
|
||||||
|
|
||||||
|
uint8_t friendlyName[LEN_FRIENDLY_NAME] = {0};
|
||||||
|
prop = parameters.property(PID_FRIENDLY_NAME);
|
||||||
|
prop->read(1, LEN_FRIENDLY_NAME, friendlyName);
|
||||||
|
_deviceInfo.friendlyName(friendlyName);
|
||||||
|
|
||||||
|
_supportedServices.length(LEN_SERVICE_DIB);
|
||||||
|
_supportedServices.code(SUPP_SVC_FAMILIES);
|
||||||
|
_supportedServices.serviceVersion(Core, 1);
|
||||||
|
_supportedServices.serviceVersion(DeviceManagement, 1);
|
||||||
|
#ifdef KNX_TUNNELING
|
||||||
|
_supportedServices.serviceVersion(Tunnelling, 1);
|
||||||
|
#endif
|
||||||
|
#if MASK_VERSION == 0x091A
|
||||||
|
_supportedServices.serviceVersion(Routing, 1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
KnxIpDeviceInformationDIB& KnxIpDescriptionResponse::deviceInfo()
|
||||||
|
{
|
||||||
|
return _deviceInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
KnxIpSupportedServiceDIB& KnxIpDescriptionResponse::supportedServices()
|
||||||
|
{
|
||||||
|
return _supportedServices;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
21
components/knx/src/knx/knx_ip_description_response.h
Normal file
21
components/knx/src/knx/knx_ip_description_response.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "knx_ip_frame.h"
|
||||||
|
#include "ip_host_protocol_address_information.h"
|
||||||
|
#include "knx_ip_device_information_dib.h"
|
||||||
|
#include "knx_ip_supported_service_dib.h"
|
||||||
|
#include "ip_parameter_object.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
|
||||||
|
class KnxIpDescriptionResponse : public KnxIpFrame
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KnxIpDescriptionResponse(IpParameterObject& parameters, DeviceObject& deviceObj);
|
||||||
|
KnxIpDeviceInformationDIB& deviceInfo();
|
||||||
|
KnxIpSupportedServiceDIB& supportedServices();
|
||||||
|
private:
|
||||||
|
KnxIpDeviceInformationDIB _deviceInfo;
|
||||||
|
KnxIpSupportedServiceDIB _supportedServices;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
102
components/knx/src/knx/knx_ip_device_information_dib.cpp
Normal file
102
components/knx/src/knx/knx_ip_device_information_dib.cpp
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#include "knx_ip_device_information_dib.h"
|
||||||
|
#include "bits.h"
|
||||||
|
|
||||||
|
#ifdef USE_IP
|
||||||
|
KnxIpDeviceInformationDIB::KnxIpDeviceInformationDIB(uint8_t* data) : KnxIpDIB(data)
|
||||||
|
{}
|
||||||
|
|
||||||
|
uint8_t KnxIpDeviceInformationDIB::medium() const
|
||||||
|
{
|
||||||
|
return _data[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KnxIpDeviceInformationDIB::medium(uint8_t value)
|
||||||
|
{
|
||||||
|
_data[2] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t KnxIpDeviceInformationDIB::status() const
|
||||||
|
{
|
||||||
|
return _data[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KnxIpDeviceInformationDIB::status(uint8_t value)
|
||||||
|
{
|
||||||
|
_data[3] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t KnxIpDeviceInformationDIB::individualAddress() const
|
||||||
|
{
|
||||||
|
return getWord(_data + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KnxIpDeviceInformationDIB::individualAddress(uint16_t value)
|
||||||
|
{
|
||||||
|
pushWord(value, _data + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t KnxIpDeviceInformationDIB::projectInstallationIdentifier() const
|
||||||
|
{
|
||||||
|
return getWord(_data + 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KnxIpDeviceInformationDIB::projectInstallationIdentifier(uint16_t value)
|
||||||
|
{
|
||||||
|
pushWord(value, _data + 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t* KnxIpDeviceInformationDIB::serialNumber() const
|
||||||
|
{
|
||||||
|
return _data + 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KnxIpDeviceInformationDIB::serialNumber(const uint8_t* value)
|
||||||
|
{
|
||||||
|
pushByteArray(value, LEN_SERIAL_NUMBER, _data + 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t KnxIpDeviceInformationDIB::routingMulticastAddress() const
|
||||||
|
{
|
||||||
|
return getInt(_data + 14);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KnxIpDeviceInformationDIB::routingMulticastAddress(uint32_t value)
|
||||||
|
{
|
||||||
|
pushInt(value, _data + 14);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t* KnxIpDeviceInformationDIB::macAddress() const
|
||||||
|
{
|
||||||
|
return _data + 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KnxIpDeviceInformationDIB::macAddress(const uint8_t* value)
|
||||||
|
{
|
||||||
|
pushByteArray(value, LEN_MAC_ADDRESS, _data + 18);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t* KnxIpDeviceInformationDIB::friendlyName() const
|
||||||
|
{
|
||||||
|
return _data + 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KnxIpDeviceInformationDIB::friendlyName(const uint8_t* value)
|
||||||
|
{
|
||||||
|
pushByteArray(value, LEN_FRIENDLY_NAME, _data + 24);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
32
components/knx/src/knx/knx_ip_device_information_dib.h
Normal file
32
components/knx/src/knx/knx_ip_device_information_dib.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "knx_ip_dib.h"
|
||||||
|
|
||||||
|
#ifdef USE_IP
|
||||||
|
#define LEN_DEVICE_INFORMATION_DIB 54
|
||||||
|
#define LEN_SERIAL_NUMBER 6
|
||||||
|
#define LEN_MAC_ADDRESS 6
|
||||||
|
#define LEN_FRIENDLY_NAME 30
|
||||||
|
|
||||||
|
class KnxIpDeviceInformationDIB : public KnxIpDIB
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KnxIpDeviceInformationDIB(uint8_t* data);
|
||||||
|
uint8_t medium() const;
|
||||||
|
void medium(uint8_t value);
|
||||||
|
uint8_t status() const;
|
||||||
|
void status(uint8_t value);
|
||||||
|
uint16_t individualAddress() const;
|
||||||
|
void individualAddress(uint16_t value);
|
||||||
|
uint16_t projectInstallationIdentifier() const;
|
||||||
|
void projectInstallationIdentifier(uint16_t value);
|
||||||
|
const uint8_t* serialNumber() const;
|
||||||
|
void serialNumber(const uint8_t* value);
|
||||||
|
uint32_t routingMulticastAddress() const;
|
||||||
|
void routingMulticastAddress(uint32_t value);
|
||||||
|
const uint8_t* macAddress() const;
|
||||||
|
void macAddress(const uint8_t* value);
|
||||||
|
const uint8_t* friendlyName() const;
|
||||||
|
void friendlyName(const uint8_t* value);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
28
components/knx/src/knx/knx_ip_dib.cpp
Normal file
28
components/knx/src/knx/knx_ip_dib.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include "knx_ip_dib.h"
|
||||||
|
#ifdef USE_IP
|
||||||
|
KnxIpDIB::KnxIpDIB(uint8_t* data) : _data(data)
|
||||||
|
{}
|
||||||
|
|
||||||
|
KnxIpDIB::~KnxIpDIB()
|
||||||
|
{}
|
||||||
|
|
||||||
|
uint8_t KnxIpDIB::length() const
|
||||||
|
{
|
||||||
|
return *_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpDIB::length(uint8_t value)
|
||||||
|
{
|
||||||
|
*_data = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
DescriptionTypeCode KnxIpDIB::code() const
|
||||||
|
{
|
||||||
|
return (DescriptionTypeCode)_data[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnxIpDIB::code(DescriptionTypeCode value)
|
||||||
|
{
|
||||||
|
_data[1] = value;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user