From 8421279d5312208040cf72b4a48585cab41628f9 Mon Sep 17 00:00:00 2001 From: Thomas Kunze Date: Sun, 3 Nov 2019 22:09:22 +0100 Subject: [PATCH] -add saveLength to SaveRestore -undo split of Restore from SaveRestore -add some dynamic memory management to memory-class --- knx-linux/knx-linux.vcxproj | 8 ++ knx-linux/knx-linux.vcxproj.filters | 24 ++++ src/knx/address_table_object.cpp | 5 - src/knx/address_table_object.h | 2 +- src/knx/application_program_object.cpp | 4 + src/knx/application_program_object.h | 1 + src/knx/association_table_object.cpp | 5 - src/knx/association_table_object.h | 1 - src/knx/bau_systemB.cpp | 2 +- src/knx/device_object.cpp | 5 + src/knx/device_object.h | 1 + src/knx/group_object_table_object.cpp | 7 - src/knx/group_object_table_object.h | 5 +- src/knx/ip_parameter_object.cpp | 7 +- src/knx/ip_parameter_object.h | 1 + src/knx/memory.cpp | 183 +++++++++++++++++++++++-- src/knx/memory.h | 21 ++- src/knx/platform.h | 17 ++- src/knx/restore.h | 21 --- src/knx/rf_medium_object.cpp | 5 + src/knx/rf_medium_object.h | 3 +- src/knx/save_restore.h | 16 ++- src/knx/table_object.cpp | 34 ++--- src/knx/table_object.h | 6 +- src/knx_facade.h | 11 ++ 25 files changed, 305 insertions(+), 90 deletions(-) delete mode 100644 src/knx/restore.h diff --git a/knx-linux/knx-linux.vcxproj b/knx-linux/knx-linux.vcxproj index 928a1c1..6d634f3 100644 --- a/knx-linux/knx-linux.vcxproj +++ b/knx-linux/knx-linux.vcxproj @@ -78,6 +78,7 @@ + @@ -98,6 +99,9 @@ + + + @@ -121,6 +125,7 @@ + @@ -139,6 +144,9 @@ + + + diff --git a/knx-linux/knx-linux.vcxproj.filters b/knx-linux/knx-linux.vcxproj.filters index f4fef6b..b77d70c 100644 --- a/knx-linux/knx-linux.vcxproj.filters +++ b/knx-linux/knx-linux.vcxproj.filters @@ -137,6 +137,18 @@ Header files\knx + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + @@ -235,5 +247,17 @@ Source files\knx + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + \ No newline at end of file diff --git a/src/knx/address_table_object.cpp b/src/knx/address_table_object.cpp index c0d8ec8..0902aac 100644 --- a/src/knx/address_table_object.cpp +++ b/src/knx/address_table_object.cpp @@ -50,11 +50,6 @@ uint16_t AddressTableObject::getTsap(uint16_t addr) #pragma region SaveRestore -uint8_t* AddressTableObject::save(uint8_t* buffer) -{ - return TableObject::save(buffer); -} - uint8_t* AddressTableObject::restore(uint8_t* buffer) { buffer = TableObject::restore(buffer); diff --git a/src/knx/address_table_object.h b/src/knx/address_table_object.h index c46ba07..95bcf83 100644 --- a/src/knx/address_table_object.h +++ b/src/knx/address_table_object.h @@ -19,8 +19,8 @@ class AddressTableObject : public TableObject */ AddressTableObject(Memory& memory); void readProperty(PropertyID id, uint32_t start, uint32_t& count, uint8_t* data); - uint8_t* save(uint8_t* buffer); uint8_t* restore(uint8_t* buffer); + /** * returns the number of group addresses of the object. */ diff --git a/src/knx/application_program_object.cpp b/src/knx/application_program_object.cpp index 4c183b6..30e7a5a 100644 --- a/src/knx/application_program_object.cpp +++ b/src/knx/application_program_object.cpp @@ -110,3 +110,7 @@ PropertyDescription* ApplicationProgramObject::propertyDescriptions() return _propertyDescriptions; } +uint16_t ApplicationProgramObject::saveSize() +{ + return TableObject::saveSize() + 5; +} \ No newline at end of file diff --git a/src/knx/application_program_object.h b/src/knx/application_program_object.h index abd8e04..26822f1 100644 --- a/src/knx/application_program_object.h +++ b/src/knx/application_program_object.h @@ -15,6 +15,7 @@ class ApplicationProgramObject : public TableObject uint32_t getInt(uint32_t addr); uint8_t* save(uint8_t* buffer); uint8_t* restore(uint8_t* buffer); + uint16_t saveSize(); protected: uint8_t propertyCount(); diff --git a/src/knx/association_table_object.cpp b/src/knx/association_table_object.cpp index b640219..b5ae024 100644 --- a/src/knx/association_table_object.cpp +++ b/src/knx/association_table_object.cpp @@ -44,11 +44,6 @@ uint16_t AssociationTableObject::getASAP(uint16_t idx) return ntohs(_tableData[2 * idx + 2]); } -uint8_t* AssociationTableObject::save(uint8_t* buffer) -{ - return TableObject::save(buffer); -} - uint8_t* AssociationTableObject::restore(uint8_t* buffer) { buffer = TableObject::restore(buffer); diff --git a/src/knx/association_table_object.h b/src/knx/association_table_object.h index fcf45cd..df0c4ef 100644 --- a/src/knx/association_table_object.h +++ b/src/knx/association_table_object.h @@ -8,7 +8,6 @@ class AssociationTableObject : public TableObject AssociationTableObject(Memory& memory); void readProperty(PropertyID id, uint32_t start, uint32_t& count, uint8_t* data); - uint8_t* save(uint8_t* buffer); uint8_t* restore(uint8_t* buffer); int32_t translateAsap(uint16_t asap); diff --git a/src/knx/bau_systemB.cpp b/src/knx/bau_systemB.cpp index 75d0938..0cb2097 100644 --- a/src/knx/bau_systemB.cpp +++ b/src/knx/bau_systemB.cpp @@ -11,7 +11,7 @@ enum NmReadSerialNumberType NM_Read_SerialNumber_By_ManufacturerSpecific = 0xFE, }; -BauSystemB::BauSystemB(Platform& platform): _memory(platform), _addrTable(_memory), +BauSystemB::BauSystemB(Platform& platform): _memory(platform, _deviceObj), _addrTable(_memory), _assocTable(_memory), _groupObjTable(_memory), _appProgram(_memory), _platform(platform), _appLayer(_assocTable, *this), _transLayer(_appLayer, _addrTable), _netLayer(_transLayer) diff --git a/src/knx/device_object.cpp b/src/knx/device_object.cpp index e9d0905..69ad3e8 100644 --- a/src/knx/device_object.cpp +++ b/src/knx/device_object.cpp @@ -295,3 +295,8 @@ PropertyDescription* DeviceObject::propertyDescriptions() { return _propertyDescriptions; } + +uint16_t DeviceObject::saveSize() +{ + return 4; +} \ No newline at end of file diff --git a/src/knx/device_object.h b/src/knx/device_object.h index 35704f1..725b5f1 100644 --- a/src/knx/device_object.h +++ b/src/knx/device_object.h @@ -10,6 +10,7 @@ public: uint8_t propertySize(PropertyID id); uint8_t* save(uint8_t* buffer); uint8_t* restore(uint8_t* buffer); + uint16_t saveSize(); void readPropertyDescription(uint8_t propertyId, uint8_t& propertyIndex, bool& writeEnable, uint8_t& type, uint16_t& numberOfElements, uint8_t& access); diff --git a/src/knx/group_object_table_object.cpp b/src/knx/group_object_table_object.cpp index 3e159d6..0ab929a 100644 --- a/src/knx/group_object_table_object.cpp +++ b/src/knx/group_object_table_object.cpp @@ -41,13 +41,6 @@ GroupObject& GroupObjectTableObject::get(uint16_t asap) return _groupObjects[asap - 1]; } - -uint8_t* GroupObjectTableObject::save(uint8_t* buffer) -{ - return TableObject::save(buffer); -} - - uint8_t* GroupObjectTableObject::restore(uint8_t* buffer) { buffer = TableObject::restore(buffer); diff --git a/src/knx/group_object_table_object.h b/src/knx/group_object_table_object.h index 4fb7a62..088474f 100644 --- a/src/knx/group_object_table_object.h +++ b/src/knx/group_object_table_object.h @@ -16,11 +16,10 @@ class GroupObjectTableObject : public TableObject GroupObject& nextUpdatedObject(bool& valid); void groupObjects(GroupObject* objs, uint16_t size); - virtual uint8_t* save(uint8_t* buffer); - virtual uint8_t* restore(uint8_t* buffer); + uint8_t* restore(uint8_t* buffer); protected: - virtual void beforeStateChange(LoadState& newState); + void beforeStateChange(LoadState& newState); uint8_t propertyCount(); PropertyDescription* propertyDescriptions(); diff --git a/src/knx/ip_parameter_object.cpp b/src/knx/ip_parameter_object.cpp index d35883e..3a169a2 100644 --- a/src/knx/ip_parameter_object.cpp +++ b/src/knx/ip_parameter_object.cpp @@ -320,4 +320,9 @@ uint8_t IpParameterObject::propertyCount() PropertyDescription* IpParameterObject::propertyDescriptions() { return _propertyDescriptions; -} \ No newline at end of file +} + +uint16_t IpParameterObject::saveSize() +{ + return 51; +} diff --git a/src/knx/ip_parameter_object.h b/src/knx/ip_parameter_object.h index 4b23e34..819d55b 100644 --- a/src/knx/ip_parameter_object.h +++ b/src/knx/ip_parameter_object.h @@ -14,6 +14,7 @@ class IpParameterObject : public InterfaceObject uint8_t* save(uint8_t* buffer); uint8_t* restore(uint8_t* buffer); + uint16_t saveSize(); uint32_t multicastAddress() const; uint8_t ttl() const { return _ttl; } diff --git a/src/knx/memory.cpp b/src/knx/memory.cpp index 17ebc70..821ee6b 100644 --- a/src/knx/memory.cpp +++ b/src/knx/memory.cpp @@ -1,7 +1,9 @@ #include "memory.h" #include +#include "bits.h" -Memory::Memory(Platform & platform): _platform(platform) +Memory::Memory(Platform& platform, DeviceObject& deviceObject) + : _platform(platform), _deviceObject(deviceObject) { } @@ -34,18 +36,16 @@ void Memory::readMemory() void Memory::writeMemory() { - _data[0] = 0x00; - _data[1] = 0xAD; - _data[2] = 0xAF; - _data[3] = 0xFE; + uint8_t* buffer = _data; + buffer = pushWord(_deviceObject.manufacturerId(), buffer); + buffer = pushByteArray(_deviceObject.hardwareType(), 6, buffer); + buffer = pushWord(_deviceObject.version(), buffer); - uint8_t* buffer = _data + 4; int size = _saveCount; for (int i = 0; i < size; i++) { - SaveRestore* saveRestore = dynamic_cast(_saveRestores[i]); - if(saveRestore) - buffer = saveRestore->save(buffer); + // TODO: Hande TableObject correctly, i.e. save the size of the buffer somewhere to, so that we can rebuild the usedList and freeList + buffer = _saveRestores[i]->save(buffer); } _platform.commitToEeprom(); _modified = false; @@ -63,13 +63,71 @@ void Memory::addSaveRestore(SaveRestore * obj) uint8_t* Memory::allocMemory(size_t size) { - return _platform.allocMemory(size); + // always allocate aligned to 32 bit + size = (size + 3) & ~0x3; + + MemoryBlock* freeBlock = _freeList; + MemoryBlock* blockToUse = 0; + + // find the smallest possible block that is big enough + while (freeBlock) + { + if (freeBlock->size >= size) + { + if (blockToUse != 0 && (blockToUse->size - size) > (freeBlock->size - size)) + blockToUse = freeBlock; + } + freeBlock = freeBlock->next; + } + if (!blockToUse) + { + println("No available non volatile memory!"); + _platform.fatalError(); + } + + if (blockToUse->size == size) + { + // use whole block + removeFromFreeList(blockToUse); + addToUsedList(blockToUse); + return blockToUse->address; + } + else + { + // split block + MemoryBlock* newBlock = new MemoryBlock(); + newBlock->address = blockToUse->address; + newBlock->size = size; + addToUsedList(newBlock); + + blockToUse->address += size; + blockToUse->size -= size; + + return newBlock->address; + } } void Memory::freeMemory(uint8_t* ptr) { - return _platform.freeMemory(ptr); + MemoryBlock* block = _usedList; + MemoryBlock* found = 0; + while (_usedList) + { + if (block->address == ptr) + { + found = block; + break; + } + block = block->next; + } + if(!found) + { + println("freeMemory for not used pointer called"); + _platform.fatalError(); + } + removeFromUsedList(block); + addToFreeList(block); } void Memory::writeMemory(uint32_t relativeAddress, size_t size, uint8_t* data) @@ -81,11 +139,110 @@ void Memory::writeMemory(uint32_t relativeAddress, size_t size, uint8_t* data) uint8_t* Memory::toAbsolute(uint32_t relativeAddress) { - return _platform.memoryReference() + (ptrdiff_t)relativeAddress; + return _data + (ptrdiff_t)relativeAddress; } uint32_t Memory::toRelative(uint8_t* absoluteAddress) { - return absoluteAddress - _platform.memoryReference(); + return absoluteAddress - _data; +} + +MemoryBlock* Memory::removeFromList(MemoryBlock* head, MemoryBlock* item) +{ + if (head == item) + { + MemoryBlock* newHead = head->next; + head->next = 0; + return newHead; + } + + if (!head || !item) + { + println("invalid parameters of Memory::removeFromList"); + _platform.fatalError(); + } + + bool found = false; + while (head) + { + if (head->next == item) + { + found = true; + head->next = item->next; + break; + } + head = head->next; + } + + if (!found) + { + println("tried to remove block from list not in it"); + _platform.fatalError(); + } + item->next = 0; + return head; +} + +void Memory::removeFromFreeList(MemoryBlock* block) +{ + _freeList = removeFromList(_freeList, block); +} + + +void Memory::removeFromUsedList(MemoryBlock* block) +{ + _usedList = removeFromList(_usedList, block); +} + + +void Memory::addToUsedList(MemoryBlock* block) +{ + block->next = _usedList; + _usedList = block; +} + + +void Memory::addToFreeList(MemoryBlock* block) +{ + if (_freeList == 0) + { + _freeList = block; + return; + } + + // first insert free block in list + MemoryBlock* current = _freeList; + while (current) + { + if (current->address <= block->address && (block->next == 0 || block->address < current->next->address)) + { + block->next = current->next; + current->next = block; + break; + } + current = current->next; + } + // now check if we can merge the blocks + // first current an block + if ((current->address + current->size) == block->address) + { + current->size += block->size; + current->next = block->next; + delete block; + // check further if now current can be merged with current->next + block = current; + } + + // if block is the last one, we are done + if (block->next == 0) + return; + + // now check block and block->next + if ((block->address + block->size) == block->next->address) + { + block->size += block->next->size; + block->next = block->next->next; + delete block->next; + } } diff --git a/src/knx/memory.h b/src/knx/memory.h index 505048a..f0c40f4 100644 --- a/src/knx/memory.h +++ b/src/knx/memory.h @@ -3,13 +3,21 @@ #include #include "save_restore.h" #include "platform.h" +#include "device_object.h" #define MAXSAVE 10 +typedef struct _memoryBlock +{ + uint8_t* address; + size_t size; + struct _memoryBlock* next; +} MemoryBlock; + class Memory { public: - Memory(Platform& platform); + Memory(Platform& platform, DeviceObject& deviceObject); void memoryModified(); bool isMemoryModified(); void readMemory(); @@ -23,9 +31,18 @@ public: uint32_t toRelative(uint8_t* absoluteAddress); private: + void removeFromFreeList(MemoryBlock* block); + void addToUsedList(MemoryBlock* block); + void removeFromUsedList(MemoryBlock* block); + void addToFreeList(MemoryBlock* block); + MemoryBlock* removeFromList(MemoryBlock* head, MemoryBlock* item); + Platform& _platform; + DeviceObject& _deviceObject; bool _modified = false; - Restore* _saveRestores[MAXSAVE] = {0}; + SaveRestore* _saveRestores[MAXSAVE] = {0}; int _saveCount = 0; uint8_t* _data = 0; + MemoryBlock* _freeList = 0; + MemoryBlock* _usedList = 0; }; diff --git a/src/knx/platform.h b/src/knx/platform.h index 5a082aa..50d9bef 100644 --- a/src/knx/platform.h +++ b/src/knx/platform.h @@ -8,19 +8,23 @@ class Platform { public: Platform(); + // ip config virtual uint32_t currentIpAddress() = 0; virtual uint32_t currentSubnetMask() = 0; virtual uint32_t currentDefaultGateway() = 0; virtual void macAddress(uint8_t* data) = 0; + // basic stuff virtual void restart() = 0; virtual void fatalError() = 0; + //multicast socket virtual void setupMultiCast(uint32_t addr, uint16_t port) = 0; virtual void closeMultiCast() = 0; virtual bool sendBytes(uint8_t* buffer, uint16_t len) = 0; virtual int readBytes(uint8_t* buffer, uint16_t maxLen) = 0; - + + //UART virtual void setupUart() = 0; virtual void closeUart() = 0; virtual int uartAvailable() = 0; @@ -29,10 +33,19 @@ class Platform virtual int readUart() = 0; virtual size_t readBytesUart(uint8_t* buffer, size_t length) = 0; + // SPI virtual void setupSpi() = 0; virtual void closeSpi() = 0; virtual int readWriteSpi (uint8_t *data, size_t len) = 0; - +#if 0 + // Flash memory + virtual size_t flashEraseBlockSize(); // in pages + virtual size_t flashPageSize(); // in bytes + virtual uint8_t* userFlashStart(); // start of user flash aligned to start of an erase block + virtual size_t userFlashSizeEraseBlocks(); // in eraseBlocks + virtual void flashErase(uint16_t eraseBlockNum); //relativ to userFlashStart + virtual void flashWritePage(uint16_t pageNumber, uint8_t* data); //write a single page to flash (pageNumber relative to userFashStart +#endif virtual uint8_t* getEepromBuffer(uint16_t size) = 0; virtual void commitToEeprom() = 0; diff --git a/src/knx/restore.h b/src/knx/restore.h deleted file mode 100644 index fe8ca41..0000000 --- a/src/knx/restore.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#pragma once -#include - -/** - * Interface for classes that can restore data from a buffer. - */ -class Restore -{ - public: - /** - * This method is called when the object should restore its state from the buffer. - * - * @param buffer The buffer the object should restore its state from. - * - * @return The buffer plus the size of the object state. The next object will use this value as - * the start of its buffer. - */ - virtual uint8_t* restore(uint8_t* buffer) = 0; -}; \ No newline at end of file diff --git a/src/knx/rf_medium_object.cpp b/src/knx/rf_medium_object.cpp index 2e96d9d..3a55efa 100644 --- a/src/knx/rf_medium_object.cpp +++ b/src/knx/rf_medium_object.cpp @@ -98,6 +98,11 @@ uint8_t* RfMediumObject::restore(uint8_t* buffer) return buffer; } +uint16_t RfMediumObject::saveSize() +{ + return 6; +} + uint8_t* RfMediumObject::rfDomainAddress() { return _rfDomainAddress; diff --git a/src/knx/rf_medium_object.h b/src/knx/rf_medium_object.h index 57c0a2e..315cf11 100644 --- a/src/knx/rf_medium_object.h +++ b/src/knx/rf_medium_object.h @@ -10,6 +10,7 @@ public: uint8_t propertySize(PropertyID id); uint8_t* save(uint8_t* buffer); uint8_t* restore(uint8_t* buffer); + uint16_t saveSize(); void readPropertyDescription(uint8_t propertyId, uint8_t& propertyIndex, bool& writeEnable, uint8_t& type, uint16_t& numberOfElements, uint8_t& access); uint8_t* rfDomainAddress(); @@ -22,6 +23,4 @@ private: uint8_t _rfDomainAddress[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // see KNX RF S-Mode AN160 p.11 uint8_t _rfDiagSourceAddressFilterTable[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; uint8_t _rfDiagLinkBudgetTable[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; - - }; \ No newline at end of file diff --git a/src/knx/save_restore.h b/src/knx/save_restore.h index d36d563..7bc1c1c 100644 --- a/src/knx/save_restore.h +++ b/src/knx/save_restore.h @@ -1,11 +1,10 @@ #pragma once #include -#include "restore.h" /** * Interface for classes that can save and restore data from a buffer. */ -class SaveRestore : public Restore +class SaveRestore { public: /** @@ -17,4 +16,17 @@ class SaveRestore : public Restore * the start of its buffer. */ virtual uint8_t* save(uint8_t* buffer) = 0; + /** + * This method is called when the object should restore its state from the buffer. + * + * @param buffer The buffer the object should restore its state from. + * + * @return The buffer plus the size of the object state. The next object will use this value as + * the start of its buffer. + */ + virtual uint8_t* restore(uint8_t* buffer) = 0; + /** + * @return The number of byte the object needs to save its state. + */ + virtual uint16_t saveSize() = 0; }; \ No newline at end of file diff --git a/src/knx/table_object.cpp b/src/knx/table_object.cpp index 0e3fc12..64f816a 100644 --- a/src/knx/table_object.cpp +++ b/src/knx/table_object.cpp @@ -86,8 +86,11 @@ uint8_t* TableObject::save(uint8_t* buffer) { buffer = pushByte(_state, buffer); buffer = pushByte(_errorCode, buffer); - buffer = pushInt(_size, buffer); - buffer = pushByteArray(_data, _size, buffer); + + if (_data) + buffer = pushInt(_memory.toRelative(_data), buffer); + else + buffer = pushInt(0, buffer); return buffer; } @@ -102,18 +105,14 @@ uint8_t* TableObject::restore(uint8_t* buffer) _state = (LoadState)state; _errorCode = (ErrorCode)errorCode; - buffer = popInt(_size, buffer); + uint32_t relativeAddress = 0; + buffer = popInt(relativeAddress, buffer); - if (_data) - _memory.freeMemory(_data); - - if (_size > 0) - _data = _memory.allocMemory(_size); + if (relativeAddress != 0) + _data = _memory.toAbsolute(relativeAddress); else _data = 0; - buffer = popByteArray(_data, _size, buffer); - return buffer; } @@ -128,7 +127,6 @@ bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte) { _memory.freeMemory(_data); _data = 0; - _size = 0; } if (size == 0) @@ -138,8 +136,6 @@ bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte) if (!_data) return false; - _size = size; - if (doFill) memset(_data, fillByte, size); @@ -277,12 +273,12 @@ uint8_t* TableObject::data() return _data; } -uint32_t TableObject::size() -{ - return _size; -} - void TableObject::errorCode(ErrorCode errorCode) { _errorCode = errorCode; -} \ No newline at end of file +} + +uint16_t TableObject::saveSize() +{ + return 6; +} diff --git a/src/knx/table_object.h b/src/knx/table_object.h index 8fd64d6..7724c87 100644 --- a/src/knx/table_object.h +++ b/src/knx/table_object.h @@ -27,6 +27,7 @@ public: LoadState loadState(); virtual uint8_t* save(uint8_t* buffer); virtual uint8_t* restore(uint8_t* buffer); + uint16_t saveSize(); protected: /** * This method is called before the interface object enters a new ::LoadState. @@ -40,10 +41,6 @@ protected: * must not be freed. */ uint8_t* data(); - /** - * returns the size of the internal data of the interface object int byte. - */ - uint32_t size(); /** * Set the reason for a state change failure. */ @@ -69,6 +66,5 @@ protected: LoadState _state = LS_UNLOADED; Memory& _memory; uint8_t *_data = 0; - uint32_t _size = 0; ErrorCode _errorCode = E_NO_FAULT; }; diff --git a/src/knx_facade.h b/src/knx_facade.h index ab4c0a4..0fed8e9 100644 --- a/src/knx_facade.h +++ b/src/knx_facade.h @@ -285,6 +285,7 @@ template class KnxFacade : private SaveRestore saveRestoreCallback _restoreCallback = 0; bool _toogleProgMode = false; bool _progLedState = false; + uint16_t _saveSize = 0; uint8_t* save(uint8_t* buffer) { @@ -301,6 +302,16 @@ template class KnxFacade : private SaveRestore return buffer; } + + uint16_t saveSize() + { + return _saveSize; + } + + void saveSize(uint16_t size) + { + _saveSize = size; + } }; #ifdef ARDUINO_ARCH_SAMD