mirror of
				https://github.com/thelsing/knx.git
				synced 2025-10-26 10:26:25 +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); | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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
 | ||||
|  | ||||
| @ -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; | ||||
| }; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user