.. _program_listing_file_src_knx_table_object.cpp: Program Listing for File table_object.cpp ========================================= |exhale_lsh| :ref:`Return to documentation for file ` (``src/knx/table_object.cpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #include #include "table_object.h" #include "bits.h" #include "memory.h" #include "callback_property.h" #include "data_property.h" BeforeTablesUnloadCallback TableObject::_beforeTablesUnload = 0; uint8_t TableObject::_tableUnloadCount = 0; void TableObject::beforeTablesUnloadCallback(BeforeTablesUnloadCallback func) { _beforeTablesUnload = func; } BeforeTablesUnloadCallback TableObject::beforeTablesUnloadCallback() { return _beforeTablesUnload; } TableObject::TableObject(Memory& memory, uint32_t staticTableAdr, uint32_t staticTableSize) : _memory(memory) { _staticTableAdr = staticTableAdr; _staticTableSize = staticTableSize; } TableObject::~TableObject() {} void TableObject::beforeStateChange(LoadState& newState) { if (newState == LS_LOADED && _tableUnloadCount > 0) _tableUnloadCount--; if (_tableUnloadCount > 0) return; if (newState == LS_UNLOADED) { _tableUnloadCount++; if (_beforeTablesUnload != 0) _beforeTablesUnload(); } } LoadState TableObject::loadState() { return _state; } void TableObject::loadState(LoadState newState) { if (newState == _state) return; beforeStateChange(newState); _state = newState; } uint8_t* TableObject::save(uint8_t* buffer) { //println("TableObject::save"); allocTableStatic(); buffer = pushByte(_state, buffer); buffer = pushInt(_size, buffer); if (_data) buffer = pushInt(_memory.toRelative(_data), buffer); else buffer = pushInt(0, buffer); return InterfaceObject::save(buffer); } const uint8_t* TableObject::restore(const uint8_t* buffer) { //println("TableObject::restore"); uint8_t state = 0; buffer = popByte(state, buffer); _state = (LoadState)state; buffer = popInt(_size, buffer); uint32_t relativeAddress = 0; buffer = popInt(relativeAddress, buffer); //println(relativeAddress); if (relativeAddress != 0) _data = _memory.toAbsolute(relativeAddress); else _data = 0; //println((uint32_t)_data); return InterfaceObject::restore(buffer); } uint32_t TableObject::tableReference() { return (uint32_t)_memory.toRelative(_data); } bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte) { if (_staticTableAdr) return false; if (_data) { _memory.freeMemory(_data); _data = 0; } if (size == 0) return true; _data = _memory.allocMemory(size); if (!_data) return false; if (doFill) { uint32_t addr = _memory.toRelative(_data); for (uint32_t i = 0; i < size; i++) _memory.writeMemory(addr + i, 1, &fillByte); } _size = size; return true; } void TableObject::allocTableStatic() { if (_staticTableAdr && !_data) { _data = _memory.toAbsolute(_staticTableAdr); _size = _staticTableSize; _memory.addNewUsedBlock(_data, _size); } } void TableObject::loadEvent(const uint8_t* data) { //printHex("TableObject::loadEvent 0x", data, 10); switch (_state) { case LS_UNLOADED: loadEventUnloaded(data); break; case LS_LOADING: loadEventLoading(data); break; case LS_LOADED: loadEventLoaded(data); break; case LS_ERROR: loadEventError(data); break; default: /* do nothing */ break; } } void TableObject::loadEventUnloaded(const uint8_t* data) { uint8_t event = data[0]; switch (event) { case LE_NOOP: case LE_LOAD_COMPLETED: case LE_ADDITIONAL_LOAD_CONTROLS: case LE_UNLOAD: break; case LE_START_LOADING: loadState(LS_LOADING); break; default: loadState(LS_ERROR); errorCode(E_GOT_UNDEF_LOAD_CMD); } } void TableObject::loadEventLoading(const uint8_t* data) { uint8_t event = data[0]; switch (event) { case LE_NOOP: case LE_START_LOADING: break; case LE_LOAD_COMPLETED: _memory.saveMemory(); loadState(LS_LOADED); break; case LE_UNLOAD: loadState(LS_UNLOADED); break; case LE_ADDITIONAL_LOAD_CONTROLS: additionalLoadControls(data); break; default: loadState(LS_ERROR); errorCode(E_GOT_UNDEF_LOAD_CMD); } } void TableObject::loadEventLoaded(const uint8_t* data) { uint8_t event = data[0]; switch (event) { case LE_NOOP: case LE_LOAD_COMPLETED: break; case LE_START_LOADING: loadState(LS_LOADING); break; case LE_UNLOAD: loadState(LS_UNLOADED); //free nv memory if (_data) { if (!_staticTableAdr) { _memory.freeMemory(_data); _data = 0; } } break; case LE_ADDITIONAL_LOAD_CONTROLS: loadState(LS_ERROR); errorCode(E_INVALID_OPCODE); break; default: loadState(LS_ERROR); errorCode(E_GOT_UNDEF_LOAD_CMD); } } void TableObject::loadEventError(const uint8_t* data) { uint8_t event = data[0]; switch (event) { case LE_NOOP: case LE_LOAD_COMPLETED: case LE_ADDITIONAL_LOAD_CONTROLS: case LE_START_LOADING: break; case LE_UNLOAD: loadState(LS_UNLOADED); break; default: loadState(LS_ERROR); errorCode(E_GOT_UNDEF_LOAD_CMD); } } void TableObject::additionalLoadControls(const uint8_t* data) { if (data[1] != 0x0B) // Data Relative Allocation { loadState(LS_ERROR); errorCode(E_INVALID_OPCODE); return; } size_t size = ((data[2] << 24) | (data[3] << 16) | (data[4] << 8) | data[5]); bool doFill = data[6] == 0x1; uint8_t fillByte = data[7]; if (!allocTable(size, doFill, fillByte)) { loadState(LS_ERROR); errorCode(E_MAX_TABLE_LENGTH_EXEEDED); } } uint8_t* TableObject::data() { return _data; } void TableObject::errorCode(ErrorCode errorCode) { uint8_t data = errorCode; Property* prop = property(PID_ERROR_CODE); prop->write(data); } uint16_t TableObject::saveSize() { return 5 + InterfaceObject::saveSize() + sizeof(_size); } void TableObject::initializeProperties(size_t propertiesSize, Property** properties) { Property* ownProperties[] = { new CallbackProperty(this, PID_LOAD_STATE_CONTROL, true, PDT_CONTROL, 1, ReadLv3 | WriteLv3, [](TableObject * obj, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { if (start == 0) { uint16_t currentNoOfElements = 1; pushWord(currentNoOfElements, data); return 1; } data[0] = obj->_state; return 1; }, [](TableObject * obj, uint16_t start, uint8_t count, const uint8_t* data) -> uint8_t { obj->loadEvent(data); return 1; }) }; uint8_t ownPropertiesCount = sizeof(ownProperties) / sizeof(Property*); uint8_t propertyCount = propertiesSize / sizeof(Property*); uint8_t allPropertiesCount = propertyCount + ownPropertiesCount; Property* allProperties[allPropertiesCount]; memcpy(allProperties, properties, propertiesSize); memcpy(allProperties + propertyCount, ownProperties, sizeof(ownProperties)); if (_staticTableAdr) InterfaceObject::initializeProperties(sizeof(allProperties), allProperties); else initializeDynTableProperties(sizeof(allProperties), allProperties); } void TableObject::initializeDynTableProperties(size_t propertiesSize, Property** properties) { Property* ownProperties[] = { new CallbackProperty(this, PID_TABLE_REFERENCE, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0, [](TableObject * obj, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t { if (start == 0) { uint16_t currentNoOfElements = 1; pushWord(currentNoOfElements, data); return 1; } if (obj->_state == LS_UNLOADED) pushInt(0, data); else pushInt(obj->tableReference(), data); return 1; }), new CallbackProperty(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) }; uint8_t ownPropertiesCount = sizeof(ownProperties) / sizeof(Property*); uint8_t propertyCount = propertiesSize / sizeof(Property*); uint8_t allPropertiesCount = propertyCount + ownPropertiesCount; Property* allProperties[allPropertiesCount]; memcpy(allProperties, properties, propertiesSize); memcpy(allProperties + propertyCount, ownProperties, sizeof(ownProperties)); InterfaceObject::initializeProperties(sizeof(allProperties), allProperties); }