fixes to enable partial programming (#132)

* fixes to enable partial programming (thanks to mumpf and proggerKA at KNX-UF!)

* add PID_MCB_TABLE to TableObject

* add CallBackProperty to send PID_MCB_TABLE

* calculate crc checksum using Crc16Citt when state switches to LOAD_COMPLETED

* add crc to save(), restore() and saveSize() to save crc to flash

* add CallBackProperty for read and write of PID_PROG_VERSION to ApplicationProgramObject

* create overrides for save, restore, and saveSize in ApplicationProgramObject to save _programVersion to flash

* improve crc calculation

* removed TableObject::crc16Citt method and use the one in bits.h

* do not save crc in flash, instead calculate on-the-fly in CallbackProperty when state==LS_LOADED

* use DataProperty to store PID_PROG_VERSION

* WARNING: segmentSize calculation for crc calculation is currently not correct. Need to somehow access size of data in class that inherits from TableObject (e.g. ApplicationObject or RouterObject)

* fix segment size in TableObject()

* save size after TableObject::allocTable() is called. Also change save() and restore() to save _size to flash. Modify saveSize()

* use _size to calculate crc value in CallbackProperty

* reduce footprint, save 5 byte

* add comment why _size field is needed

* remove PID_MCB_TABLE from RouterObject

* this is now implemented in TableObject
This commit is contained in:
OutOfSync1 2021-04-14 23:44:12 +02:00 committed by GitHub
parent e57bbf9dbe
commit 1343ed0b7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 58 additions and 25 deletions

View File

@ -29,6 +29,29 @@ ApplicationProgramObject::ApplicationProgramObject(Memory& memory)
TableObject::initializeProperties(sizeof(properties), properties);
}
uint8_t* ApplicationProgramObject::save(uint8_t* buffer)
{
uint8_t programVersion[5];
property(PID_PROG_VERSION)->read(programVersion);
buffer = pushByteArray(programVersion, 5, buffer);
return TableObject::save(buffer);
}
const uint8_t* ApplicationProgramObject::restore(const uint8_t* buffer)
{
uint8_t programVersion[5];
buffer = popByteArray(programVersion, 5, buffer);
property(PID_PROG_VERSION)->write(programVersion);
return TableObject::restore(buffer);
}
uint16_t ApplicationProgramObject::saveSize()
{
return TableObject::saveSize() + 5; // sizeof(programVersion)
}
uint8_t * ApplicationProgramObject::data(uint32_t addr)
{
return TableObject::data() + addr;

View File

@ -7,6 +7,9 @@ class ApplicationProgramObject : public TableObject
{
public:
ApplicationProgramObject(Memory& memory);
uint8_t* save(uint8_t* buffer) override;
const uint8_t* restore(const uint8_t* buffer) override;
uint16_t saveSize() override;
uint8_t* data(uint32_t addr);
uint8_t getByte(uint32_t addr);
uint16_t getWord(uint32_t addr);

View File

@ -84,7 +84,6 @@ void RouterObject::initialize(CouplerModel model, uint8_t objIndex, DptMedium me
Property* tableProperties[] =
{
new DataProperty( PID_COUPLER_SERVICES_CONTROL, true, PDT_GENERIC_01, 1, ReadLv3 | WriteLv0, (uint8_t) 0), // written by ETS TODO: implement
new DataProperty( PID_MCB_TABLE, false, PDT_GENERIC_08, 1, ReadLv3 | WriteLv0), // TODO: improve: move to TableObject once segment size handling is clear
new DataProperty( PID_FILTER_TABLE_USE, true, PDT_BINARY_INFORMATION, 1, ReadLv3 | WriteLv0, (uint16_t) 0 ), // default: invalid filter table, do not use, written by ETS
new FunctionProperty<RouterObject>(this, PID_ROUTETABLE_CONTROL,
// Command Callback of PID_ROUTETABLE_CONTROL
@ -452,27 +451,9 @@ void RouterObject::beforeStateChange(LoadState& newState)
if (newState != LS_LOADED)
return;
// calculate crc16-ccitt for PID_MCB_TABLE
updateMcb();
_filterTableGroupAddresses = (uint16_t*)data();
}
void RouterObject::updateMcb()
{
uint8_t mcb[propertySize(PID_MCB_TABLE)];
static constexpr uint32_t segmentSize = kFilterTableSize;
uint16_t crc16 = crc16Ccitt(data(), segmentSize);
pushInt(segmentSize, &mcb[0]); // Segment size
pushByte(0x00, &mcb[4]); // CRC control byte -> 0: always valid -> according to coupler spec. it shall always be a valid CRC
pushByte(0xFF, &mcb[5]); // Read access 4 bits + Write access 4 bits (unknown: value taken from real coupler device)
pushWord(crc16, &mcb[6]); // CRC-16 CCITT of filter table
property(PID_MCB_TABLE)->write(mcb);
}
void RouterObject::masterReset(EraseCode eraseCode, uint8_t channel)
{
if (eraseCode == FactoryReset)

View File

@ -52,8 +52,6 @@ private:
void commandClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet);
bool statusClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet);
void updateMcb();
bool _rfSbcRoutingEnabled = false;
bool _ipSbcRoutingEnabled = false;
uint16_t* _filterTableGroupAddresses = 0;

View File

@ -31,6 +31,8 @@ uint8_t* TableObject::save(uint8_t* buffer)
{
buffer = pushByte(_state, buffer);
buffer = pushInt(_size, buffer);
if (_data)
buffer = pushInt(_memory.toRelative(_data), buffer);
else
@ -46,6 +48,8 @@ const uint8_t* TableObject::restore(const uint8_t* buffer)
buffer = popByte(state, buffer);
_state = (LoadState)state;
buffer = popInt(_size, buffer);
uint32_t relativeAddress = 0;
buffer = popInt(relativeAddress, buffer);
@ -80,6 +84,8 @@ bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte)
if (doFill)
memset(_data, fillByte, size);
_size = size;
return true;
}
@ -229,7 +235,7 @@ void TableObject::errorCode(ErrorCode errorCode)
uint16_t TableObject::saveSize()
{
return 5 + InterfaceObject::saveSize();
return 5 + InterfaceObject::saveSize() + sizeof(_size);
}
void TableObject::initializeProperties(size_t propertiesSize, Property** properties)
@ -267,6 +273,21 @@ void TableObject::initializeProperties(size_t propertiesSize, Property** propert
pushInt(obj->tableReference(), data);
return 1;
}),
new CallbackProperty<TableObject>(this, PID_MCB_TABLE, false, PDT_GENERIC_08, 1, ReadLv3 | WriteLv0,
[](TableObject* obj, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t {
if (obj->_state != LS_LOADED)
return 0; // need to check return code for invalid
uint32_t segmentSize = obj->_size;
uint16_t crc16 = crc16Ccitt(obj->data(), segmentSize);
pushInt(segmentSize, data); // Segment size
pushByte(0x00, data + 4); // CRC control byte -> 0: always valid
pushByte(0xFF, data + 5); // Read access 4 bits + Write access 4 bits
pushWord(crc16, data + 6); // CRC-16 CCITT of data
return 1;
}),
new DataProperty(PID_ERROR_CODE, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint8_t)E_NO_FAULT)
};
//TODO: missing

View File

@ -28,7 +28,7 @@ class TableObject: public InterfaceObject
uint8_t* save(uint8_t* buffer) override;
const uint8_t* restore(const uint8_t* buffer) override;
uint16_t saveSize() override;
protected:
protected:
/**
* This method is called before the interface object enters a new ::LoadState.
* If there is a error changing the state newState should be set to ::LS_ERROR and errorCode()
@ -68,4 +68,11 @@ protected:
LoadState _state = LS_UNLOADED;
Memory& _memory;
uint8_t *_data = 0;
/**
* used to store size of data() in allocTable(), needed for calculation of crc in PID_MCB_TABLE.
* This value is also saved and restored.
* The size of the memory block cannot be used because it is changed during alignment to page size.
*/
uint32_t _size = 0;
};