Program Listing for File table_object.cpp
↰ Return to documentation for file (src/knx/table_object.cpp)
#include <string.h>
#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<TableObject>(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<TableObject>(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<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)
};
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);
}