mirror of
https://github.com/thelsing/knx.git
synced 2024-12-18 19:08:18 +01:00
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:
parent
e57bbf9dbe
commit
1343ed0b7d
@ -29,6 +29,29 @@ ApplicationProgramObject::ApplicationProgramObject(Memory& memory)
|
|||||||
TableObject::initializeProperties(sizeof(properties), properties);
|
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)
|
uint8_t * ApplicationProgramObject::data(uint32_t addr)
|
||||||
{
|
{
|
||||||
return TableObject::data() + addr;
|
return TableObject::data() + addr;
|
||||||
|
@ -7,6 +7,9 @@ class ApplicationProgramObject : public TableObject
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ApplicationProgramObject(Memory& memory);
|
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* data(uint32_t addr);
|
||||||
uint8_t getByte(uint32_t addr);
|
uint8_t getByte(uint32_t addr);
|
||||||
uint16_t getWord(uint32_t addr);
|
uint16_t getWord(uint32_t addr);
|
||||||
|
@ -84,7 +84,6 @@ void RouterObject::initialize(CouplerModel model, uint8_t objIndex, DptMedium me
|
|||||||
Property* tableProperties[] =
|
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_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 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,
|
new FunctionProperty<RouterObject>(this, PID_ROUTETABLE_CONTROL,
|
||||||
// Command Callback of PID_ROUTETABLE_CONTROL
|
// Command Callback of PID_ROUTETABLE_CONTROL
|
||||||
@ -452,27 +451,9 @@ void RouterObject::beforeStateChange(LoadState& newState)
|
|||||||
if (newState != LS_LOADED)
|
if (newState != LS_LOADED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// calculate crc16-ccitt for PID_MCB_TABLE
|
|
||||||
updateMcb();
|
|
||||||
|
|
||||||
_filterTableGroupAddresses = (uint16_t*)data();
|
_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)
|
void RouterObject::masterReset(EraseCode eraseCode, uint8_t channel)
|
||||||
{
|
{
|
||||||
if (eraseCode == FactoryReset)
|
if (eraseCode == FactoryReset)
|
||||||
|
@ -52,8 +52,6 @@ private:
|
|||||||
void commandClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet);
|
void commandClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet);
|
||||||
bool statusClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet);
|
bool statusClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet);
|
||||||
|
|
||||||
void updateMcb();
|
|
||||||
|
|
||||||
bool _rfSbcRoutingEnabled = false;
|
bool _rfSbcRoutingEnabled = false;
|
||||||
bool _ipSbcRoutingEnabled = false;
|
bool _ipSbcRoutingEnabled = false;
|
||||||
uint16_t* _filterTableGroupAddresses = 0;
|
uint16_t* _filterTableGroupAddresses = 0;
|
||||||
|
@ -31,6 +31,8 @@ uint8_t* TableObject::save(uint8_t* buffer)
|
|||||||
{
|
{
|
||||||
buffer = pushByte(_state, buffer);
|
buffer = pushByte(_state, buffer);
|
||||||
|
|
||||||
|
buffer = pushInt(_size, buffer);
|
||||||
|
|
||||||
if (_data)
|
if (_data)
|
||||||
buffer = pushInt(_memory.toRelative(_data), buffer);
|
buffer = pushInt(_memory.toRelative(_data), buffer);
|
||||||
else
|
else
|
||||||
@ -46,6 +48,8 @@ const uint8_t* TableObject::restore(const uint8_t* buffer)
|
|||||||
buffer = popByte(state, buffer);
|
buffer = popByte(state, buffer);
|
||||||
_state = (LoadState)state;
|
_state = (LoadState)state;
|
||||||
|
|
||||||
|
buffer = popInt(_size, buffer);
|
||||||
|
|
||||||
uint32_t relativeAddress = 0;
|
uint32_t relativeAddress = 0;
|
||||||
buffer = popInt(relativeAddress, buffer);
|
buffer = popInt(relativeAddress, buffer);
|
||||||
|
|
||||||
@ -80,6 +84,8 @@ bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte)
|
|||||||
if (doFill)
|
if (doFill)
|
||||||
memset(_data, fillByte, size);
|
memset(_data, fillByte, size);
|
||||||
|
|
||||||
|
_size = size;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +235,7 @@ void TableObject::errorCode(ErrorCode errorCode)
|
|||||||
|
|
||||||
uint16_t TableObject::saveSize()
|
uint16_t TableObject::saveSize()
|
||||||
{
|
{
|
||||||
return 5 + InterfaceObject::saveSize();
|
return 5 + InterfaceObject::saveSize() + sizeof(_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TableObject::initializeProperties(size_t propertiesSize, Property** properties)
|
void TableObject::initializeProperties(size_t propertiesSize, Property** properties)
|
||||||
@ -267,6 +273,21 @@ void TableObject::initializeProperties(size_t propertiesSize, Property** propert
|
|||||||
pushInt(obj->tableReference(), data);
|
pushInt(obj->tableReference(), data);
|
||||||
return 1;
|
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)
|
new DataProperty(PID_ERROR_CODE, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint8_t)E_NO_FAULT)
|
||||||
};
|
};
|
||||||
//TODO: missing
|
//TODO: missing
|
||||||
|
@ -28,7 +28,7 @@ class TableObject: public InterfaceObject
|
|||||||
uint8_t* save(uint8_t* buffer) override;
|
uint8_t* save(uint8_t* buffer) override;
|
||||||
const uint8_t* restore(const uint8_t* buffer) override;
|
const uint8_t* restore(const uint8_t* buffer) override;
|
||||||
uint16_t saveSize() override;
|
uint16_t saveSize() override;
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* This method is called before the interface object enters a new ::LoadState.
|
* 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()
|
* 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;
|
LoadState _state = LS_UNLOADED;
|
||||||
Memory& _memory;
|
Memory& _memory;
|
||||||
uint8_t *_data = 0;
|
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;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user