mirror of
https://github.com/thelsing/knx.git
synced 2025-08-13 13:46:20 +02:00
-change memory management
This commit is contained in:
parent
29ef91f2e0
commit
afe3ae7936
@ -84,15 +84,36 @@ int Esp32Platform::readBytes(uint8_t * buffer, uint16_t maxLen)
|
||||
return len;
|
||||
}
|
||||
|
||||
uint8_t * Esp32Platform::getEepromBuffer(uint16_t size)
|
||||
bool Esp32Platform::writeNVMemory(uint32_t addr,uint8_t data)
|
||||
{
|
||||
EEPROM.begin(size);
|
||||
return EEPROM.getDataPtr();
|
||||
*((uint8_t*)addr) = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Esp32Platform::commitToEeprom()
|
||||
uint8_t Esp32Platform::readNVMemory(uint32_t addr)
|
||||
{
|
||||
return *((uint8_t*)addr);
|
||||
}
|
||||
|
||||
uint32_t Esp32Platform::allocNVMemory(uint32_t size,uint32_t ID)
|
||||
{
|
||||
if(size > EEPROM_EMULATION_SIZE)
|
||||
fatalError();
|
||||
return (uint32_t)EEPROM.getDataPtr();
|
||||
}
|
||||
|
||||
uint32_t Esp32Platform::reloadNVMemory(uint32_t ID)
|
||||
{
|
||||
EEPROM.begin(1024);
|
||||
return (uint32_t)EEPROM.getDataPtr();
|
||||
}
|
||||
|
||||
void Esp32Platform::finishNVMemory()
|
||||
{
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
void Esp32Platform::freeNVMemory(uint32_t ID)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
@ -28,8 +28,12 @@ public:
|
||||
int readBytes(uint8_t* buffer, uint16_t maxLen) override;
|
||||
|
||||
//memory
|
||||
uint8_t* getEepromBuffer(uint16_t size);
|
||||
void commitToEeprom();
|
||||
bool writeNVMemory(uint32_t addr,uint8_t data);
|
||||
uint8_t readNVMemory(uint32_t addr);
|
||||
uint32_t allocNVMemory(uint32_t size,uint32_t ID);
|
||||
uint32_t reloadNVMemory(uint32_t ID);
|
||||
void finishNVMemory();
|
||||
void freeNVMemory(uint32_t ID);
|
||||
private:
|
||||
WiFiUDP _udp;
|
||||
};
|
||||
|
@ -85,14 +85,36 @@ int EspPlatform::readBytes(uint8_t * buffer, uint16_t maxLen)
|
||||
return len;
|
||||
}
|
||||
|
||||
uint8_t * EspPlatform::getEepromBuffer(uint16_t size)
|
||||
bool EspPlatform::writeNVMemory(uint32_t addr,uint8_t data)
|
||||
{
|
||||
EEPROM.begin(size);
|
||||
return EEPROM.getDataPtr();
|
||||
*((uint8_t*)addr) = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
void EspPlatform::commitToEeprom()
|
||||
uint8_t EspPlatform::readNVMemory(uint32_t addr)
|
||||
{
|
||||
return *((uint8_t*)addr);
|
||||
}
|
||||
|
||||
uint32_t EspPlatform::allocNVMemory(uint32_t size,uint32_t ID)
|
||||
{
|
||||
if(size > EEPROM_EMULATION_SIZE)
|
||||
fatalError();
|
||||
return (uint32_t)EEPROM.getDataPtr();
|
||||
}
|
||||
|
||||
uint32_t EspPlatform::reloadNVMemory(uint32_t ID)
|
||||
{
|
||||
EEPROM.begin(1024);
|
||||
return (uint32_t)EEPROM.getDataPtr();
|
||||
}
|
||||
|
||||
void EspPlatform::finishNVMemory()
|
||||
{
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
void EspPlatform::freeNVMemory(uint32_t ID)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
@ -29,8 +29,12 @@ class EspPlatform : public ArduinoPlatform
|
||||
int readBytes(uint8_t* buffer, uint16_t maxLen) override;
|
||||
|
||||
//memory
|
||||
uint8_t* getEepromBuffer(uint16_t size);
|
||||
void commitToEeprom();
|
||||
bool writeNVMemory(uint32_t addr,uint8_t data);
|
||||
uint8_t readNVMemory(uint32_t addr);
|
||||
uint32_t allocNVMemory(uint32_t size,uint32_t ID);
|
||||
uint32_t reloadNVMemory(uint32_t ID);
|
||||
void finishNVMemory();
|
||||
void freeNVMemory(uint32_t ID);
|
||||
private:
|
||||
WiFiUDP _udp;
|
||||
};
|
||||
|
@ -74,6 +74,35 @@ uint32_t ApplicationProgramObject::getInt(uint32_t addr)
|
||||
return ::getInt(TableObject::data() + addr);
|
||||
}
|
||||
|
||||
uint32_t ApplicationProgramObject::size(){
|
||||
return sizeof(_programVersion)+TableObject::size();
|
||||
}
|
||||
|
||||
|
||||
uint8_t* ApplicationProgramObject::save()
|
||||
{
|
||||
if(TableObject::data() == NULL)
|
||||
return NULL;
|
||||
|
||||
uint8_t* buffer;
|
||||
uint32_t addr =(uint32_t)(TableObject::data() - sizeof(_programVersion) - TableObject::sizeMetadata());
|
||||
if(TableObject::_platform.NVMemoryType() == internalFlash)
|
||||
buffer = new uint8_t[sizeof(_programVersion)];
|
||||
else
|
||||
buffer = (uint8_t*)addr;
|
||||
|
||||
pushByteArray(_programVersion, sizeof(_programVersion), buffer);
|
||||
|
||||
if(TableObject::_platform.NVMemoryType() == internalFlash){
|
||||
for(uint32_t i=0;i<sizeof(_programVersion);i++)
|
||||
TableObject::_platform.writeNVMemory(addr+i, buffer[i]);
|
||||
|
||||
free (buffer);
|
||||
}
|
||||
|
||||
return TableObject::save();
|
||||
}
|
||||
|
||||
uint8_t* ApplicationProgramObject::save(uint8_t* buffer)
|
||||
{
|
||||
buffer = pushByteArray(_programVersion, 5, buffer);
|
||||
@ -83,8 +112,8 @@ uint8_t* ApplicationProgramObject::save(uint8_t* buffer)
|
||||
|
||||
uint8_t* ApplicationProgramObject::restore(uint8_t* buffer)
|
||||
{
|
||||
TableObject::_dataComplete = buffer;
|
||||
buffer = popByteArray(_programVersion, 5, buffer);
|
||||
|
||||
return TableObject::restore(buffer);
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,9 @@ class ApplicationProgramObject : public TableObject
|
||||
uint16_t getWord(uint32_t addr);
|
||||
uint32_t getInt(uint32_t addr);
|
||||
uint8_t* save(uint8_t* buffer);
|
||||
uint8_t* save();
|
||||
uint8_t* restore(uint8_t* buffer);
|
||||
uint32_t size();
|
||||
|
||||
protected:
|
||||
uint8_t propertyCount();
|
||||
|
@ -5,7 +5,7 @@
|
||||
BauSystemB::BauSystemB(Platform& platform): _memory(platform), _addrTable(platform),
|
||||
_assocTable(platform), _groupObjTable(platform), _appProgram(platform),
|
||||
_platform(platform), _appLayer(_assocTable, *this),
|
||||
_transLayer(_appLayer, _addrTable), _netLayer(_transLayer)
|
||||
_transLayer(_appLayer, _addrTable), _netLayer(_transLayer), _deviceObj(platform)
|
||||
{
|
||||
_appLayer.transportLayer(_transLayer);
|
||||
_transLayer.networkLayer(_netLayer);
|
||||
@ -139,7 +139,13 @@ void BauSystemB::deviceDescriptorReadIndication(Priority priority, HopCountType
|
||||
void BauSystemB::memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
|
||||
uint16_t memoryAddress, uint8_t * data)
|
||||
{
|
||||
memcpy(_platform.memoryReference() + memoryAddress, data, number);
|
||||
if(_platform.NVMemoryType() == internalFlash){
|
||||
for(uint8_t i=0;i<number;i++)
|
||||
_platform.writeNVMemory((uint32_t)_platform.memoryReference() + memoryAddress+i, data[i]);
|
||||
}
|
||||
else
|
||||
memcpy(_platform.memoryReference() + memoryAddress, data, number);
|
||||
|
||||
_memory.memoryModified();
|
||||
|
||||
if (_deviceObj.verifyMode())
|
||||
@ -149,8 +155,17 @@ void BauSystemB::memoryWriteIndication(Priority priority, HopCountType hopType,
|
||||
void BauSystemB::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
|
||||
uint16_t memoryAddress)
|
||||
{
|
||||
if(_platform.NVMemoryType() == internalFlash){
|
||||
uint8_t* buffer = new uint8_t[number];
|
||||
for(uint8_t i=0;i<number;i++)
|
||||
buffer[i] = _platform.readNVMemory((uint32_t)_platform.memoryReference() + memoryAddress+i);
|
||||
|
||||
_appLayer.memoryReadResponse(AckRequested, priority, hopType, asap, number, memoryAddress,buffer);
|
||||
}
|
||||
else{
|
||||
_appLayer.memoryReadResponse(AckRequested, priority, hopType, asap, number, memoryAddress,
|
||||
_platform.memoryReference() + memoryAddress);
|
||||
_platform.memoryReference() + memoryAddress);
|
||||
}
|
||||
}
|
||||
|
||||
void BauSystemB::restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap)
|
||||
@ -167,13 +182,27 @@ void BauSystemB::authorizeIndication(Priority priority, HopCountType hopType, ui
|
||||
|
||||
void BauSystemB::userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint32_t memoryAddress)
|
||||
{
|
||||
_appLayer.userMemoryReadResponse(AckRequested, priority, hopType, asap, number, memoryAddress,
|
||||
_platform.memoryReference() + memoryAddress);
|
||||
if(_platform.NVMemoryType() == internalFlash){
|
||||
uint8_t* buffer = new uint8_t[number];
|
||||
for(uint8_t i=0;i<number;i++)
|
||||
buffer[i] = _platform.readNVMemory((uint32_t)_platform.memoryReference() + memoryAddress+i);
|
||||
_appLayer.userMemoryReadResponse(AckRequested, priority, hopType, asap, number, memoryAddress,buffer);
|
||||
}
|
||||
else{
|
||||
_appLayer.userMemoryReadResponse(AckRequested, priority, hopType, asap, number, memoryAddress,
|
||||
_platform.memoryReference() + memoryAddress);
|
||||
}
|
||||
}
|
||||
|
||||
void BauSystemB::userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint32_t memoryAddress, uint8_t* data)
|
||||
{
|
||||
memcpy(_platform.memoryReference() + memoryAddress, data, number);
|
||||
if(_platform.NVMemoryType() == internalFlash){
|
||||
for(uint8_t i=0;i<number;i++)
|
||||
_platform.writeNVMemory((uint32_t)_platform.memoryReference() + memoryAddress+i, data[i]);
|
||||
}
|
||||
else{
|
||||
memcpy(_platform.memoryReference() + memoryAddress, data, number);
|
||||
}
|
||||
_memory.memoryModified();
|
||||
|
||||
if (_deviceObj.verifyMode())
|
||||
|
@ -2,6 +2,15 @@
|
||||
#include "device_object.h"
|
||||
#include "bits.h"
|
||||
|
||||
#define METADATA_SIZE (sizeof(_deviceControl)+sizeof(_routingCount)+sizeof(_ownAddress))
|
||||
|
||||
DeviceObject::DeviceObject(Platform& platform): _platform(platform)
|
||||
{
|
||||
for(int i = 0; i < 10; ++i)
|
||||
_orderNumber[i] = 0;
|
||||
for(int i = 0; i < 6; ++i)
|
||||
_hardwareType[i] = 0;
|
||||
}
|
||||
void DeviceObject::readProperty(PropertyID propertyId, uint32_t start, uint32_t& count, uint8_t* data)
|
||||
{
|
||||
switch (propertyId)
|
||||
@ -106,6 +115,32 @@ uint8_t DeviceObject::propertySize(PropertyID id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t DeviceObject::size(){
|
||||
return METADATA_SIZE;
|
||||
}
|
||||
|
||||
uint8_t* DeviceObject::save()
|
||||
{
|
||||
uint8_t* buffer = new uint8_t[METADATA_SIZE];
|
||||
|
||||
buffer = pushByte(_deviceControl, buffer);
|
||||
buffer = pushByte(_routingCount, buffer);
|
||||
buffer = pushWord(_ownAddress, buffer);
|
||||
buffer -= METADATA_SIZE;
|
||||
|
||||
if(_platform.NVMemoryType() == internalFlash){
|
||||
_platform.freeNVMemory(_ID);
|
||||
uint32_t addr = _platform.allocNVMemory(METADATA_SIZE, _ID);
|
||||
|
||||
for(uint32_t i=0;i<METADATA_SIZE;i++)
|
||||
_platform.writeNVMemory(addr+i, buffer[i]);
|
||||
|
||||
free (buffer);
|
||||
return (uint8_t*)addr;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
uint8_t* DeviceObject::save(uint8_t* buffer)
|
||||
{
|
||||
buffer = pushByte(_deviceControl, buffer);
|
||||
|
@ -1,15 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "interface_object.h"
|
||||
#include "platform.h"
|
||||
|
||||
class DeviceObject: public InterfaceObject
|
||||
{
|
||||
public:
|
||||
DeviceObject(Platform& platform);
|
||||
void readProperty(PropertyID id, uint32_t start, uint32_t& count, uint8_t* data);
|
||||
void writeProperty(PropertyID id, uint8_t start, uint8_t* data, uint8_t count);
|
||||
uint8_t propertySize(PropertyID id);
|
||||
uint8_t* save(uint8_t* buffer);
|
||||
uint8_t* save();
|
||||
uint8_t* restore(uint8_t* buffer);
|
||||
uint32_t size();
|
||||
void readPropertyDescription(uint8_t propertyId, uint8_t& propertyIndex, bool& writeEnable, uint8_t& type, uint16_t& numberOfElements, uint8_t& access);
|
||||
|
||||
|
||||
@ -45,7 +49,8 @@ private:
|
||||
uint16_t _ownAddress = 0;
|
||||
uint16_t _manufacturerId = 0xfa; //Default to KNXA
|
||||
uint32_t _bauNumber = 0;
|
||||
char _orderNumber[10] = "";
|
||||
uint8_t _hardwareType[6] = { 0, 0, 0, 0, 0, 0};
|
||||
char _orderNumber[10];
|
||||
uint8_t _hardwareType[6];
|
||||
uint16_t _version = 0;
|
||||
Platform& _platform;
|
||||
};
|
@ -1810,7 +1810,7 @@ void float16ToPayload(uint8_t* payload, size_t payload_length, int index, double
|
||||
if (wasNegative)
|
||||
mantissa *= -1;
|
||||
|
||||
println(mantissa);
|
||||
// println(mantissa);
|
||||
|
||||
signed16ToPayload(payload, payload_length, index, mantissa, mask);
|
||||
unsigned8ToPayload(payload, payload_length, index, exponent << 3, 0x78 & (mask >> 8));
|
||||
@ -1839,4 +1839,4 @@ void bcdToPayload(uint8_t* payload, size_t payload_length, int index, uint8_t va
|
||||
payload[index / 2] = (payload[index / 2] & 0xF0) | (value & 0x0F);
|
||||
else
|
||||
payload[index / 2] = (payload[index / 2] & 0x0F) | ((value << 4) & 0xF0);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,15 @@
|
||||
|
||||
//224.0.23.12
|
||||
#define DEFAULT_MULTICAST_ADDR 0xE000170C
|
||||
#define METADATA_SIZE ( sizeof(_projectInstallationId) \
|
||||
+sizeof(_ipAssignmentMethod) \
|
||||
+sizeof(_ipCapabilities) \
|
||||
+sizeof(_ipAddress) \
|
||||
+sizeof(_subnetMask) \
|
||||
+sizeof(_defaultGateway) \
|
||||
+sizeof(_multicastAddress) \
|
||||
+sizeof(_ttl) \
|
||||
+sizeof(_friendlyName))
|
||||
|
||||
IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platform): _deviceObject(deviceObject),
|
||||
_platform(platform)
|
||||
@ -146,6 +155,38 @@ uint8_t IpParameterObject::propertySize(PropertyID id)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
uint32_t IpParameterObject::size(){
|
||||
return METADATA_SIZE;
|
||||
}
|
||||
|
||||
uint8_t* IpParameterObject::save()
|
||||
{
|
||||
uint8_t* buffer = new uint8_t[METADATA_SIZE];
|
||||
|
||||
buffer = pushWord(_projectInstallationId, buffer);
|
||||
buffer = pushByte(_ipAssignmentMethod, buffer);
|
||||
buffer = pushByte(_ipCapabilities, buffer);
|
||||
buffer = pushInt(_ipAddress, buffer);
|
||||
buffer = pushInt(_subnetMask, buffer);
|
||||
buffer = pushInt(_defaultGateway, buffer);
|
||||
buffer = pushInt(_multicastAddress, buffer);
|
||||
buffer = pushByte(_ttl, buffer);
|
||||
buffer = pushByteArray((uint8_t*)_friendlyName, 30, buffer);
|
||||
buffer -= METADATA_SIZE;
|
||||
|
||||
if(_platform.NVMemoryType() == internalFlash){
|
||||
_platform.freeNVMemory(_ID);
|
||||
uint32_t addr = _platform.allocNVMemory(METADATA_SIZE, _ID);
|
||||
|
||||
for(uint32_t i=0;i<METADATA_SIZE;i++)
|
||||
_platform.writeNVMemory(addr+i, buffer[i]);
|
||||
|
||||
free (buffer);
|
||||
return (uint8_t*)addr;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
uint8_t* IpParameterObject::save(uint8_t* buffer)
|
||||
{
|
||||
@ -320,4 +361,4 @@ uint8_t IpParameterObject::propertyCount()
|
||||
PropertyDescription* IpParameterObject::propertyDescriptions()
|
||||
{
|
||||
return _propertyDescriptions;
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,9 @@ class IpParameterObject : public InterfaceObject
|
||||
uint8_t propertySize(PropertyID id);
|
||||
|
||||
uint8_t* save(uint8_t* buffer);
|
||||
uint8_t* save();
|
||||
uint8_t* restore(uint8_t* buffer);
|
||||
uint32_t size();
|
||||
|
||||
uint32_t multicastAddress() const;
|
||||
uint8_t ttl() const { return _ttl; }
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "memory.h"
|
||||
|
||||
#define BASE_ID 0xC0DE0000
|
||||
|
||||
Memory::Memory(Platform & platform): _platform(platform)
|
||||
{
|
||||
}
|
||||
@ -14,9 +16,66 @@ bool Memory::isMemoryModified()
|
||||
return _modified;
|
||||
}
|
||||
|
||||
void Memory::readMemory()
|
||||
void Memory::readMemory(){
|
||||
switch (_platform.NVMemoryType()){
|
||||
case internalRam:
|
||||
readRamMemory();
|
||||
break;
|
||||
case internalFlash:
|
||||
readFlashMemory();
|
||||
break;
|
||||
case external:
|
||||
readExternalMemory();
|
||||
break;
|
||||
case notDefined:
|
||||
default:
|
||||
_platform.fatalError();
|
||||
}
|
||||
}
|
||||
|
||||
void Memory::writeMemory(){
|
||||
switch (_platform.NVMemoryType()){
|
||||
case internalRam:
|
||||
writeRamMemory();
|
||||
break;
|
||||
case internalFlash:
|
||||
writeFlashMemory();
|
||||
break;
|
||||
case external:
|
||||
writeExternalMemory();
|
||||
break;
|
||||
case notDefined:
|
||||
default:
|
||||
_platform.fatalError();
|
||||
}
|
||||
}
|
||||
|
||||
void Memory::readFlashMemory()
|
||||
{
|
||||
_data = _platform.getEepromBuffer(512);
|
||||
for (int i = 0; i < _saveCount; i++)
|
||||
{
|
||||
uint8_t* data = (uint8_t*)_platform.reloadNVMemory(BASE_ID+i);
|
||||
if(data == NULL)
|
||||
continue;
|
||||
|
||||
_saveRestores[i]->restore(data);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Memory::writeFlashMemory()
|
||||
{
|
||||
for (int i = 0; i < _saveCount; i++){
|
||||
_saveRestores[i]->save();
|
||||
}
|
||||
|
||||
_platform.finishNVMemory();
|
||||
_modified = false;
|
||||
}
|
||||
|
||||
void Memory::readRamMemory()
|
||||
{
|
||||
_data = (uint8_t*)_platform.reloadNVMemory(1);
|
||||
|
||||
if (_data[0] != 0x00 || _data[1] != 0xAD || _data[2] != 0xAF || _data[3] != 0xFE)
|
||||
return;
|
||||
@ -26,11 +85,20 @@ void Memory::readMemory()
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
buffer = _saveRestores[i]->restore(buffer);
|
||||
buffer = (uint8_t*)(((uint32_t)buffer + 3) / 4 * 4); //allign to 32bit
|
||||
}
|
||||
}
|
||||
|
||||
void Memory::writeMemory()
|
||||
void Memory::writeRamMemory()
|
||||
{
|
||||
uint32_t bytesToSave = 10;
|
||||
|
||||
for (int i = 0; i < _saveCount; i++){
|
||||
bytesToSave += _saveRestores[i]->size();
|
||||
}
|
||||
|
||||
_data = (uint8_t*)_platform.allocNVMemory(bytesToSave,BASE_ID);
|
||||
|
||||
_data[0] = 0x00;
|
||||
_data[1] = 0xAD;
|
||||
_data[2] = 0xAF;
|
||||
@ -41,16 +109,103 @@ void Memory::writeMemory()
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
buffer = _saveRestores[i]->save(buffer);
|
||||
buffer = (uint8_t*)(((uint32_t)buffer + 3) / 4 * 4); //allign to 32bit
|
||||
}
|
||||
_platform.commitToEeprom();
|
||||
_platform.finishNVMemory();
|
||||
_modified = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Memory::readExternalMemory()
|
||||
{
|
||||
|
||||
int size = _saveCount;
|
||||
volatile uint32_t addr = _platform.reloadNVMemory(BASE_ID);
|
||||
volatile uint32_t bytesToRestore;
|
||||
|
||||
if(addr == 0)
|
||||
return;
|
||||
|
||||
|
||||
if (_platform.readNVMemory(addr++) != 0x00 || _platform.readNVMemory(addr++) != 0xAD || _platform.readNVMemory(addr++) != 0xAF || _platform.readNVMemory(addr++) != 0xFE)
|
||||
return;
|
||||
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
((uint8_t*)&bytesToRestore)[0] = _platform.readNVMemory(addr++);
|
||||
((uint8_t*)&bytesToRestore)[1] = _platform.readNVMemory(addr++);
|
||||
((uint8_t*)&bytesToRestore)[2] = _platform.readNVMemory(addr++);
|
||||
((uint8_t*)&bytesToRestore)[3] = _platform.readNVMemory(addr++);
|
||||
|
||||
if(bytesToRestore == 0)
|
||||
continue;
|
||||
_data = _platform.allocMemory(bytesToRestore);
|
||||
if(_data == NULL)
|
||||
_platform.fatalError();
|
||||
|
||||
for (uint32_t e=0;e<bytesToRestore;e++){
|
||||
_data[e] = _platform.readNVMemory(addr++);
|
||||
}
|
||||
_saveRestores[i]->restore(_data);
|
||||
}
|
||||
}
|
||||
|
||||
void Memory::writeExternalMemory()
|
||||
{
|
||||
uint32_t bytesToSave = 4;
|
||||
int size = _saveCount;
|
||||
|
||||
_platform.freeNVMemory(BASE_ID);
|
||||
|
||||
for (int i = 0; i < size; i++){
|
||||
bytesToSave += _saveRestores[i]->size() + 4;
|
||||
}
|
||||
|
||||
uint32_t addr = _platform.allocNVMemory(bytesToSave,BASE_ID);
|
||||
|
||||
//write valid mask
|
||||
_platform.writeNVMemory(addr++,0x00);
|
||||
_platform.writeNVMemory(addr++,0xAD);
|
||||
_platform.writeNVMemory(addr++,0xAF);
|
||||
_platform.writeNVMemory(addr++,0xFE);
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
_data = _saveRestores[i]->save();
|
||||
if(_data == NULL)
|
||||
bytesToSave = 0;
|
||||
else
|
||||
bytesToSave = _saveRestores[i]->size();
|
||||
|
||||
//write size
|
||||
_platform.writeNVMemory(addr++,((uint8_t*)&bytesToSave)[0]);
|
||||
_platform.writeNVMemory(addr++,((uint8_t*)&bytesToSave)[1]);
|
||||
_platform.writeNVMemory(addr++,((uint8_t*)&bytesToSave)[2]);
|
||||
_platform.writeNVMemory(addr++,((uint8_t*)&bytesToSave)[3]);
|
||||
|
||||
if(bytesToSave == 0)
|
||||
continue;
|
||||
|
||||
|
||||
for (uint32_t e=0;e<bytesToSave;e++){
|
||||
_platform.writeNVMemory(addr++,_data[e]);
|
||||
}
|
||||
|
||||
_platform.freeMemory(_data);
|
||||
}
|
||||
|
||||
_platform.finishNVMemory();
|
||||
_modified = false;
|
||||
}
|
||||
void Memory::addSaveRestore(SaveRestore * obj)
|
||||
{
|
||||
if (_saveCount >= MAXSAVE - 1)
|
||||
return;
|
||||
|
||||
obj->memoryID(BASE_ID + _saveCount);
|
||||
_saveRestores[_saveCount] = obj;
|
||||
_saveCount += 1;
|
||||
}
|
||||
|
@ -16,6 +16,12 @@ public:
|
||||
void writeMemory();
|
||||
void addSaveRestore(SaveRestore* obj);
|
||||
private:
|
||||
void readFlashMemory();
|
||||
void writeFlashMemory();
|
||||
void readRamMemory();
|
||||
void writeRamMemory();
|
||||
void readExternalMemory();
|
||||
void writeExternalMemory();
|
||||
Platform& _platform;
|
||||
bool _modified = false;
|
||||
SaveRestore* _saveRestores[MAXSAVE] = {0};
|
||||
|
@ -12,6 +12,8 @@ uint8_t* Platform::memoryReference()
|
||||
uint8_t* Platform::allocMemory(size_t size)
|
||||
{
|
||||
uint8_t* address = (uint8_t*)malloc(size);
|
||||
if(address == NULL)
|
||||
fatalError();
|
||||
// if (_memoryReference == 0 || address < _memoryReference)
|
||||
// _memoryReference = address;
|
||||
print("MemRef: ");
|
||||
|
@ -4,6 +4,13 @@
|
||||
#include <stddef.h>
|
||||
#include "save_restore.h"
|
||||
|
||||
typedef enum{
|
||||
notDefined,
|
||||
internalRam,
|
||||
internalFlash,
|
||||
external
|
||||
}NVMemory_t;
|
||||
|
||||
class Platform
|
||||
{
|
||||
public:
|
||||
@ -29,13 +36,18 @@ class Platform
|
||||
virtual int readUart() = 0;
|
||||
virtual size_t readBytesUart(uint8_t* buffer, size_t length) = 0;
|
||||
|
||||
virtual uint8_t* getEepromBuffer(uint16_t size) = 0;
|
||||
virtual void commitToEeprom() = 0;
|
||||
virtual bool writeNVMemory(uint32_t addr,uint8_t data) = 0;
|
||||
virtual uint8_t readNVMemory(uint32_t addr) = 0;
|
||||
virtual uint32_t allocNVMemory(uint32_t size,uint32_t ID) = 0;
|
||||
virtual uint32_t reloadNVMemory(uint32_t ID) = 0;
|
||||
virtual void finishNVMemory() = 0;
|
||||
virtual void freeNVMemory(uint32_t ID) = 0;
|
||||
|
||||
virtual uint8_t* memoryReference();
|
||||
virtual uint8_t* allocMemory(size_t size);
|
||||
virtual void freeMemory(uint8_t* ptr);
|
||||
|
||||
NVMemory_t NVMemoryType(){return _NVMemoryType;}
|
||||
protected:
|
||||
uint8_t* _memoryReference = 0;
|
||||
};
|
||||
NVMemory_t _NVMemoryType = notDefined;
|
||||
};
|
||||
|
@ -16,6 +16,7 @@ class SaveRestore
|
||||
* the start of its buffer.
|
||||
*/
|
||||
virtual uint8_t* save(uint8_t* buffer) = 0;
|
||||
virtual uint8_t* save() = 0;
|
||||
/**
|
||||
* This method is called when the object should restore its state from the buffer.
|
||||
*
|
||||
@ -25,4 +26,8 @@ class SaveRestore
|
||||
* the start of its buffer.
|
||||
*/
|
||||
virtual uint8_t* restore(uint8_t* buffer) = 0;
|
||||
virtual uint32_t size() = 0;
|
||||
void memoryID (uint32_t ID){_ID = ID;}
|
||||
protected:
|
||||
uint32_t _ID;
|
||||
};
|
@ -3,6 +3,8 @@
|
||||
#include "table_object.h"
|
||||
#include "bits.h"
|
||||
|
||||
#define METADATA_SIZE (sizeof(_state)+sizeof(_errorCode)+sizeof(_size))
|
||||
|
||||
TableObject::TableObject(Platform& platform): _platform(platform)
|
||||
{
|
||||
|
||||
@ -92,11 +94,40 @@ uint8_t* TableObject::save(uint8_t* buffer)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
uint8_t* TableObject::save()
|
||||
{
|
||||
if(_data == NULL)
|
||||
return NULL;
|
||||
|
||||
uint32_t addr;
|
||||
uint8_t* buffer;
|
||||
addr =(uint32_t)(_data - METADATA_SIZE);
|
||||
if(_platform.NVMemoryType() == internalFlash)
|
||||
buffer = new uint8_t[METADATA_SIZE];
|
||||
else
|
||||
buffer = (uint8_t*)addr;
|
||||
|
||||
buffer = pushByte(_state, buffer);
|
||||
buffer = pushByte(_errorCode, buffer);
|
||||
buffer = pushInt(_size, buffer);
|
||||
buffer -= METADATA_SIZE;
|
||||
|
||||
if(_platform.NVMemoryType() == internalFlash){
|
||||
for(uint32_t i=0;i<METADATA_SIZE;i++)
|
||||
_platform.writeNVMemory(addr+i, buffer[i]);
|
||||
|
||||
free (buffer);
|
||||
}
|
||||
|
||||
return _dataComplete;
|
||||
}
|
||||
|
||||
uint8_t* TableObject::restore(uint8_t* buffer)
|
||||
{
|
||||
uint8_t state = 0;
|
||||
uint8_t errorCode = 0;
|
||||
if(_dataComplete == NULL)
|
||||
_dataComplete = buffer;
|
||||
buffer = popByte(state, buffer);
|
||||
buffer = popByte(errorCode, buffer);
|
||||
_state = (LoadState)state;
|
||||
@ -104,15 +135,13 @@ uint8_t* TableObject::restore(uint8_t* buffer)
|
||||
|
||||
buffer = popInt(_size, buffer);
|
||||
|
||||
if (_data)
|
||||
_platform.freeMemory(_data);
|
||||
|
||||
if (_size > 0)
|
||||
_data = _platform.allocMemory(_size);
|
||||
_data = buffer;
|
||||
|
||||
else
|
||||
_data = 0;
|
||||
|
||||
buffer = popByteArray(_data, _size, buffer);
|
||||
buffer += _size;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
@ -124,9 +153,13 @@ uint32_t TableObject::tableReference()
|
||||
|
||||
bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte)
|
||||
{
|
||||
if (_data)
|
||||
if (_dataComplete)
|
||||
{
|
||||
_platform.freeMemory(_data);
|
||||
if(_platform.NVMemoryType() == internalFlash)
|
||||
_platform.freeNVMemory(_ID);
|
||||
else if(_platform.NVMemoryType() == external)
|
||||
_platform.freeMemory(_dataComplete);
|
||||
_dataComplete = 0;
|
||||
_data = 0;
|
||||
_size = 0;
|
||||
}
|
||||
@ -134,15 +167,24 @@ bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte)
|
||||
if (size == 0)
|
||||
return true;
|
||||
|
||||
_data = _platform.allocMemory(size);
|
||||
if (!_data)
|
||||
return false;
|
||||
|
||||
if(_platform.NVMemoryType() == internalFlash){
|
||||
_dataComplete = (uint8_t*)_platform.allocNVMemory(size+this->size(), _ID);
|
||||
}
|
||||
else{
|
||||
_dataComplete = _platform.allocMemory(size+this->size());
|
||||
}
|
||||
_data = _dataComplete + this->size(); //skip metadata
|
||||
_size = size;
|
||||
|
||||
if (doFill)
|
||||
memset(_data, fillByte, size);
|
||||
|
||||
if (doFill){
|
||||
if(_platform.NVMemoryType() == internalFlash){
|
||||
uint32_t addr = (uint32_t)_data;
|
||||
for(uint32_t i=0; i<_size;i++)
|
||||
_platform.writeNVMemory(addr++, fillByte);
|
||||
}
|
||||
else{
|
||||
memset(_data, fillByte, _size);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -279,7 +321,12 @@ uint8_t* TableObject::data()
|
||||
|
||||
uint32_t TableObject::size()
|
||||
{
|
||||
return _size;
|
||||
return _size + METADATA_SIZE;
|
||||
}
|
||||
|
||||
uint32_t TableObject::sizeMetadata()
|
||||
{
|
||||
return METADATA_SIZE;
|
||||
}
|
||||
|
||||
void TableObject::errorCode(ErrorCode errorCode)
|
||||
|
@ -26,7 +26,9 @@ public:
|
||||
*/
|
||||
LoadState loadState();
|
||||
virtual uint8_t* save(uint8_t* buffer);
|
||||
virtual uint8_t* save();
|
||||
virtual uint8_t* restore(uint8_t* buffer);
|
||||
virtual uint32_t size();
|
||||
protected:
|
||||
/**
|
||||
* This method is called before the interface object enters a new ::LoadState.
|
||||
@ -40,15 +42,18 @@ protected:
|
||||
* must not be freed.
|
||||
*/
|
||||
uint8_t* data();
|
||||
uint32_t sizeMetadata();
|
||||
/**
|
||||
* returns the size of the internal data of the interface object int byte.
|
||||
*/
|
||||
uint32_t size();
|
||||
// uint32_t size();
|
||||
/**
|
||||
* Set the reason for a state change failure.
|
||||
*/
|
||||
void errorCode(ErrorCode errorCode);
|
||||
|
||||
Platform& _platform;
|
||||
uint8_t *_dataComplete = 0;
|
||||
private:
|
||||
uint32_t tableReference();
|
||||
bool allocTable(uint32_t size, bool doFill, uint8_t fillByte);
|
||||
@ -67,7 +72,6 @@ protected:
|
||||
*/
|
||||
void loadState(LoadState newState);
|
||||
LoadState _state = LS_UNLOADED;
|
||||
Platform& _platform;
|
||||
uint8_t *_data = 0;
|
||||
uint32_t _size = 0;
|
||||
ErrorCode _errorCode = E_NO_FAULT;
|
||||
|
@ -257,9 +257,16 @@ template <class P, class B> class KnxFacade : private SaveRestore
|
||||
uint32_t _buttonPin = 0;
|
||||
saveRestoreCallback _saveCallback = 0;
|
||||
saveRestoreCallback _restoreCallback = 0;
|
||||
uint32_t (*_sizeCallback)() = 0;
|
||||
bool _toogleProgMode = false;
|
||||
bool _progLedState = false;
|
||||
|
||||
uint32_t size(){
|
||||
if (_sizeCallback != 0)
|
||||
return _sizeCallback();
|
||||
|
||||
return 0;
|
||||
}
|
||||
uint8_t* save(uint8_t* buffer)
|
||||
{
|
||||
if (_saveCallback != 0)
|
||||
@ -268,6 +275,7 @@ template <class P, class B> class KnxFacade : private SaveRestore
|
||||
return buffer;
|
||||
}
|
||||
|
||||
uint8_t* save(){};
|
||||
uint8_t* restore(uint8_t* buffer)
|
||||
{
|
||||
if (_restoreCallback != 0)
|
||||
|
@ -200,22 +200,44 @@ int LinuxPlatform::readBytes(uint8_t * buffer, uint16_t maxLen)
|
||||
return len;
|
||||
}
|
||||
|
||||
uint8_t * LinuxPlatform::getEepromBuffer(uint16_t size)
|
||||
bool LinuxPlatform::writeNVMemory(uint32_t addr,uint8_t data)
|
||||
{
|
||||
if (_fd < 0)
|
||||
doMemoryMapping();
|
||||
|
||||
return _mappedFile + 2;
|
||||
*((uint8_t*)addr) = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
void LinuxPlatform::commitToEeprom()
|
||||
uint8_t LinuxPlatform::readNVMemory(uint32_t addr)
|
||||
{
|
||||
return *((uint8_t*)addr);
|
||||
}
|
||||
|
||||
uint32_t LinuxPlatform::allocNVMemory(uint32_t size,uint32_t ID)
|
||||
{
|
||||
if (_fd < 0)
|
||||
doMemoryMapping();
|
||||
|
||||
return (uint32_t)_mappedFile + 2;
|
||||
}
|
||||
|
||||
uint32_t LinuxPlatform::reloadNVMemory(uint32_t ID)
|
||||
{
|
||||
if (_fd < 0)
|
||||
doMemoryMapping();
|
||||
|
||||
return (uint32_t)_mappedFile + 2;
|
||||
}
|
||||
|
||||
void LinuxPlatform::finishNVMemory()
|
||||
{
|
||||
if (_fd < 0)
|
||||
doMemoryMapping();
|
||||
|
||||
fsync(_fd);
|
||||
}
|
||||
|
||||
void LinuxPlatform::freeNVMemory(uint32_t ID)
|
||||
{
|
||||
}
|
||||
#define FLASHSIZE 0x10000
|
||||
void LinuxPlatform::doMemoryMapping()
|
||||
{
|
||||
|
@ -44,8 +44,12 @@ public:
|
||||
size_t readBytesUart(uint8_t *buffer, size_t length) override;
|
||||
|
||||
//memory
|
||||
uint8_t* getEepromBuffer(uint16_t size) override;
|
||||
void commitToEeprom() override;
|
||||
bool writeNVMemory(uint32_t addr,uint8_t data);
|
||||
uint8_t readNVMemory(uint32_t addr);
|
||||
uint32_t allocNVMemory(uint32_t size,uint32_t ID);
|
||||
uint32_t reloadNVMemory(uint32_t ID);
|
||||
void finishNVMemory();
|
||||
void freeNVMemory(uint32_t ID);
|
||||
uint8_t* allocMemory(size_t size) override;
|
||||
void freeMemory(uint8_t* ptr) override;
|
||||
void cmdlineArgs(int argc, char** argv);
|
||||
|
416
src/samd_flash.cpp
Normal file
416
src/samd_flash.cpp
Normal file
@ -0,0 +1,416 @@
|
||||
#include <Arduino.h>
|
||||
#include "samd_flash.h"
|
||||
|
||||
#define VALID (0xDEADC0DE)
|
||||
|
||||
extern uint32_t __etext;
|
||||
extern uint32_t __data_start__;
|
||||
extern uint32_t __data_end__;
|
||||
|
||||
static const uint32_t pageSizes[] = { 8, 16, 32, 64, 128, 256, 512, 1024 };
|
||||
|
||||
SamdFlash::SamdFlash(){
|
||||
_pageSize = pageSizes[NVMCTRL->PARAM.bit.PSZ];
|
||||
_pageCnt = NVMCTRL->PARAM.bit.NVMP;
|
||||
_rowSize = PAGES_PER_ROW * _pageSize;
|
||||
_rowBuffer = new uint8_t[_rowSize];
|
||||
|
||||
//find end of program flash and set limit to next row
|
||||
uint32_t endEddr = (uint32_t)(&__etext + (&__data_end__ - &__data_start__)); //text + data MemoryBlock
|
||||
_MemoryEnd = getRowAddr(endEddr) + _rowSize-1; //23295
|
||||
|
||||
//map info structure to last row in flash
|
||||
_info = (info_data_t*)getRowAddr(_pageSize*_pageCnt-1); //261888 (rowAddr of last row)
|
||||
}
|
||||
|
||||
uint32_t SamdFlash::getStartAddress(){
|
||||
return _info->freeMemoryStart;
|
||||
}
|
||||
|
||||
uint8_t SamdFlash::read(uint8_t* addr){
|
||||
if(_rowBufferModified == false)
|
||||
return *addr;
|
||||
|
||||
if(getRowAddr((uint32_t)addr) != _rowBufferAddr)
|
||||
return *addr;
|
||||
|
||||
//return data from buffer because flash data is not up to date
|
||||
return _rowBuffer[(uint32_t)addr-_rowBufferAddr];
|
||||
}
|
||||
|
||||
bool SamdFlash::write(uint8_t* addr, uint8_t data){
|
||||
//Check if the destination address is valid
|
||||
if ((uint32_t)addr >= (_pageSize * _pageCnt) || (uint32_t)addr <= _MemoryEnd)
|
||||
return false;
|
||||
|
||||
uint32_t newRowAddr = getRowAddr((uint32_t)addr);
|
||||
//if the row changed, write old Buffer and init new
|
||||
if(newRowAddr != _rowBufferAddr){
|
||||
uploadRowBuffer(_rowBufferAddr);
|
||||
downloadRowBuffer(newRowAddr);
|
||||
_rowBufferAddr = newRowAddr;
|
||||
}
|
||||
|
||||
_rowBuffer[(uint32_t)addr-_rowBufferAddr] = data;
|
||||
_rowBufferModified = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SamdFlash::uploadRowBuffer(uint32_t rowAddr){
|
||||
if(!_rowBufferModified) return;
|
||||
eraseRow(rowAddr);
|
||||
//Clear Page Buffer
|
||||
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC;
|
||||
while (NVMCTRL->INTFLAG.bit.READY == 0) {}
|
||||
// Disable automatic page write
|
||||
NVMCTRL->CTRLB.bit.MANW = 1;
|
||||
|
||||
volatile uint32_t* src_addr = (volatile uint32_t*)_rowBuffer;
|
||||
volatile uint32_t* dst_addr = (volatile uint32_t *)rowAddr;
|
||||
for(uint32_t p=0;p<PAGES_PER_ROW;p++){
|
||||
for (uint32_t i=0; i<(_pageSize/4); i++) {
|
||||
*dst_addr = *src_addr;
|
||||
dst_addr++;
|
||||
src_addr++;
|
||||
}
|
||||
// Execute "WP" Write Page
|
||||
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP;
|
||||
while (NVMCTRL->INTFLAG.bit.READY == 0) { }
|
||||
}
|
||||
}
|
||||
void SamdFlash::downloadRowBuffer(uint32_t rowAddr){
|
||||
volatile uint32_t* src_addr = (volatile uint32_t*)rowAddr;
|
||||
volatile uint32_t* dst_addr = (volatile uint32_t *)_rowBuffer;
|
||||
for(uint32_t p=0;p<PAGES_PER_ROW;p++){
|
||||
for (uint32_t i=0; i<(_pageSize/4); i++) {
|
||||
*dst_addr = *src_addr;
|
||||
dst_addr++;
|
||||
src_addr++;
|
||||
}
|
||||
}
|
||||
_rowBufferModified = false;
|
||||
}
|
||||
|
||||
uint32_t SamdFlash::getRowAddr(uint32_t flasAddr){
|
||||
return flasAddr & ~(_rowSize-1);
|
||||
}
|
||||
|
||||
void SamdFlash::finalise(){
|
||||
uploadRowBuffer(_rowBufferAddr);
|
||||
}
|
||||
|
||||
void SamdFlash::eraseRow(uint32_t rowAddr){
|
||||
NVMCTRL->ADDR.reg = rowAddr/2;
|
||||
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER;
|
||||
while (!NVMCTRL->INTFLAG.bit.READY) { }
|
||||
}
|
||||
|
||||
void SamdFlash::erase(){
|
||||
uint32_t rowAddr = getRowAddr((uint32_t)_info);
|
||||
uint32_t nextrowAddr = getRowAddr(_MemoryEnd);
|
||||
|
||||
while(rowAddr != nextrowAddr){
|
||||
eraseRow(rowAddr);
|
||||
rowAddr = rowAddr - _rowSize;
|
||||
}
|
||||
}
|
||||
|
||||
void SamdFlash::erase(uint32_t ID){
|
||||
block_meta_data_t ramCopy;
|
||||
block_meta_data_t* block = getBlock(ID);
|
||||
if(block == NULL)
|
||||
return;
|
||||
|
||||
ramCopy = *block;
|
||||
uint32_t rowAddr = (uint32_t)block;
|
||||
uint32_t nextrowAddr = getRowAddr(rowAddr + block->size - 1 +sizeof(block_meta_data_t));
|
||||
|
||||
while(rowAddr != nextrowAddr){
|
||||
eraseRow(nextrowAddr);
|
||||
nextrowAddr = nextrowAddr - _rowSize;
|
||||
}
|
||||
uploadRowBuffer(_rowBufferAddr);
|
||||
|
||||
_rowBufferAddr = rowAddr;
|
||||
downloadRowBuffer(_rowBufferAddr);
|
||||
//map block meta structure into ram copy
|
||||
block = (block_meta_data_t*)_rowBuffer;
|
||||
//copy into row buffer
|
||||
*block = ramCopy;
|
||||
_rowBufferModified = true;
|
||||
uploadRowBuffer(_rowBufferAddr);
|
||||
}
|
||||
void SamdFlash::copyAndFree(block_meta_data_t* src, block_meta_data_t* dst){
|
||||
block_meta_data_t metaDataRamCopy;
|
||||
block_meta_data_t* tempBlock;
|
||||
if(src == NULL || dst == NULL)
|
||||
return;
|
||||
|
||||
metaDataRamCopy = *dst;
|
||||
uint32_t lastRow = getRowAddr((uint32_t)src + src->size -1 + sizeof(block_meta_data_t));
|
||||
uint32_t srcRow = (uint32_t)src;
|
||||
uint32_t dstRow = (uint32_t)dst;
|
||||
|
||||
while(srcRow <= lastRow){
|
||||
downloadRowBuffer(srcRow);
|
||||
//if first row copy meta data too
|
||||
if(srcRow == (uint32_t)src){
|
||||
//map block meta structure into ram copy
|
||||
tempBlock = (block_meta_data_t*)_rowBuffer;
|
||||
//copy into row buffer
|
||||
*tempBlock = metaDataRamCopy;
|
||||
}
|
||||
_rowBufferModified = true;
|
||||
uploadRowBuffer(dstRow);
|
||||
|
||||
srcRow = srcRow + _rowSize;
|
||||
dstRow = dstRow + _rowSize;
|
||||
}
|
||||
|
||||
//free src
|
||||
downloadRowBuffer((uint32_t)src);
|
||||
//map block meta structure into ram copy
|
||||
tempBlock = (block_meta_data_t*)_rowBuffer;
|
||||
tempBlock->ID = 0;
|
||||
_rowBufferModified = true;
|
||||
uploadRowBuffer((uint32_t)src);
|
||||
}
|
||||
|
||||
block_meta_data_t* SamdFlash::findEmptyBlock(uint32_t size,uint32_t* compSize, uint32_t* previousBlockAddr){
|
||||
block_meta_data_t* block = _info->firstBlock;
|
||||
block_meta_data_t* preblock = NULL;
|
||||
block_meta_data_t* conblock = NULL;
|
||||
if(block != NULL && block->validMask == VALID){
|
||||
do{
|
||||
if(block->ID == 0){
|
||||
if(block->size >= size){
|
||||
*compSize = 0;
|
||||
return block;
|
||||
}
|
||||
//ceck if we can merge next empty blocks
|
||||
else if(block->next != NULL){
|
||||
conblock = block->next;
|
||||
*compSize = block->size;
|
||||
while(conblock != NULL && conblock->ID == 0){
|
||||
*compSize += conblock->size + sizeof(block_meta_data_t);
|
||||
if(*compSize >= size){
|
||||
*previousBlockAddr = (uint32_t)preblock;
|
||||
return conblock;
|
||||
}
|
||||
conblock = conblock->next;
|
||||
}
|
||||
}
|
||||
//block is last one
|
||||
else{
|
||||
*compSize = 0;
|
||||
*previousBlockAddr = (uint32_t)preblock;
|
||||
return block;
|
||||
}
|
||||
}
|
||||
preblock = block;
|
||||
block = block->next;
|
||||
}while(block != NULL && block->validMask == VALID);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t* SamdFlash::loadBlock(uint32_t ID){
|
||||
block_meta_data_t* block = _info->firstBlock;
|
||||
if(block == (block_meta_data_t*)0xFFFFFFFF)
|
||||
return NULL;
|
||||
|
||||
if(block != NULL && block->validMask == VALID){
|
||||
do{
|
||||
if(block->ID == ID){
|
||||
return ((uint8_t*)block)+sizeof(block_meta_data_t);
|
||||
}
|
||||
block = block->next;
|
||||
}while(block != NULL && block->validMask == VALID);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block_meta_data_t* SamdFlash::getBlock(uint32_t ID){
|
||||
uint8_t* block = loadBlock(ID);
|
||||
if(block == NULL)
|
||||
return NULL;
|
||||
return (block_meta_data_t*)(block-sizeof(block_meta_data_t));
|
||||
}
|
||||
|
||||
block_meta_data_t* SamdFlash::findLastBlock(){
|
||||
block_meta_data_t* block = _info->firstBlock;
|
||||
if(block == (block_meta_data_t*)0xFFFFFFFF || block == NULL)
|
||||
return NULL;
|
||||
while(block->next != NULL && block->next->validMask == VALID){
|
||||
block = block->next;
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
void SamdFlash::free(uint32_t ID){
|
||||
block_meta_data_t* block = getBlock(ID);
|
||||
if(block != NULL){
|
||||
//upload actual rowBuffer if necessary
|
||||
uploadRowBuffer(_rowBufferAddr);
|
||||
//download block into ram buffer
|
||||
_rowBufferAddr = (uint32_t)block;
|
||||
downloadRowBuffer(_rowBufferAddr);
|
||||
//map block structure into ram copy
|
||||
block = (block_meta_data_t*)_rowBuffer;
|
||||
//mark the block as empty and write to flash
|
||||
block->ID = 0;
|
||||
_rowBufferModified = true;
|
||||
uploadRowBuffer(_rowBufferAddr);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* SamdFlash::malloc(uint32_t size, uint32_t ID){
|
||||
//check if ID is already present
|
||||
if(loadBlock(ID) != NULL)
|
||||
return NULL;
|
||||
|
||||
return forcemalloc(size, ID);
|
||||
|
||||
}
|
||||
|
||||
uint8_t* SamdFlash::forcemalloc(uint32_t size, uint32_t ID){
|
||||
uploadRowBuffer(_rowBufferAddr);
|
||||
//download actual info row into ram buffer
|
||||
_rowBufferAddr = (uint32_t)_info; //261888
|
||||
downloadRowBuffer(_rowBufferAddr);
|
||||
//map info structure into ram copy
|
||||
_info = (info_data_t*)_rowBuffer;
|
||||
|
||||
//create new info if actual is not valid (all data got lost)
|
||||
if(_info->validMask != VALID){
|
||||
_info->validMask = VALID;
|
||||
_info->freeMemoryStart = getRowAddr(_pageSize*_pageCnt-1)-1; //161887
|
||||
_info->firstBlock = NULL;
|
||||
}
|
||||
|
||||
//create ram copies for further usage
|
||||
block_meta_data_t newBlock;
|
||||
block_meta_data_t previousBlock;
|
||||
uint32_t newBlockFlashAddr;
|
||||
uint32_t previousBlockFlashAddr = 0;
|
||||
block_meta_data_t* tempBlock;
|
||||
|
||||
//check if we can use an existing empty block or allocate a new one
|
||||
uint32_t newSize;
|
||||
tempBlock = findEmptyBlock(size,&newSize,&previousBlockFlashAddr);
|
||||
if(tempBlock != NULL){
|
||||
//copy found block into ram
|
||||
newBlock = *tempBlock;
|
||||
newBlockFlashAddr = (uint32_t)tempBlock;
|
||||
//two ore more empty blocks were connected
|
||||
if(newSize != 0){
|
||||
newBlock.size = newSize;
|
||||
if(previousBlockFlashAddr == 0){
|
||||
_info->firstBlock = (block_meta_data_t*)newBlockFlashAddr;
|
||||
}
|
||||
else{
|
||||
//copy found block into ram
|
||||
previousBlock = *((block_meta_data_t*)previousBlockFlashAddr);
|
||||
previousBlock.next = (block_meta_data_t*)newBlockFlashAddr;
|
||||
}
|
||||
}
|
||||
//newBlock is last one in list an can be extended
|
||||
if(newBlock.size < size){
|
||||
if(previousBlockFlashAddr == 0){
|
||||
newBlockFlashAddr = getRowAddr(getRowAddr(_pageSize*_pageCnt-1) - (size+sizeof(block_meta_data_t)));
|
||||
newBlock.size = getRowAddr(_pageSize*_pageCnt-1)-newBlockFlashAddr-sizeof(block_meta_data_t); //1008
|
||||
//update newBlockAddr in list
|
||||
_info->firstBlock = (block_meta_data_t*)newBlockFlashAddr;
|
||||
}
|
||||
else{
|
||||
newBlockFlashAddr = getRowAddr(previousBlockFlashAddr - (size+sizeof(block_meta_data_t)));
|
||||
newBlock.size = previousBlockFlashAddr-newBlockFlashAddr-sizeof(block_meta_data_t); //1008
|
||||
//copy found block into ram and update newBlockAddr in list
|
||||
previousBlock = *((block_meta_data_t*)previousBlockFlashAddr);
|
||||
previousBlock.next = (block_meta_data_t*)newBlockFlashAddr;
|
||||
}
|
||||
//set MemoryStart to end of new block
|
||||
_info->freeMemoryStart = newBlockFlashAddr-1; //260863
|
||||
}
|
||||
//fill meta data of new block
|
||||
newBlock.validMask = VALID;
|
||||
newBlock.ID = ID;
|
||||
}
|
||||
else{
|
||||
//check if size fits into free area
|
||||
if(_info->freeMemoryStart - (size+sizeof(block_meta_data_t)) <= _MemoryEnd)
|
||||
return NULL;
|
||||
|
||||
//get start address of new block
|
||||
newBlockFlashAddr = getRowAddr(_info->freeMemoryStart +1 - (size+sizeof(block_meta_data_t))); //260864 (size= 1024-16=1008)
|
||||
newBlock.size = _info->freeMemoryStart-newBlockFlashAddr+1-sizeof(block_meta_data_t); //1008
|
||||
newBlock.next = NULL;
|
||||
//set MemoryStart to end of new block
|
||||
_info->freeMemoryStart = newBlockFlashAddr-1; //260863
|
||||
//fill meta data of new block
|
||||
newBlock.validMask = VALID;
|
||||
newBlock.ID = ID;
|
||||
|
||||
//add block to end of list
|
||||
tempBlock = findLastBlock();//(block_meta_data_t*)previousBlockFlashAddr;
|
||||
if(tempBlock == NULL){
|
||||
_info->firstBlock = (block_meta_data_t*)newBlockFlashAddr;
|
||||
}
|
||||
else{
|
||||
//copy found block into ram
|
||||
previousBlock = *tempBlock;
|
||||
previousBlock.next = (block_meta_data_t*)newBlockFlashAddr;
|
||||
previousBlockFlashAddr = (uint32_t)tempBlock;
|
||||
}
|
||||
}
|
||||
|
||||
//write modified ram info structure into last flash row
|
||||
_rowBufferModified = true;
|
||||
uploadRowBuffer(_rowBufferAddr);
|
||||
|
||||
//write modified ram copy of last block meta into flash
|
||||
if(previousBlockFlashAddr != 0){
|
||||
_rowBufferAddr = previousBlockFlashAddr;
|
||||
downloadRowBuffer(_rowBufferAddr);
|
||||
//map block meta structure into ram copy
|
||||
tempBlock = (block_meta_data_t*)_rowBuffer;
|
||||
//copy into row buffer
|
||||
*tempBlock = previousBlock;
|
||||
|
||||
_rowBufferModified = true;
|
||||
uploadRowBuffer(_rowBufferAddr);
|
||||
}
|
||||
|
||||
//write ram copy of new block meta into flash
|
||||
_rowBufferAddr = newBlockFlashAddr;
|
||||
downloadRowBuffer(_rowBufferAddr);
|
||||
//map block meta structure into ram copy
|
||||
tempBlock = (block_meta_data_t*)_rowBuffer;
|
||||
//copy into row buffer
|
||||
*tempBlock = newBlock;
|
||||
_rowBufferModified = true;
|
||||
uploadRowBuffer(_rowBufferAddr);
|
||||
|
||||
//config structure now points into updated flash again
|
||||
_info = (info_data_t*)getRowAddr(_pageSize*_pageCnt-1);
|
||||
return (uint8_t*)(newBlockFlashAddr+sizeof(block_meta_data_t));
|
||||
}
|
||||
|
||||
uint8_t* SamdFlash::realloc(uint32_t size, uint32_t ID){
|
||||
uint32_t newBlockFlashAddr;
|
||||
block_meta_data_t* actualBlock;
|
||||
|
||||
actualBlock = getBlock(ID);
|
||||
|
||||
//check if ID is presenty
|
||||
if(actualBlock == NULL)
|
||||
return malloc(size, ID);
|
||||
|
||||
//if size already fits into block, nothing to do otherwise alloc block with new size
|
||||
if(actualBlock->size >= size)
|
||||
return loadBlock(ID);
|
||||
|
||||
newBlockFlashAddr = (uint32_t)(forcemalloc(size, ID)-sizeof(block_meta_data_t));
|
||||
copyAndFree(actualBlock, (block_meta_data_t*)newBlockFlashAddr);
|
||||
return (uint8_t*)(newBlockFlashAddr+sizeof(block_meta_data_t));
|
||||
}
|
59
src/samd_flash.h
Normal file
59
src/samd_flash.h
Normal file
@ -0,0 +1,59 @@
|
||||
#ifndef SAMD_FLASH_H
|
||||
#define SAMD_FLASH_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#define PAGES_PER_ROW 4
|
||||
|
||||
typedef struct block_meta_data{
|
||||
uint32_t validMask;
|
||||
uint32_t ID;
|
||||
uint32_t size;
|
||||
struct block_meta_data *next;
|
||||
}__attribute__((__packed__))block_meta_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t validMask;
|
||||
uint32_t freeMemoryStart;
|
||||
block_meta_data_t* firstBlock;
|
||||
}__attribute__((__packed__))info_data_t;
|
||||
|
||||
class SamdFlash{
|
||||
public:
|
||||
SamdFlash();
|
||||
void erase();
|
||||
void erase(uint32_t ID);
|
||||
void free(uint32_t ID);
|
||||
uint8_t* malloc(uint32_t size, uint32_t ID);
|
||||
uint8_t* realloc(uint32_t size, uint32_t ID);
|
||||
uint8_t* loadBlock(uint32_t ID);
|
||||
bool write(uint8_t* addr, uint8_t data);
|
||||
uint8_t read(uint8_t* addr);
|
||||
void finalise();
|
||||
uint32_t getStartAddress();
|
||||
|
||||
private:
|
||||
uint8_t* forcemalloc(uint32_t size, uint32_t ID);
|
||||
void uploadRowBuffer(uint32_t rowAddr);
|
||||
void downloadRowBuffer(uint32_t rowAddr);
|
||||
uint32_t getRowAddr(uint32_t flasAddr);
|
||||
void eraseRow(uint32_t rowAddr);
|
||||
void copyAndFree(block_meta_data_t* src, block_meta_data_t* dst);
|
||||
|
||||
|
||||
block_meta_data_t* findEmptyBlock(uint32_t size,uint32_t* compSize, uint32_t* nextBlockAddr);
|
||||
block_meta_data_t* findLastBlock();
|
||||
block_meta_data_t* getBlock(uint32_t ID);
|
||||
|
||||
uint32_t _MemoryEnd=0;
|
||||
uint32_t _pageSize;
|
||||
uint32_t _rowSize;
|
||||
uint32_t _pageCnt;
|
||||
|
||||
|
||||
uint8_t* _rowBuffer;
|
||||
bool _rowBufferModified = false;
|
||||
uint32_t _rowBufferAddr;
|
||||
volatile info_data_t* _info;
|
||||
};
|
||||
#endif /* SAMD_FLASH_H */
|
@ -4,14 +4,18 @@
|
||||
#include <knx/bits.h>
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <FlashAsEEPROM.h>
|
||||
#include "samd_flash.h"
|
||||
|
||||
SamdFlash Flash;
|
||||
|
||||
SamdPlatform::SamdPlatform() : ArduinoPlatform(&Serial1)
|
||||
{
|
||||
Platform::_NVMemoryType = internalFlash;
|
||||
}
|
||||
|
||||
SamdPlatform::SamdPlatform( HardwareSerial* s) : ArduinoPlatform(s)
|
||||
{
|
||||
Platform::_NVMemoryType = internalFlash;
|
||||
}
|
||||
|
||||
void SamdPlatform::restart()
|
||||
@ -20,19 +24,121 @@ void SamdPlatform::restart()
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
uint8_t * SamdPlatform::getEepromBuffer(uint16_t size)
|
||||
|
||||
bool SamdPlatform::writeNVMemory(uint32_t addr,uint8_t data)
|
||||
{
|
||||
//EEPROM.begin(size);
|
||||
if(size > EEPROM_EMULATION_SIZE)
|
||||
if(Flash.write((uint8_t*)addr, data)==false)
|
||||
fatalError();
|
||||
|
||||
return EEPROM.getDataPtr();
|
||||
return true;
|
||||
}
|
||||
|
||||
void SamdPlatform::commitToEeprom()
|
||||
uint8_t SamdPlatform::readNVMemory(uint32_t addr)
|
||||
{
|
||||
return Flash.read((uint8_t*)addr);
|
||||
}
|
||||
|
||||
uint32_t SamdPlatform::allocNVMemory(uint32_t size,uint32_t ID)
|
||||
{
|
||||
uint32_t addr = (uint32_t)Flash.malloc(size, ID);
|
||||
if(addr == 0)
|
||||
fatalError();
|
||||
return addr;
|
||||
}
|
||||
|
||||
uint32_t SamdPlatform::reloadNVMemory(uint32_t ID)
|
||||
{
|
||||
// Flash.erase();
|
||||
return (uint32_t)Flash.loadBlock(ID);
|
||||
}
|
||||
|
||||
void SamdPlatform::finishNVMemory()
|
||||
{
|
||||
Flash.finalise();
|
||||
}
|
||||
|
||||
void SamdPlatform::freeNVMemory(uint32_t ID)
|
||||
{
|
||||
Flash.free(ID);
|
||||
// Flash.erase();
|
||||
}
|
||||
|
||||
uint8_t* SamdPlatform::memoryReference()
|
||||
{
|
||||
return (uint8_t*)Flash.getStartAddress();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************_NVMemoryType = internalRam*************************
|
||||
|
||||
bool SamdPlatform::writeNVMemory(uint32_t addr,uint8_t data)
|
||||
{
|
||||
*((uint8_t*)addr) = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t SamdPlatform::readNVMemory(uint32_t addr)
|
||||
{
|
||||
return *((uint8_t*)addr);
|
||||
}
|
||||
|
||||
uint32_t SamdPlatform::allocNVMemory(uint32_t size,uint32_t ID)
|
||||
{
|
||||
if(size > EEPROM_EMULATION_SIZE)
|
||||
fatalError();
|
||||
return (uint32_t)EEPROM.getDataPtr();
|
||||
}
|
||||
|
||||
uint32_t SamdPlatform::reloadNVMemory(uint32_t ID)
|
||||
{
|
||||
return (uint32_t)EEPROM.getDataPtr();
|
||||
}
|
||||
|
||||
void SamdPlatform::finishNVMemory()
|
||||
{
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
void SamdPlatform::freeNVMemory(uint32_t ID)
|
||||
{
|
||||
}
|
||||
/*
|
||||
|
||||
/*************_NVMemoryType = external*************************
|
||||
bool SamdPlatform::writeNVMemory(uint32_t addr,uint8_t data)
|
||||
{
|
||||
EEPROM.write(addr-1, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t SamdPlatform::readNVMemory(uint32_t addr)
|
||||
{
|
||||
return EEPROM.read(addr-1);
|
||||
}
|
||||
|
||||
uint32_t SamdPlatform::allocNVMemory(uint32_t size,uint32_t ID)
|
||||
{
|
||||
if(size > EEPROM_EMULATION_SIZE)
|
||||
fatalError();
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t SamdPlatform::reloadNVMemory(uint32_t ID)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SamdPlatform::finishNVMemory()
|
||||
{
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
void SamdPlatform::freeNVMemory(uint32_t ID)
|
||||
{
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -11,8 +11,13 @@ public:
|
||||
SamdPlatform( HardwareSerial* s);
|
||||
|
||||
void restart();
|
||||
uint8_t* getEepromBuffer(uint16_t size);
|
||||
void commitToEeprom();
|
||||
bool writeNVMemory(uint32_t addr,uint8_t data);
|
||||
uint8_t readNVMemory(uint32_t addr);
|
||||
uint32_t allocNVMemory(uint32_t size,uint32_t ID);
|
||||
uint32_t reloadNVMemory(uint32_t ID);
|
||||
void finishNVMemory();
|
||||
void freeNVMemory(uint32_t ID);
|
||||
uint8_t* memoryReference();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user