Merge pull request #317 from Phil1pp/libretiny

Added support for LibreTiny IoT chips
This commit is contained in:
thelsing 2025-07-23 23:12:51 +02:00 committed by GitHub
commit f073d8fd0b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 308 additions and 17 deletions

View File

@ -1,6 +1,6 @@
# knx
This projects provides a knx-device stack for Arduino (ESP8266, ESP32, SAMD21, RP2040, STM32), CC1310, ESP IDF and Linux. (more are quite easy to add)
This projects provides a knx-device stack for Arduino (ESP8266, ESP32, SAMD21, RP2040, STM32), CC1310, ESP IDF, LibreTiny (BK7231, RTL8710 and LN882H) and Linux. (more are quite easy to add)
It implements most of System-B specification and can be configured with ETS.
The necessary knxprod-files can be generated with the [Kaenx-Creator](https://github.com/OpenKNX/Kaenx-Creator) tool.

View File

@ -58,7 +58,11 @@ void setup()
Serial.begin(115200);
ArduinoPlatform::SerialDebug = &Serial;
#ifdef LIBRETINY
srandom(millis());
#else
randomSeed(millis());
#endif
#if MASK_VERSION != 0x07B0 && (defined ARDUINO_ARCH_ESP8266 || defined ARDUINO_ARCH_ESP32)
WiFiManager wifiManager;

View File

@ -96,3 +96,17 @@ build_flags =
-DKNX_FLASH_SIZE=4096
-D PIO_FRAMEWORK_ARDUINO_ENABLE_RTTI
-Wno-unknown-pragmas
;--- LibreTiny BK7231N ------------------------------------
[env:BK7231N_ip]
platform = libretiny
board = cbu
framework = arduino
lib_deps =
knx
build_flags =
-DMASK_VERSION=0x57B0
-DKNX_NO_SPI
-DKNX_FLASH_OFFSET=0x1DB000
-Wno-unknown-pragmas

View File

@ -168,4 +168,22 @@ build_flags =
-DMASK_VERSION=0x07B0
-DKNX_FLASH_SIZE=4096
-D PIO_FRAMEWORK_ARDUINO_ENABLE_RTTI
-Wno-unknown-pragmas
;--- LibreTiny BK7231N ------------------------------------
[env:BK7231N_ip]
platform = libretiny
board = cbu
framework = arduino
; We consider that the this projects is opened within its project directory
; while working with VS Code.
lib_extra_dirs = ../../../
lib_deps =
knx
build_flags =
-DMASK_VERSION=0x57B0
-DKNX_NO_SPI
-DKNX_FLASH_OFFSET=0x1DB000
-Wno-unknown-pragmas

View File

@ -11,21 +11,13 @@
#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
#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
#if defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_STM32)
#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>
@ -85,6 +77,18 @@
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);

View File

@ -21,7 +21,7 @@ enum ComFlag : uint8_t
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)
#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

View File

@ -8,7 +8,8 @@
defined(ARDUINO_ARCH_ESP32) || \
defined(ARDUINO_ARCH_ESP8266) || \
defined(ARDUINO_ARCH_SAMD) || \
defined(ARDUINO_ARCH_RP2040))
defined(ARDUINO_ARCH_RP2040)) || \
defined(LIBRETINY)
// Only ESP8266 and ESP32 have this define. For all other platforms this is just empty.
#ifndef IRAM_ATTR
@ -95,6 +96,18 @@ IRAM_ATTR void buttonEvent()
#error "Mask version not supported on ARDUINO_ARCH_ESP32"
#endif
#elif defined(LIBRETINY)
// predefined global instance for TP or IP or TP/IP coupler
#if MASK_VERSION == 0x07B0
KnxFacade<LibretinyPlatform, Bau07B0> knx(buttonEvent);
#elif MASK_VERSION == 0x57B0
KnxFacade<LibretinyPlatform, Bau57B0> knx(buttonEvent);
#elif MASK_VERSION == 0x091A
KnxFacade<LibretinyPlatform, Bau091A> knx(buttonEvent);
#else
#error "Mask version not supported on LIBRETINY"
#endif
#elif defined(ESP_PLATFORM)
// predefined global instance for TP or IP or TP/IP coupler
#if MASK_VERSION == 0x07B0

View File

@ -32,6 +32,8 @@
#ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE
void buttonUp();
#endif
#elif defined(LIBRETINY)
#include "libretiny_platform.h"
#elif defined(ESP_PLATFORM)
#include "esp32_idf_platform.h"
#ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE
@ -265,7 +267,6 @@ template <class P, class B> class KnxFacade : private SaveRestore
void start()
{
if (_ledPin >= 0)
{
#if defined(ESP_PLATFORM)
@ -553,6 +554,17 @@ template <class P, class B> class KnxFacade : private SaveRestore
#else
#error "Mask version not supported on ARDUINO_ARCH_ESP32"
#endif
#elif defined(LIBRETINY)
// predefined global instance for TP or IP or TP/IP coupler
#if MASK_VERSION == 0x07B0
extern KnxFacade<LibretinyPlatform, Bau07B0> knx;
#elif MASK_VERSION == 0x57B0
extern KnxFacade<LibretinyPlatform, Bau57B0> knx;
#elif MASK_VERSION == 0x091A
extern KnxFacade<LibretinyPlatform, Bau091A> knx;
#else
#error "Mask version not supported on LIBRETINY"
#endif
#elif defined(ESP_PLATFORM)
// predefined global instance for TP or IP or TP/IP coupler
#if MASK_VERSION == 0x07B0

173
src/libretiny_platform.cpp Normal file
View File

@ -0,0 +1,173 @@
#include "libretiny_platform.h"
#ifdef LIBRETINY
#include <Arduino.h>
#include "knx/bits.h"
#include <lwip/netif.h>
#ifndef KNX_SERIAL
#define KNX_SERIAL Serial
#endif
#ifndef KNX_FLASH_OFFSET
#error "KNX_FLASH_OFFSET is not defined. E.g. 0x1DB000 for BK7231N"
#elif (KNX_FLASH_OFFSET % 4096) != 0
#error "KNX_FLASH_OFFSET must be a multiple of 4096"
#endif
static uint8_t NVS_buffer[KNX_FLASH_SIZE];
LibretinyPlatform::LibretinyPlatform()
#ifndef KNX_NO_DEFAULT_UART
: ArduinoPlatform(&KNX_SERIAL)
#endif
{
_memoryType = Flash;
}
LibretinyPlatform::LibretinyPlatform( HardwareSerial* s) : ArduinoPlatform(s)
{
_memoryType = Flash;
}
uint32_t LibretinyPlatform::currentIpAddress()
{
return WiFi.localIP();
}
uint32_t LibretinyPlatform::currentSubnetMask()
{
return WiFi.subnetMask();
}
uint32_t LibretinyPlatform::currentDefaultGateway()
{
return WiFi.gatewayIP();
}
void LibretinyPlatform::macAddress(uint8_t * addr)
{
WiFi.macAddress(addr);
}
uint32_t LibretinyPlatform::uniqueSerialNumber()
{
return lt_cpu_get_mac_id();
}
void LibretinyPlatform::restart()
{
println("restart");
lt_reboot();
}
void LibretinyPlatform::setupMultiCast(uint32_t addr, uint16_t port)
{
//workaround for libretiny bug: NETIF_FLAG_IGMP is not set by default
struct netif *netif;
for (netif = netif_list; netif != NULL; netif = netif->next)
{
netif->flags |= NETIF_FLAG_IGMP;
}
IPAddress mcastaddr(htonl(addr));
KNX_DEBUG_SERIAL.printf("setup multicast addr: %d.%d.%d.%d port: %d ip: %d.%d.%d.%d\n", mcastaddr[0], mcastaddr[1], mcastaddr[2], mcastaddr[3], port, WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3]);
uint8_t result = _udp.beginMulticast(mcastaddr, port);
KNX_DEBUG_SERIAL.printf("multicast setup result %d\n", result);
}
void LibretinyPlatform::closeMultiCast()
{
_udp.stop();
}
bool LibretinyPlatform::sendBytesMultiCast(uint8_t * buffer, uint16_t len)
{
_udp.beginMulticastPacket();
_udp.write(buffer, len);
_udp.endPacket();
return true;
}
int LibretinyPlatform::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);
return len;
}
bool LibretinyPlatform::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;
}
size_t LibretinyPlatform::flashEraseBlockSize()
{
return 16;
}
size_t LibretinyPlatform::flashPageSize()
{
return 256;
}
uint8_t* LibretinyPlatform::userFlashStart()
{
lt_flash_read(KNX_FLASH_OFFSET, NVS_buffer, KNX_FLASH_SIZE);
return NVS_buffer;
}
size_t LibretinyPlatform::userFlashSizeEraseBlocks()
{
if(KNX_FLASH_SIZE <= 0)
return 0;
else
return ( (KNX_FLASH_SIZE - 1) / (flashPageSize() * flashEraseBlockSize())) + 1;
}
void LibretinyPlatform::flashErase(uint16_t eraseBlockNum)
{
// 16 pages x 256byte/page = 4096byte
lt_flash_erase_block(KNX_FLASH_OFFSET + eraseBlockNum * flashPageSize() * flashEraseBlockSize());
}
void LibretinyPlatform::flashWritePage(uint16_t pageNumber, uint8_t* data)
{
lt_flash_write(KNX_FLASH_OFFSET + pageNumber * flashPageSize(), data, flashPageSize());
}
void LibretinyPlatform::writeBufferedEraseBlock()
{
if(_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty)
{
lt_flash_erase_block(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize());
lt_flash_write(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), _eraseblockBuffer, flashPageSize() * flashEraseBlockSize());
_bufferedEraseblockDirty = false;
}
}
#endif

53
src/libretiny_platform.h Normal file
View File

@ -0,0 +1,53 @@
#ifdef LIBRETINY
#include "arduino_platform.h"
#include <WiFi.h>
#include <LwIPUdp.h>
class LibretinyPlatform : public ArduinoPlatform
{
public:
LibretinyPlatform();
LibretinyPlatform(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;
// size of one EraseBlock in pages
virtual size_t flashEraseBlockSize();
// size of one flash page in bytes
virtual size_t flashPageSize();
// start of user flash aligned to start of an erase block
virtual uint8_t* userFlashStart();
// size of the user flash in EraseBlocks
virtual size_t userFlashSizeEraseBlocks();
// relativ to userFlashStart
virtual void flashErase(uint16_t eraseBlockNum);
// write a single page to flash (pageNumber relative to userFashStart
virtual void flashWritePage(uint16_t pageNumber, uint8_t* data);
// writes _eraseblockBuffer to flash - overrides Plattform::writeBufferedEraseBlock() for performance optimization only
void writeBufferedEraseBlock();
private:
WiFiUDP _udp;
};
#endif