-add saveLength to SaveRestore

-undo split of Restore from SaveRestore
-add some dynamic memory management to memory-class
This commit is contained in:
Thomas Kunze 2019-11-03 22:09:22 +01:00
parent 2770f5eaa9
commit 8421279d53
25 changed files with 305 additions and 90 deletions

View File

@ -78,6 +78,7 @@
<ClInclude Include="..\src\knx\association_table_object.h" />
<ClInclude Include="..\src\knx\bau.h" />
<ClInclude Include="..\src\knx\bau07B0.h" />
<ClInclude Include="..\src\knx\bau27B0.h" />
<ClInclude Include="..\src\knx\bau57B0.h" />
<ClInclude Include="..\src\knx\bau_systemB.h" />
<ClInclude Include="..\src\knx\bits.h" />
@ -98,6 +99,9 @@
<ClInclude Include="..\src\knx\npdu.h" />
<ClInclude Include="..\src\knx\platform.h" />
<ClInclude Include="..\src\knx\property_types.h" />
<ClInclude Include="..\src\knx\rf_data_link_layer.h" />
<ClInclude Include="..\src\knx\rf_medium_object.h" />
<ClInclude Include="..\src\knx\rf_physical_layer.h" />
<ClInclude Include="..\src\knx\save_restore.h" />
<ClInclude Include="..\src\knx\table_object.h" />
<ClInclude Include="..\src\knx\tpdu.h" />
@ -121,6 +125,7 @@
<ClCompile Include="..\src\knx\association_table_object.cpp" />
<ClCompile Include="..\src\knx\bau.cpp" />
<ClCompile Include="..\src\knx\bau07B0.cpp" />
<ClCompile Include="..\src\knx\bau27B0.cpp" />
<ClCompile Include="..\src\knx\bau57B0.cpp" />
<ClCompile Include="..\src\knx\bau_systemB.cpp" />
<ClCompile Include="..\src\knx\bits.cpp" />
@ -139,6 +144,9 @@
<ClCompile Include="..\src\knx\network_layer.cpp" />
<ClCompile Include="..\src\knx\npdu.cpp" />
<ClCompile Include="..\src\knx\platform.cpp" />
<ClCompile Include="..\src\knx\rf_data_link_layer.cpp" />
<ClCompile Include="..\src\knx\rf_medium_object.cpp" />
<ClCompile Include="..\src\knx\rf_physical_layer.cpp" />
<ClCompile Include="..\src\knx\table_object.cpp" />
<ClCompile Include="..\src\knx\tpdu.cpp" />
<ClCompile Include="..\src\knx\tpuart_data_link_layer.cpp" />

View File

@ -137,6 +137,18 @@
<ClInclude Include="..\src\knx\knx_value.h">
<Filter>Header files\knx</Filter>
</ClInclude>
<ClInclude Include="..\src\knx\bau27B0.h">
<Filter>Header files\knx</Filter>
</ClInclude>
<ClInclude Include="..\src\knx\rf_data_link_layer.h">
<Filter>Header files\knx</Filter>
</ClInclude>
<ClInclude Include="..\src\knx\rf_medium_object.h">
<Filter>Header files\knx</Filter>
</ClInclude>
<ClInclude Include="..\src\knx\rf_physical_layer.h">
<Filter>Header files\knx</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\knx\address_table_object.cpp">
@ -235,5 +247,17 @@
<ClCompile Include="..\src\knx\knx_value.cpp">
<Filter>Source files\knx</Filter>
</ClCompile>
<ClCompile Include="..\src\knx\bau27B0.cpp">
<Filter>Source files\knx</Filter>
</ClCompile>
<ClCompile Include="..\src\knx\rf_data_link_layer.cpp">
<Filter>Source files\knx</Filter>
</ClCompile>
<ClCompile Include="..\src\knx\rf_medium_object.cpp">
<Filter>Source files\knx</Filter>
</ClCompile>
<ClCompile Include="..\src\knx\rf_physical_layer.cpp">
<Filter>Source files\knx</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -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);

View File

@ -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.
*/

View File

@ -110,3 +110,7 @@ PropertyDescription* ApplicationProgramObject::propertyDescriptions()
return _propertyDescriptions;
}
uint16_t ApplicationProgramObject::saveSize()
{
return TableObject::saveSize() + 5;
}

View File

@ -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();

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -295,3 +295,8 @@ PropertyDescription* DeviceObject::propertyDescriptions()
{
return _propertyDescriptions;
}
uint16_t DeviceObject::saveSize()
{
return 4;
}

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -320,4 +320,9 @@ uint8_t IpParameterObject::propertyCount()
PropertyDescription* IpParameterObject::propertyDescriptions()
{
return _propertyDescriptions;
}
}
uint16_t IpParameterObject::saveSize()
{
return 51;
}

View File

@ -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; }

View File

@ -1,7 +1,9 @@
#include "memory.h"
#include <string.h>
#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<SaveRestore*>(_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;
}
}

View File

@ -3,13 +3,21 @@
#include <stdint.h>
#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;
};

View File

@ -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;

View File

@ -1,21 +0,0 @@
#pragma once
#pragma once
#include <stdint.h>
/**
* 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;
};

View File

@ -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;

View File

@ -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,};
};

View File

@ -1,11 +1,10 @@
#pragma once
#include <stdint.h>
#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;
};

View File

@ -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;
}
}
uint16_t TableObject::saveSize()
{
return 6;
}

View File

@ -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;
};

View File

@ -285,6 +285,7 @@ template <class P, class B> 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 P, class B> class KnxFacade : private SaveRestore
return buffer;
}
uint16_t saveSize()
{
return _saveSize;
}
void saveSize(uint16_t size)
{
_saveSize = size;
}
};
#ifdef ARDUINO_ARCH_SAMD