diff --git a/src/knx/bau_systemB.cpp b/src/knx/bau_systemB.cpp index 9c6fb0a..26a3af7 100644 --- a/src/knx/bau_systemB.cpp +++ b/src/knx/bau_systemB.cpp @@ -611,3 +611,13 @@ Memory& BauSystemB::memory() { return _memory; } + +void BauSystemB::addVersionCheckCallback(versionCheckCallback func) +{ + _memory.addVersionCheckCallback(func); +} + +versionCheckCallback BauSystemB::getVersionCheckCallback() +{ + return _memory.getVersionCheckCallback(); +} \ No newline at end of file diff --git a/src/knx/bau_systemB.h b/src/knx/bau_systemB.h index abbc653..7b5be26 100644 --- a/src/knx/bau_systemB.h +++ b/src/knx/bau_systemB.h @@ -38,6 +38,8 @@ class BauSystemB : protected BusAccessUnit void propertyValueWrite(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t& numberOfElements, uint16_t startIndex, uint8_t* data, uint32_t length) override; + void addVersionCheckCallback(versionCheckCallback func); + versionCheckCallback getVersionCheckCallback(); protected: virtual ApplicationLayer& applicationLayer() = 0; diff --git a/src/knx/device_object.h b/src/knx/device_object.h index a7d80d4..80b556c 100644 --- a/src/knx/device_object.h +++ b/src/knx/device_object.h @@ -7,36 +7,40 @@ class DeviceObject: public InterfaceObject { public: - DeviceObject(); - uint8_t* save(uint8_t* buffer) override; - const uint8_t* restore(const uint8_t* buffer) override; - uint16_t saveSize() override; + // increase this version anytime DeviceObject-API changes + // the following value represents the serialized representation of DeviceObject. + const uint16_t apiVersion = 1; + + DeviceObject(); + uint8_t* save(uint8_t* buffer) override; + const uint8_t* restore(const uint8_t* buffer) override; + uint16_t saveSize() override; - uint16_t individualAddress(); - void individualAddress(uint16_t value); + uint16_t individualAddress(); + void individualAddress(uint16_t value); - void individualAddressDuplication(bool value); - bool verifyMode(); - void verifyMode(bool value); - bool progMode(); - void progMode(bool value); - uint16_t manufacturerId(); - void manufacturerId(uint16_t value); - uint32_t bauNumber(); - void bauNumber(uint32_t value); - const uint8_t* orderNumber(); - void orderNumber(const uint8_t* value); - const uint8_t* hardwareType(); - void hardwareType(const uint8_t* value); - uint16_t version(); - void version(uint16_t value); - uint16_t maskVersion(); - void maskVersion(uint16_t value); - uint16_t maxApduLength(); - void maxApduLength(uint16_t value); - const uint8_t* rfDomainAddress(); - void rfDomainAddress(uint8_t* value); - uint8_t defaultHopCount(); + void individualAddressDuplication(bool value); + bool verifyMode(); + void verifyMode(bool value); + bool progMode(); + void progMode(bool value); + uint16_t manufacturerId(); + void manufacturerId(uint16_t value); + uint32_t bauNumber(); + void bauNumber(uint32_t value); + const uint8_t* orderNumber(); + void orderNumber(const uint8_t* value); + const uint8_t* hardwareType(); + void hardwareType(const uint8_t* value); + uint16_t version(); + void version(uint16_t value); + uint16_t maskVersion(); + void maskVersion(uint16_t value); + uint16_t maxApduLength(); + void maxApduLength(uint16_t value); + const uint8_t* rfDomainAddress(); + void rfDomainAddress(uint8_t* value); + uint8_t defaultHopCount(); private: uint8_t _prgMode = 0; uint16_t _ownAddress = 65535; // 15.15.255; diff --git a/src/knx/memory.cpp b/src/knx/memory.cpp index f53a1a1..04a2219 100644 --- a/src/knx/memory.cpp +++ b/src/knx/memory.cpp @@ -37,30 +37,51 @@ void Memory::readMemory() uint16_t version = 0; buffer = popWord(version, buffer); - - - - if (_deviceObject.manufacturerId() != manufacturerId - || _deviceObject.version() != version - || memcmp(_deviceObject.hardwareType(), hardwareType, LEN_HARDWARE_TYPE) != 0) + + VersionCheckResult versionCheck = FlashAllInvalid; + + // first check correct format of deviceObject-API + if (_deviceObject.apiVersion == version) { - println("saved memory doesn't match manufacturerId, version or hardwaretype"); - print("manufacturerId: "); - print(manufacturerId, HEX); - print(" "); - println(_deviceObject.manufacturerId(), HEX); - print("version: "); - print(version, HEX); - print(" "); - println(_deviceObject.version(), HEX); - print("hardwareType: "); - printHex("", hardwareType, LEN_HARDWARE_TYPE); - print(" "); - printHex("", _deviceObject.hardwareType(), LEN_HARDWARE_TYPE); + if (_versionCheckCallback != 0) { + versionCheck = _versionCheckCallback(manufacturerId, hardwareType); + // callback should provide infomation about version check failure reasons + } + else if (_deviceObject.manufacturerId() == manufacturerId && + memcmp(_deviceObject.hardwareType(), hardwareType, LEN_HARDWARE_TYPE) == 0) + { + versionCheck = FlashValid; + } + else + { + println("manufacturerId or hardwareType are different"); + print("expexted manufacturerId: "); + print(_deviceObject.manufacturerId(), HEX); + print(", stored manufacturerId: "); + println(manufacturerId, HEX); + print("expexted hardwareType: "); + printHex("", _deviceObject.hardwareType(), LEN_HARDWARE_TYPE); + print(", stored hardwareType: "); + printHex("", hardwareType, LEN_HARDWARE_TYPE); + println(""); + } + } + else + { + println("DataObject api changed, any data stored in flash is invalid."); + print("expexted DataObject api version: "); + print(_deviceObject.apiVersion, HEX); + print(", stored api version: "); + println(version, HEX); + } + + if (versionCheck == FlashAllInvalid) + { + println("ETS has to reprogram PA and application!"); return; } - println("manufacturerId, version and hardwareType matches"); + println("restoring data from flash..."); print("saverestores "); println(_saveCount); for (int i = 0; i < _saveCount; i++) @@ -70,6 +91,11 @@ void Memory::readMemory() buffer = _saveRestores[i]->restore(buffer); } println("restored saveRestores"); + if (versionCheck == FlashTablesInvalid) + { + println("TableObjects are referring to an older firmware version and are not loaded"); + return; + } print("tableObjs "); println(_tableObjCount); for (int i = 0; i < _tableObjCount; i++) @@ -105,7 +131,7 @@ void Memory::writeMemory() bufferPos = pushWord(_deviceObject.manufacturerId(), bufferPos); bufferPos = pushByteArray(_deviceObject.hardwareType(), LEN_HARDWARE_TYPE, bufferPos); - bufferPos = pushWord(_deviceObject.version(), bufferPos); + bufferPos = pushWord(_deviceObject.apiVersion, bufferPos); flashPos = _platform.writeNonVolatileMemory(flashPos, buffer, bufferPos - buffer); @@ -451,3 +477,13 @@ void Memory::addNewUsedBlock(uint8_t* address, size_t size) MemoryBlock* newUsedBlock = new MemoryBlock(address, size); addToUsedList(newUsedBlock); } + +void Memory::addVersionCheckCallback(versionCheckCallback func) +{ + _versionCheckCallback = func; +} + +versionCheckCallback Memory::getVersionCheckCallback() +{ + return _versionCheckCallback; +} diff --git a/src/knx/memory.h b/src/knx/memory.h index 8ebb5c2..4006e47 100644 --- a/src/knx/memory.h +++ b/src/knx/memory.h @@ -24,6 +24,15 @@ class MemoryBlock MemoryBlock* next = nullptr; }; +enum VersionCheckResult +{ + FlashAllInvalid = 0, //!< All flash content is not valid for this firmware, we delete it + FlashTablesInvalid = 1,//!< All table objects are invalid for this firmware, device object and saveRestores are OK + FlashValid = 2 //!< Flash content is valid and will be used +}; + +typedef VersionCheckResult (*versionCheckCallback)(uint16_t manufacturerId, uint8_t* hardwareType); + class Memory { public: @@ -41,6 +50,9 @@ public: uint8_t* toAbsolute(uint32_t relativeAddress); uint32_t toRelative(uint8_t* absoluteAddress); + void addVersionCheckCallback(versionCheckCallback func); + versionCheckCallback getVersionCheckCallback(); + private: void removeFromFreeList(MemoryBlock* block); void addToUsedList(MemoryBlock* block); @@ -56,6 +68,7 @@ public: uint8_t* eraseBlockEnd(uint32_t blockNum); void saveBufferdEraseBlock(); + versionCheckCallback _versionCheckCallback = 0; Platform& _platform; DeviceObject& _deviceObject; SaveRestore* _saveRestores[MAXSAVE] = {0};