Merge branch 'v1dev-tp2' into v1dev

This commit is contained in:
Marco Scholl 2024-05-21 22:47:18 +02:00
commit 06e0365a53
No known key found for this signature in database
19 changed files with 1856 additions and 705 deletions

View File

@ -103,6 +103,11 @@ size_t ArduinoPlatform::readBytesUart(uint8_t *buffer, size_t length)
return length;
}
void ArduinoPlatform::flushUart()
{
return _knxSerial->flush();
}
#ifndef KNX_NO_SPI
void ArduinoPlatform::setupSpi()
{

View File

@ -25,6 +25,7 @@ class ArduinoPlatform : public Platform
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

View File

@ -151,4 +151,7 @@ bool Bau07B0::isAckRequired(uint16_t address, bool isGrpAddr)
return false;
}
TpUartDataLinkLayer* Bau07B0::getDataLinkLayer() {
return (TpUartDataLinkLayer*)&_dlLayer;
}
#endif

View File

@ -16,6 +16,7 @@ class Bau07B0 : public BauSystemBDevice, public ITpUartCallBacks, public DataLin
bool enabled() override;
void enabled(bool value) override;
TpUartDataLinkLayer* getDataLinkLayer();
protected:
InterfaceObject* getInterfaceObject(uint8_t idx);
InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance);

View File

@ -167,4 +167,11 @@ bool Bau091A::isAckRequired(uint16_t address, bool isGrpAddr)
return false;
}
IpDataLinkLayer* Bau091A::getPrimaryDataLinkLayer() {
return (IpDataLinkLayer*)&_dlLayerPrimary;
}
TpUartDataLinkLayer* Bau091A::getSecondaryDataLinkLayer() {
return (TpUartDataLinkLayer*)&_dlLayerSecondary;
}
#endif

View File

@ -18,6 +18,8 @@ class Bau091A : public BauSystemBCoupler, public ITpUartCallBacks, public DataLi
bool enabled() override;
void enabled(bool value) override;
IpDataLinkLayer* getPrimaryDataLinkLayer();
TpUartDataLinkLayer* getSecondaryDataLinkLayer();
protected:
InterfaceObject* getInterfaceObject(uint8_t idx);
InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance);

View File

@ -181,5 +181,7 @@ void Bau27B0::domainAddressSerialNumberReadLocalConfirm(Priority priority, HopCo
{
}
RfDataLinkLayer* Bau27B0::getDataLinkLayer() {
return (RfDataLinkLayer*)&_dlLayer;
}
#endif // #ifdef USE_RF

View File

@ -22,6 +22,7 @@ class Bau27B0 : public BauSystemBDevice
bool enabled() override;
void enabled(bool value) override;
RfDataLinkLayer* getDataLinkLayer();
protected:
InterfaceObject* getInterfaceObject(uint8_t idx);
InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance);

View File

@ -154,4 +154,11 @@ void Bau2920::loop()
BauSystemBCoupler::loop();
}
TpUartDataLinkLayer* Bau2920::getPrimaryDataLinkLayer() {
return (TpUartDataLinkLayer*)&_dlLayerPrimary;
}
RfDataLinkLayer* Bau2920::getSecondaryDataLinkLayer() {
return (RfDataLinkLayer*)&_dlLayerSecondary;
}
#endif

View File

@ -22,6 +22,8 @@ class Bau2920 : public BauSystemBCoupler
bool enabled() override;
void enabled(bool value) override;
TpUartDataLinkLayer* getPrimaryDataLinkLayer();
RfDataLinkLayer* getSecondaryDataLinkLayer();
protected:
InterfaceObject* getInterfaceObject(uint8_t idx);
InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance);

View File

@ -145,4 +145,7 @@ void Bau57B0::loop()
#endif
}
IpDataLinkLayer* Bau57B0::getDataLinkLayer() {
return (IpDataLinkLayer*)&_dlLayer;
}
#endif

View File

@ -16,6 +16,7 @@ class Bau57B0 : public BauSystemBDevice, public DataLinkLayerCallbacks
bool enabled() override;
void enabled(bool value) override;
IpDataLinkLayer* getDataLinkLayer();
protected:
InterfaceObject* getInterfaceObject(uint8_t idx);
InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance);

View File

@ -57,6 +57,14 @@ void Platform::closeUart()
void Platform::setupUart()
{}
bool Platform::overflowUart()
{
return false;
}
void Platform::flushUart()
{}
uint32_t Platform::currentIpAddress()
{
return 0x01020304;

View File

@ -62,6 +62,8 @@ class Platform
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 bool overflowUart();
virtual void flushUart();
// SPI
virtual void setupSpi();

302
src/knx/tp_frame.h Normal file
View File

@ -0,0 +1,302 @@
#pragma once
#pragma GCC optimize("O3")
#include "cemi_frame.h"
#include <cstring>
#include <stdint.h>
#include <string>
// Means that the frame is invalid
#define TP_FRAME_FLAG_INVALID 0b10000000
// Means that the frame is an extended frame
#define TP_FRAME_FLAG_EXTENDED 0b01000000
// Means that the frame has been repeated
#define TP_FRAME_FLAG_REPEATED 0b00100000
// Means that the frame comes from the device itself
#define TP_FRAME_FLAG_ECHO 0b00010000
// Means that the frame is processed by this device
#define TP_FRAME_FLAG_ADDRESSED 0b00000100
// Means that the frame has been acked by this device.
#define TP_FRAME_FLAG_ACKING 0b00000010
// Means that the frame has been acked by other (Busmontior)
#define TP_FRAME_FLAG_ACKED 0b00000001
class TpFrame
{
private:
uint8_t *_data;
uint16_t _size;
uint16_t _maxSize;
uint8_t _flags = 0;
/*
* Sets a few flags based on the control byte
*/
inline void presetFlags()
{
if (isExtended())
addFlags(TP_FRAME_FLAG_EXTENDED);
if (isRepeated())
addFlags(TP_FRAME_FLAG_REPEATED);
}
public:
/*
* Convert a CemiFrame into a TpFrame
*/
TpFrame(CemiFrame &cemiFrame)
{
_size = cemiFrame.telegramLengthtTP();
_maxSize = cemiFrame.telegramLengthtTP();
_data = (uint8_t *)malloc(cemiFrame.telegramLengthtTP());
cemiFrame.fillTelegramTP(_data);
presetFlags();
}
/*
* Create a TpFrame with a reserved space.
* Used for incoming parsing.
*/
TpFrame(uint16_t maxSize = 263)
: _maxSize(maxSize)
{
_data = (uint8_t *)malloc(_maxSize);
_size = 0;
}
/*
* Free the data area
*/
~TpFrame()
{
free(_data);
}
/*
* Add a byte at end.
* Used for incoming parsing.
*/
inline void addByte(uint8_t byte)
{
if (!isFull())
{
_data[_size] = byte;
_size++;
}
// Read meta data for flags
if (_size == 1)
presetFlags();
}
/*
* Current frame size. This may differ from the actual size as long as the frame is not complete.
*/
inline uint16_t size()
{
return _size;
}
/*
* Returns the assigned flags
*/
inline uint16_t flags()
{
return _flags;
}
/*
* Adds one or more flags
*/
inline void addFlags(uint8_t flags)
{
_flags |= flags;
}
/*
* Returns a pointer to the data
*/
inline uint8_t *data()
{
return _data;
}
/*
* Returns the byte corresponding to the specified position
*/
inline uint8_t data(uint16_t pos)
{
return _data[pos];
}
/*
* Resets the internal values to refill the frame.
*/
inline void reset()
{
_size = 0;
_flags = 0;
// It is important to fill the _data with zeros so that the length is 0 as long as the value has not yet been read in.
memset(_data, 0x0, _maxSize);
}
/*
* Checks whether the frame has been imported completely
*/
inline bool isFull()
{
return _size >= (_size >= 7 ? fullSize() : _maxSize);
}
/*
* Returns is the frame exteneded or not
*/
inline bool isExtended()
{
return (_data[0] & 0xD3) == 0x10;
}
/*
* Returns the source
* Assumes that enough data has been imported.
*/
inline uint16_t source()
{
return isExtended() ? (_data[2] << 8) + _data[3] : (_data[1] << 8) + _data[2];
}
inline std::string humanSource()
{
uint16_t value = source();
char buffer[10];
sprintf(buffer, "%02i.%02i.%03i", (value >> 12 & 0b1111), (value >> 8 & 0b1111), (value & 0b11111111));
return buffer;
}
inline std::string humanDestination()
{
uint16_t value = destination();
char buffer[10];
if (isGroupAddress())
sprintf(buffer, "%02i/%02i/%03i", (value >> 11 & 0b1111), (value >> 8 & 0b111), (value & 0b11111111));
else
sprintf(buffer, "%02i.%02i.%03i", (value >> 12 & 0b1111), (value >> 8 & 0b1111), (value & 0b11111111));
return buffer;
}
/*
* Returns the destination
* Assumes that enough data has been imported.
*/
inline uint16_t destination()
{
return isExtended() ? (_data[4] << 8) + _data[5] : (_data[3] << 8) + _data[4];
}
/*
* Returns the payload size (with checksum)
* Assumes that enough data has been imported.
*/
inline uint8_t payloadSize()
{
return isExtended() ? _data[6] : _data[5] & 0b1111;
}
/*
* Returns the header size
*/
inline uint8_t headerSize()
{
return isExtended() ? 9 : 8;
}
/*
* Returns the frame size based on header and payload size.
* Assumes that enough data has been imported.
*/
inline uint16_t fullSize()
{
return headerSize() + payloadSize();
}
/*
* Returns if the destination is a group address
* Assumes that enough data has been imported.
*/
inline bool isGroupAddress()
{
return isExtended() ? (_data[1] >> 7) & 0b1 : (_data[5] >> 7) & 0b1;
}
/*
* Calculates the size of a CemiFrame. A CemiFrame has 2 additional bytes at the beginning.
* An additional byte is added to a standard frame, as this still has to be converted into an extendend.
*/
uint16_t cemiSize()
{
return fullSize() + (isExtended() ? 2 : 3);
}
/**
* Creates a buffer and converts the TpFrame into a CemiFrame.
* Important: After processing (i.e. also after using the CemiFrame), the reference must be released manually.
*/
uint8_t *cemiData()
{
uint8_t *cemiBuffer = (uint8_t *)malloc(cemiSize());
// Das CEMI erwartet die Daten im Extended format inkl. zwei zusätzlicher Bytes am Anfang.
cemiBuffer[0] = 0x29;
cemiBuffer[1] = 0x0;
cemiBuffer[2] = _data[0];
if (isExtended())
{
memcpy(cemiBuffer + 2, _data, fullSize());
}
else
{
cemiBuffer[3] = _data[5] & 0xF0;
memcpy(cemiBuffer + 4, _data + 1, 4);
cemiBuffer[8] = _data[5] & 0x0F;
memcpy(cemiBuffer + 9, _data + 6, cemiBuffer[8] + 2);
}
return cemiBuffer;
}
/*
* Checks whether the frame is complete and valid.
*/
inline bool isValid()
{
if (!isComplete())
return false;
uint8_t sum = 0;
const uint16_t s = fullSize() - 1;
for (uint16_t i = 0; i < s; i++)
sum ^= _data[i];
return _data[s] == (uint8_t)~sum;
}
/*
* Checks whether the frame is long enough to match the length specified in the frame
*/
inline bool isComplete()
{
return _size == fullSize();
}
inline bool isRepeated()
{
return !(_data[0] & 0b100000);
}
};

File diff suppressed because it is too large Load Diff

View File

@ -3,14 +3,31 @@
#include "config.h"
#ifdef USE_TP
#include <stdint.h>
#include "data_link_layer.h"
#include "tp_frame.h"
#include <stdint.h>
#define MAX_KNX_TELEGRAM_SIZE 263
#ifndef MAX_RX_QUEUE_BYTES
#define MAX_RX_QUEUE_BYTES MAX_KNX_TELEGRAM_SIZE + 50
#endif
#ifndef MAX_TX_QUEUE
#define MAX_TX_QUEUE 50
#endif
// __time_critical_func fallback
#ifndef ARDUINO_ARCH_RP2040
#define __time_critical_func(X) X
#define __isr
#endif
void printFrame(TpFrame* tpframe);
class ITpUartCallBacks
{
public:
public:
virtual ~ITpUartCallBacks() = default;
virtual bool isAckRequired(uint16_t address, bool isGrpAddr) = 0;
};
@ -24,56 +41,137 @@ class TpUartDataLinkLayer : public DataLinkLayer
TpUartDataLinkLayer(DeviceObject& devObj, NetworkLayerEntity& netLayerEntity,
Platform& platform, ITpUartCallBacks& cb, DataLinkLayerCallbacks* dllcb = nullptr);
void loop();
void enabled(bool value);
bool enabled() const;
DptMedium mediumType() const override;
bool reset();
void monitor();
void stop(bool state);
void requestBusy(bool state);
void forceAck(bool state);
void setRepetitions(uint8_t nack, uint8_t busy);
// Alias
void setFrameRepetition(uint8_t nack, uint8_t busy);
bool isConnected();
bool isMonitoring();
bool isStopped();
bool isBusy();
#ifdef USE_TP_RX_QUEUE
void processRxISR();
#endif
#ifdef NCN5120
void powerControl(bool state);
#endif
uint32_t getRxInvalidFrameCounter();
uint32_t getRxProcessdFrameCounter();
uint32_t getRxIgnoredFrameCounter();
uint32_t getRxUnknownControlCounter();
uint32_t getTxFrameCounter();
uint32_t getTxProcessedFrameCounter();
uint8_t getMode();
private:
bool _enabled = false;
uint8_t* _sendBuffer = 0;
uint16_t _sendBufferLength = 0;
uint8_t _receiveBuffer[MAX_KNX_TELEGRAM_SIZE];
uint8_t _txState = 0;
uint8_t _rxState = 0;
uint16_t _RxByteCnt = 0;
uint16_t _TxByteCnt = 0;
uint8_t _oldIdx = 0;
bool _isEcho = false;
bool _convert = false;
uint8_t _xorSum = 0;
uint32_t _lastByteRxTime;
uint32_t _lastByteTxTime;
uint32_t _lastLoopTime;
uint32_t _waitConfirmStartTime = 0;
uint32_t _lastResetChipTime = 0;
struct _tx_queue_frame_t
// Frame
struct knx_tx_queue_entry_t
{
uint8_t* data;
uint16_t length;
_tx_queue_frame_t* next;
TpFrame* frame;
knx_tx_queue_entry_t* next = nullptr;
knx_tx_queue_entry_t(TpFrame* tpFrame)
: frame(tpFrame)
{
}
};
struct _tx_queue_t
// TX Queue
struct knx_tx_queue_t
{
_tx_queue_frame_t* front = NULL;
_tx_queue_frame_t* back = NULL;
} _tx_queue;
knx_tx_queue_entry_t* front = nullptr;
knx_tx_queue_entry_t* back = nullptr;
} _txFrameQueue;
void addFrameTxQueue(CemiFrame& frame);
bool isTxQueueEmpty();
void loadNextTxFrame();
bool sendSingleFrameByte();
TpFrame* _txFrame = nullptr;
TpFrame* _rxFrame = nullptr;
volatile bool _stopped = false;
volatile bool _connected = false;
volatile bool _monitoring = false;
volatile bool _busy = false;
volatile bool _initialized = false;
volatile uint8_t _rxState = 0;
volatile uint8_t _txState = 0;
volatile uint32_t _rxProcessdFrameCounter = 0;
volatile uint32_t _rxInvalidFrameCounter = 0;
volatile uint32_t _rxIgnoredFrameCounter = 0;
volatile uint32_t _rxUnkownControlCounter = 0;
volatile uint32_t _txFrameCounter = 0;
volatile uint32_t _txProcessdFrameCounter = 0;
volatile bool _rxMarker = false;
volatile bool _rxOverflow = false;
volatile uint8_t _tpState = 0x0;
volatile uint32_t _txLastTime = 0;
volatile uint32_t _rxLastTime = 0;
volatile bool _forceAck = false;
uint8_t _txQueueCount = 0;
inline bool markerMode();
/*
* bits
*
* 5-7 Busy (Default 11 = 3)
* 0-3 Nack (Default 11 = 3)
*/
volatile uint8_t _repetitions = 0b00110011;
// to prevent parallel rx processing by isr (when using)
volatile bool _rxProcessing = false;
volatile uint32_t _lastStateRequest = 0;
// void loadNextTxFrame();
inline bool processTxFrameBytes();
bool sendFrame(CemiFrame& frame);
void frameBytesReceived(uint8_t* buffer, uint16_t length);
void rxFrameReceived(TpFrame* frame);
void dataConBytesReceived(uint8_t* buffer, uint16_t length, bool success);
void enterRxWaitEOP();
bool resetChip();
bool resetChipTick();
void stopChip();
void processRx(bool isr = false);
void checkConnected();
void processRxByte();
void processTxQueue();
void clearTxFrameQueue();
void processRxFrameComplete();
inline void processRxFrame(TpFrame* tpFrame);
void pushTxFrameQueue(TpFrame* tpFrame);
void requestState(bool force = false);
void requestConfig();
inline void processRxFrameByte(uint8_t byte);
#ifdef USE_TP_RX_QUEUE
// Es muss ein Extended Frame rein passen + 1Byte je erlaubter ms Verzögerung
volatile uint8_t _rxBuffer[MAX_RX_QUEUE_BYTES] = {};
volatile uint16_t _rxBufferFront = 0;
volatile uint16_t _rxBufferRear = 0;
volatile uint8_t _rxBufferCount = 0;
void pushByteToRxQueue(uint8_t byte);
uint8_t pullByteFromRxQueue();
uint16_t availableInRxQueue();
void pushRxFrameQueue();
void processRxQueue();
#endif
inline bool isrLock(bool blocking = false);
inline void isrUnlock();
inline void clearUartBuffer();
inline void connected(bool state = true);
void clearTxFrame();
void clearOutdatedTxFrame();
void processTxFrameComplete(bool success);
ITpUartCallBacks& _cb;
DataLinkLayerCallbacks* _dllcb;

View File

@ -31,20 +31,77 @@ For usage of KNX-IP you have to define either
#include <Arduino.h>
//Pi Pico specific libs
#include <EEPROM.h> // EEPROM emulation in flash, part of Earl E Philhowers Pi Pico Arduino support
#include <pico/unique_id.h> // from Pico SDK
#include <hardware/watchdog.h> // from Pico SDK
#include <hardware/flash.h> // from Pico SDK
// Pi Pico specific libs
#include <EEPROM.h> // EEPROM emulation in flash, part of Earl E Philhowers Pi Pico Arduino support
#include <hardware/flash.h> // from Pico SDK
#include <hardware/watchdog.h> // from Pico SDK
#include <pico/unique_id.h> // from Pico SDK
#ifdef USE_KNX_DMA_UART
#include <hardware/dma.h>
// constexpr uint32_t uartDmaTransferCount = 0b1111111111;
constexpr uint32_t uartDmaTransferCount = UINT32_MAX;
constexpr uint8_t uartDmaBufferExp = 8u; // 2**BufferExp
constexpr uint16_t uartDmaBufferSize = (1u << uartDmaBufferExp);
int8_t uartDmaChannel = -1;
volatile uint8_t __attribute__((aligned(uartDmaBufferSize))) uartDmaBuffer[uartDmaBufferSize] = {};
volatile uint32_t uartDmaReadCount = 0;
volatile uint16_t uartDmaRestartCount = 0;
volatile uint32_t uartDmaWriteCount2 = 0;
volatile uint32_t uartDmaAvail = 0;
// Liefert die Zahl der gelesenen Bytes seit dem DMA Transferstart
inline uint32_t uartDmaWriteCount()
{
uartDmaWriteCount2 = uartDmaTransferCount - dma_channel_hw_addr(uartDmaChannel)->transfer_count;
return uartDmaWriteCount2;
}
// Liefert die aktuelle Schreibposition im DMA Buffer
inline uint16_t uartDmaWriteBufferPosition()
{
return uartDmaWriteCount() % uartDmaBufferSize;
}
// Liefert die aktuelle Leseposition im DMA Buffer
inline uint16_t uartDmaReadBufferPosition()
{
return uartDmaReadCount % uartDmaBufferSize;
}
// Liefert die aktuelle Leseposition als Pointer
inline uint8_t* uartDmaReadAddr()
{
return ((uint8_t*)uartDmaBuffer + uartDmaReadBufferPosition());
}
// Startet den Transfer nach Abschluss neu.
void __time_critical_func(uartDmaRestart)()
{
// println("Restart");
uartDmaRestartCount = uartDmaWriteBufferPosition() - uartDmaReadBufferPosition();
// wenn uartDmaRestartCount == 0 ist, wurde alles verarbeitet und der read count kann mit dem neustart wieder auf 0 gesetzt werden.
if (uartDmaRestartCount == 0)
{
uartDmaReadCount = 0;
}
asm volatile("" ::: "memory");
dma_hw->ints0 = 1u << uartDmaChannel; // clear DMA IRQ0 flag
asm volatile("" ::: "memory");
dma_channel_set_write_addr(uartDmaChannel, uartDmaBuffer, true);
}
#endif
#define FLASHPTR ((uint8_t*)XIP_BASE + KNX_FLASH_OFFSET)
#ifndef USE_RP2040_EEPROM_EMULATION
#if KNX_FLASH_SIZE%4096
#if KNX_FLASH_SIZE % 4096
#error "KNX_FLASH_SIZE must be multiple of 4096"
#endif
#if KNX_FLASH_OFFSET%4096
#if KNX_FLASH_OFFSET % 4096
#error "KNX_FLASH_OFFSET must be multiple of 4096"
#endif
#endif
@ -57,26 +114,27 @@ extern Wiznet5500lwIP KNX_NETIF;
#endif
RP2040ArduinoPlatform::RP2040ArduinoPlatform()
#ifndef KNX_NO_DEFAULT_UART
#if !defined(KNX_NO_DEFAULT_UART) && !defined(USE_KNX_DMA_UART)
: ArduinoPlatform(&KNX_SERIAL)
#endif
{
#ifdef KNX_UART_RX_PIN
#ifdef KNX_UART_RX_PIN
_rxPin = KNX_UART_RX_PIN;
#endif
#ifdef KNX_UART_TX_PIN
#endif
#ifdef KNX_UART_TX_PIN
_txPin = KNX_UART_TX_PIN;
#endif
#ifndef USE_RP2040_EEPROM_EMULATION
#endif
#ifndef USE_RP2040_EEPROM_EMULATION
_memoryType = Flash;
#endif
#endif
}
RP2040ArduinoPlatform::RP2040ArduinoPlatform( HardwareSerial* s) : ArduinoPlatform(s)
RP2040ArduinoPlatform::RP2040ArduinoPlatform(HardwareSerial* s)
: ArduinoPlatform(s)
{
#ifndef USE_RP2040_EEPROM_EMULATION
#ifndef USE_RP2040_EEPROM_EMULATION
_memoryType = Flash;
#endif
#endif
}
void RP2040ArduinoPlatform::knxUartPins(pin_size_t rxPin, pin_size_t txPin)
@ -85,31 +143,162 @@ void RP2040ArduinoPlatform::knxUartPins(pin_size_t rxPin, pin_size_t txPin)
_txPin = txPin;
}
bool RP2040ArduinoPlatform::overflowUart()
{
#ifdef USE_KNX_DMA_UART
// during dma restart
bool ret;
const uint32_t writeCount = uartDmaWriteCount();
if (uartDmaRestartCount > 0)
ret = writeCount >= (uartDmaBufferSize - uartDmaRestartCount - 1);
else
ret = (writeCount - uartDmaReadCount) > uartDmaBufferSize;
// if (ret)
// {
// println(uartDmaWriteBufferPosition());
// println(uartDmaReadBufferPosition());
// println(uartDmaWriteCount());
// println(uartDmaReadCount);
// println(uartDmaRestartCount);
// printHex("BUF: ", (const uint8_t *)uartDmaBuffer, uartDmaBufferSize);
// println("OVERFLOW");
// while (true)
// ;
// }
return ret;
#else
SerialUART* serial = dynamic_cast<SerialUART*>(_knxSerial);
return serial->overflow();
#endif
}
void RP2040ArduinoPlatform::setupUart()
{
#ifdef USE_KNX_DMA_UART
if (uartDmaChannel == -1)
{
// configure uart0
gpio_set_function(_rxPin, GPIO_FUNC_UART);
gpio_set_function(_txPin, GPIO_FUNC_UART);
uart_init(KNX_DMA_UART, 19200);
uart_set_hw_flow(KNX_DMA_UART, false, false);
uart_set_format(KNX_DMA_UART, 8, 1, UART_PARITY_EVEN);
uart_set_fifo_enabled(KNX_DMA_UART, false);
// configure uart0
uartDmaChannel = dma_claim_unused_channel(true); // get free channel for dma
dma_channel_config dmaConfig = dma_channel_get_default_config(uartDmaChannel);
channel_config_set_transfer_data_size(&dmaConfig, DMA_SIZE_8);
channel_config_set_read_increment(&dmaConfig, false);
channel_config_set_write_increment(&dmaConfig, true);
channel_config_set_high_priority(&dmaConfig, true);
channel_config_set_ring(&dmaConfig, true, uartDmaBufferExp);
channel_config_set_dreq(&dmaConfig, KNX_DMA_UART_DREQ);
dma_channel_set_read_addr(uartDmaChannel, &uart_get_hw(uart0)->dr, false);
dma_channel_set_write_addr(uartDmaChannel, uartDmaBuffer, false);
dma_channel_set_trans_count(uartDmaChannel, uartDmaTransferCount, false);
dma_channel_set_config(uartDmaChannel, &dmaConfig, true);
dma_channel_set_irq1_enabled(uartDmaChannel, true);
// irq_add_shared_handler(KNX_DMA_IRQ, uartDmaRestart, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY);
irq_set_exclusive_handler(KNX_DMA_IRQ, uartDmaRestart);
irq_set_enabled(KNX_DMA_IRQ, true);
}
#else
SerialUART* serial = dynamic_cast<SerialUART*>(_knxSerial);
if(serial)
if (serial)
{
if (_rxPin != UART_PIN_NOT_DEFINED)
serial->setRX(_rxPin);
if (_txPin != UART_PIN_NOT_DEFINED)
serial->setTX(_txPin);
serial->setPollingMode();
serial->setFIFOSize(64);
}
_knxSerial->begin(19200, SERIAL_8E1);
while (!_knxSerial)
;
#endif
}
#ifdef USE_KNX_DMA_UART
int RP2040ArduinoPlatform::uartAvailable()
{
if (uartDmaChannel == -1)
return 0;
if (uartDmaRestartCount > 0)
{
return uartDmaRestartCount;
}
else
{
uint32_t tc = dma_channel_hw_addr(uartDmaChannel)->transfer_count;
uartDmaAvail = tc;
int test = uartDmaTransferCount - tc - uartDmaReadCount;
return test;
}
}
int RP2040ArduinoPlatform::readUart()
{
if (!uartAvailable())
return -1;
int ret = uartDmaReadAddr()[0];
// print("< ");
// println(ret, HEX);
uartDmaReadCount++;
if (uartDmaRestartCount > 0)
{
// process previouse buffer
uartDmaRestartCount--;
// last char, then reset read count to start at new writer position
if (uartDmaRestartCount == 0)
uartDmaReadCount = 0;
}
return ret;
}
size_t RP2040ArduinoPlatform::writeUart(const uint8_t data)
{
if (uartDmaChannel == -1)
return 0;
// print("> ");
// println(data, HEX);
while (!uart_is_writable(uart0))
;
uart_putc_raw(uart0, data);
return 1;
}
void RP2040ArduinoPlatform::closeUart()
{
if (uartDmaChannel >= 0)
{
dma_channel_cleanup(uartDmaChannel);
irq_set_enabled(DMA_IRQ_0, false);
uart_deinit(uart0);
uartDmaChannel = -1;
uartDmaReadCount = 0;
uartDmaRestartCount = 0;
}
}
#endif
uint32_t RP2040ArduinoPlatform::uniqueSerialNumber()
{
pico_unique_board_id_t id; // 64Bit unique serial number from the QSPI flash
pico_unique_board_id_t id; // 64Bit unique serial number from the QSPI flash
noInterrupts();
rp2040.idleOtherCore();
flash_get_unique_id(id.id); //pico_get_unique_board_id(&id);
flash_get_unique_id(id.id); // pico_get_unique_board_id(&id);
rp2040.resumeOtherCore();
interrupts();
@ -123,7 +312,7 @@ uint32_t RP2040ArduinoPlatform::uniqueSerialNumber()
void RP2040ArduinoPlatform::restart()
{
println("restart");
watchdog_reboot(0,0,0);
watchdog_reboot(0, 0, 0);
}
#ifdef USE_RP2040_EEPROM_EMULATION
@ -132,15 +321,15 @@ void RP2040ArduinoPlatform::restart()
#ifdef USE_RP2040_LARGE_EEPROM_EMULATION
uint8_t * RP2040ArduinoPlatform::getEepromBuffer(uint32_t size)
uint8_t* RP2040ArduinoPlatform::getEepromBuffer(uint32_t size)
{
if(size%4096)
if (size % 4096)
{
println("KNX_FLASH_SIZE must be a multiple of 4096");
fatalError();
}
if(!_rambuff_initialized)
if (!_rambuff_initialized)
{
memcpy(_rambuff, FLASHPTR, KNX_FLASH_SIZE);
_rambuff_initialized = true;
@ -154,10 +343,10 @@ void RP2040ArduinoPlatform::commitToEeprom()
noInterrupts();
rp2040.idleOtherCore();
//ToDo: write block-by-block to prevent writing of untouched blocks
if(memcmp(_rambuff, FLASHPTR, KNX_FLASH_SIZE))
// ToDo: write block-by-block to prevent writing of untouched blocks
if (memcmp(_rambuff, FLASHPTR, KNX_FLASH_SIZE))
{
flash_range_erase (KNX_FLASH_OFFSET, KNX_FLASH_SIZE);
flash_range_erase(KNX_FLASH_OFFSET, KNX_FLASH_SIZE);
flash_range_program(KNX_FLASH_OFFSET, _rambuff, KNX_FLASH_SIZE);
}
@ -167,17 +356,17 @@ void RP2040ArduinoPlatform::commitToEeprom()
#else
uint8_t * RP2040ArduinoPlatform::getEepromBuffer(uint32_t size)
uint8_t* RP2040ArduinoPlatform::getEepromBuffer(uint32_t size)
{
if(size > 4096)
if (size > 4096)
{
println("KNX_FLASH_SIZE to big for EEPROM emulation (max. 4kB)");
fatalError();
}
uint8_t * eepromptr = EEPROM.getDataPtr();
uint8_t* eepromptr = EEPROM.getDataPtr();
if(eepromptr == nullptr)
if (eepromptr == nullptr)
{
EEPROM.begin(4096);
eepromptr = EEPROM.getDataPtr();
@ -212,10 +401,10 @@ uint8_t* RP2040ArduinoPlatform::userFlashStart()
size_t RP2040ArduinoPlatform::userFlashSizeEraseBlocks()
{
if(KNX_FLASH_SIZE <= 0)
if (KNX_FLASH_SIZE <= 0)
return 0;
else
return ( (KNX_FLASH_SIZE - 1) / (flashPageSize() * flashEraseBlockSize())) + 1;
return ((KNX_FLASH_SIZE - 1) / (flashPageSize() * flashEraseBlockSize())) + 1;
}
void RP2040ArduinoPlatform::flashErase(uint16_t eraseBlockNum)
@ -223,7 +412,7 @@ void RP2040ArduinoPlatform::flashErase(uint16_t eraseBlockNum)
noInterrupts();
rp2040.idleOtherCore();
flash_range_erase (KNX_FLASH_OFFSET + eraseBlockNum * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize());
flash_range_erase(KNX_FLASH_OFFSET + eraseBlockNum * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize());
rp2040.resumeOtherCore();
interrupts();
@ -242,12 +431,12 @@ void RP2040ArduinoPlatform::flashWritePage(uint16_t pageNumber, uint8_t* data)
void RP2040ArduinoPlatform::writeBufferedEraseBlock()
{
if(_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty)
if (_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty)
{
noInterrupts();
rp2040.idleOtherCore();
flash_range_erase (KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize());
flash_range_erase(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize());
flash_range_program(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), _eraseblockBuffer, flashPageSize() * flashEraseBlockSize());
rp2040.resumeOtherCore();
@ -276,7 +465,7 @@ void RP2040ArduinoPlatform::macAddress(uint8_t* addr)
#if defined(KNX_IP_W5500)
addr = KNX_NETIF.getNetIf()->hwaddr;
#elif defined(KNX_IP_WIFI)
uint8_t macaddr[6] = {0,0,0,0,0,0};
uint8_t macaddr[6] = {0, 0, 0, 0, 0, 0};
addr = KNX_NETIF.macAddress(macaddr);
#elif defined(KNX_IP_GENERIC)
KNX_NETIF.MACAddress(addr);
@ -289,12 +478,12 @@ void RP2040ArduinoPlatform::setupMultiCast(uint32_t addr, uint16_t port)
mcastaddr = IPAddress(htonl(addr));
_port = port;
uint8_t result = _udp.beginMulticast(mcastaddr, port);
(void) result;
(void)result;
#ifdef KNX_IP_GENERIC
//if(!_unicast_socket_setup)
// _unicast_socket_setup = UDP_UNICAST.begin(3671);
#endif
#ifdef KNX_IP_GENERIC
// if(!_unicast_socket_setup)
// _unicast_socket_setup = UDP_UNICAST.begin(3671);
#endif
// print("Setup Mcast addr: ");
// print(mcastaddr.toString().c_str());
@ -313,7 +502,7 @@ bool RP2040ArduinoPlatform::sendBytesMultiCast(uint8_t* buffer, uint16_t len)
{
// printHex("<- ",buffer, len);
//ToDo: check if Ethernet is able to receive, return false if not
// ToDo: check if Ethernet is able to receive, return false if not
_udp.beginPacket(mcastaddr, _port);
_udp.write(buffer, len);
_udp.endPacket();
@ -353,7 +542,7 @@ bool RP2040ArduinoPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8
// println(ucastaddr.toString().c_str());
#ifdef KNX_IP_GENERIC
if(!_unicast_socket_setup)
if (!_unicast_socket_setup)
_unicast_socket_setup = UDP_UNICAST.begin(3671);
#endif
@ -371,5 +560,3 @@ bool RP2040ArduinoPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8
#endif
#endif

View File

@ -58,6 +58,22 @@
#endif
#if USE_KNX_DMA_UART == 1
#define KNX_DMA_UART uart1
#define KNX_DMA_UART_IRQ UART1_IRQ
#define KNX_DMA_UART_DREQ DREQ_UART1_RX
#else
#define KNX_DMA_UART uart0
#define KNX_DMA_UART_IRQ UART0_IRQ
#define KNX_DMA_UART_DREQ DREQ_UART0_RX
#endif
#if USE_KNX_DMA_IRQ == 1
#define KNX_DMA_IRQ DMA_IRQ_1
#else
#define KNX_DMA_IRQ DMA_IRQ_0
#endif
class RP2040ArduinoPlatform : public ArduinoPlatform
{
@ -67,7 +83,20 @@ public:
// uart
void knxUartPins(pin_size_t rxPin, pin_size_t txPin);
void setupUart();
void setupUart() override;
bool overflowUart() override;
#ifdef USE_KNX_DMA_UART
int uartAvailable() override;
void closeUart() override;
void knxUart( HardwareSerial* serial) override {};
HardwareSerial* knxUart() override { return nullptr; };
size_t writeUart(const uint8_t data) override;
size_t writeUart(const uint8_t* buffer, size_t size) override { return 0; };
int readUart() override;
size_t readBytesUart(uint8_t* buffer, size_t length) override { return 0; };
void flushUart() override {};
#endif
// unique serial number
uint32_t uniqueSerialNumber() override;