From 4cc8b2bb369b5bd8aef30c1ae1e1231dffcd6417 Mon Sep 17 00:00:00 2001 From: Thomas Kunze Date: Thu, 12 Dec 2019 19:34:29 +0100 Subject: [PATCH] Finish refactoring of IpParameterObject --- src/knx/callback_property.h | 2 +- src/knx/data_property.cpp | 64 +++++++- src/knx/data_property.h | 8 +- src/knx/interface_object.cpp | 59 +++++++- src/knx/interface_object.h | 9 +- src/knx/ip_parameter_object.cpp | 256 +++++++++----------------------- src/knx/property.cpp | 12 +- src/knx/property.h | 14 +- src/knx/save_restore.h | 2 +- 9 files changed, 224 insertions(+), 202 deletions(-) diff --git a/src/knx/callback_property.h b/src/knx/callback_property.h index e2205c7..8e83183 100644 --- a/src/knx/callback_property.h +++ b/src/knx/callback_property.h @@ -18,7 +18,7 @@ template class CallbackProperty : public Property : Property(id, writeEnable, type, maxElements, access), _interfaceObject(io), _readCallback(readCallback) {} - virtual uint8_t read(uint16_t start, uint8_t count, uint8_t* data) override + virtual uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const override { if (count == 0 || _readCallback == nullptr || start > _maxElements || start + count > _maxElements + 1) return 0; diff --git a/src/knx/data_property.cpp b/src/knx/data_property.cpp index a349aa8..ec60447 100644 --- a/src/knx/data_property.cpp +++ b/src/knx/data_property.cpp @@ -3,7 +3,7 @@ #include -uint8_t DataProperty::read(uint16_t start, uint8_t count, uint8_t* data) +uint8_t DataProperty::read(uint16_t start, uint8_t count, uint8_t* data) const { if (count == 0 || _currentElements == 0 || start > _currentElements || count > _currentElements - start + 1) return 0; @@ -94,3 +94,65 @@ DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType typ write(1, 1, data); } } + +DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, + uint16_t maxElements, uint8_t access, uint32_t value) + : Property(id, writeEnable, type, maxElements, access) +{ + uint8_t elementSize = ElementSize(); + if (elementSize == 4) + { + uint8_t data[elementSize]; + pushInt(value, data); + write(1, 1, data); + } +} + +DataProperty::DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, + uint16_t maxElements, uint8_t access, uint8_t value) + : Property(id, writeEnable, type, maxElements, access) +{ + uint8_t elementSize = ElementSize(); + if (elementSize == 1) + { + uint8_t data[elementSize]; + data[0] = value; + write(1, 1, data); + } +} + +uint16_t DataProperty::saveSize() +{ + return sizeof(_currentElements) + _maxElements * ElementSize(); +} + + +uint8_t* DataProperty::restore(uint8_t* buffer) +{ + uint16_t elements = 0; + buffer = popWord(elements, buffer); + + if (elements != _currentElements) + { + if (_data != nullptr) + delete[] _data; + + _data = new uint8_t[elements * ElementSize()]; + _currentElements = elements; + } + + if (elements > 0) + buffer = popByteArray(_data, elements * ElementSize(), buffer); + + return buffer; +} + + +uint8_t* DataProperty::save(uint8_t* buffer) +{ + buffer = pushWord(_currentElements, buffer); + if (_currentElements > 0) + buffer = pushByteArray(_data, _currentElements, buffer); + + return buffer; +} diff --git a/src/knx/data_property.h b/src/knx/data_property.h index 3b81ff7..69efa37 100644 --- a/src/knx/data_property.h +++ b/src/knx/data_property.h @@ -6,10 +6,16 @@ class DataProperty : public Property { public: DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access); + DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, uint8_t value); DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, uint16_t value); + DataProperty(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access, uint32_t value); virtual ~DataProperty() override; - virtual uint8_t read(uint16_t start, uint8_t count, uint8_t* data) override; + virtual uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const override; virtual uint8_t write(uint16_t start, uint8_t count, uint8_t* data) override; + virtual uint8_t* save(uint8_t* buffer) override; + virtual uint8_t* restore(uint8_t* buffer) override; + virtual uint16_t saveSize() override; + private: uint16_t _currentElements = 0; uint8_t* _data = nullptr; diff --git a/src/knx/interface_object.cpp b/src/knx/interface_object.cpp index 95cf135..9a03f84 100644 --- a/src/knx/interface_object.cpp +++ b/src/knx/interface_object.cpp @@ -15,7 +15,7 @@ void InterfaceObject::readPropertyDescription(uint8_t& propertyId, uint8_t& prop numberOfElements = 0; if (descriptions == nullptr || count == 0) - return; + return readPropertyDescription2(propertyId, propertyIndex, writeEnable, type, numberOfElements, access); PropertyDescription* desc = nullptr; @@ -52,6 +52,53 @@ void InterfaceObject::readPropertyDescription(uint8_t& propertyId, uint8_t& prop numberOfElements = desc->MaxElements; access = desc->Access; } + else + return readPropertyDescription2(propertyId, propertyIndex, writeEnable, type, numberOfElements, access); +} + +void InterfaceObject::readPropertyDescription2(uint8_t& propertyId, uint8_t& propertyIndex, bool& writeEnable, uint8_t& type, uint16_t& numberOfElements, uint8_t& access) +{ + uint8_t count = _propertyCount; + + numberOfElements = 0; + if (_properties == nullptr || count == 0) + return; + + Property* prop = nullptr; + + // from KNX spec. 03.03.07 Application Layer (page 56) - 3.4.3.3 A_PropertyDescription_Read-service + // Summary: either propertyId OR propertyIndex, but not both at the same time + if (propertyId != 0) + { + for (uint8_t i = 0; i < count; i++) + { + Property* p = _properties[i]; + if (p->Id() != propertyId) + continue; + + prop = p; + propertyIndex = i; + break; + } + } + else + { + // If propertyId is zero, propertyIndex shall be used. + // Response: propertyIndex of received A_PropertyDescription_Read + if (propertyIndex < count) + { + prop = _properties[propertyIndex]; + } + } + + if (prop != nullptr) + { + propertyId = prop->Id(); + writeEnable = prop->WriteEnable(); + type = prop->Type(); + numberOfElements = prop->MaxElements(); + access = prop->Access(); + } } void InterfaceObject::readProperty(PropertyID id, uint16_t start, uint8_t& count, uint8_t* data) @@ -160,3 +207,13 @@ uint16_t InterfaceObject::saveSize() } return size; } + + +const Property* InterfaceObject::property(PropertyID id) const +{ + for (int i = 0; i < _propertyCount; i++) + if (_properties[i]->Id() == id) + return _properties[i]; + + return nullptr; +} diff --git a/src/knx/interface_object.h b/src/knx/interface_object.h index ff28413..f3f2507 100644 --- a/src/knx/interface_object.h +++ b/src/knx/interface_object.h @@ -116,9 +116,9 @@ class InterfaceObject : public SaveRestore * * @param[out] access the ::AccessLevel necessary to read/write the property. */ - + // TODO: remove first version after complete property refactoring void readPropertyDescription(uint8_t& propertyId, uint8_t& propertyIndex, bool& writeEnable, uint8_t& type, uint16_t& numberOfElements, uint8_t& access); - + void readPropertyDescription2(uint8_t& propertyId, uint8_t& propertyIndex, bool& writeEnable, uint8_t& type, uint16_t& numberOfElements, uint8_t& access); /** * Gets object type. * @@ -131,6 +131,11 @@ class InterfaceObject : public SaveRestore */ Property* property(PropertyID id); + /** + * Gets const property with PropertyID id if it exists and nullptr otherwise. + */ + const Property* property(PropertyID id) const; + virtual uint8_t* save(uint8_t* buffer) override; virtual uint8_t* restore(uint8_t* buffer) override; virtual uint16_t saveSize() override; diff --git a/src/knx/ip_parameter_object.cpp b/src/knx/ip_parameter_object.cpp index 78462be..9ffb221 100644 --- a/src/knx/ip_parameter_object.cpp +++ b/src/knx/ip_parameter_object.cpp @@ -13,11 +13,14 @@ IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platf { Property* properties[] = { - new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, OT_IP_PARAMETER), + new DataProperty(PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0, (uint16_t)OT_IP_PARAMETER), new DataProperty(PID_PROJECT_INSTALLATION_ID, true, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv3), new CallbackProperty(this, PID_KNX_INDIVIDUAL_ADDRESS, true, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv3, [](IpParameterObject* io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t - { + { + if(start == 0) + return 1; + // TODO: get property of deviceobject and use it pushWord(io->_deviceObject.induvidualAddress(), data); return 1; }, @@ -26,195 +29,84 @@ IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platf io->_deviceObject.induvidualAddress(getWord(data)); return 1; }), - //55 PID_IP_ASSIGNMENT_METHOD 3 / 3 - //56 PID_IP_CAPABILITIES 3 / 1 - //57 PID_CURRENT_IP_ADDRESS 3 / x - //58 PID_CURRENT_SUBNET_MASK 3 / x - //59 PID_CURRENT_DEFAULT_GATEWAY 3 / x - //60 PID_IP_ADDRESS 3 / 3 - //61 PID_SUBNET_MASK 3 / 3 - //62 PID_DEFAULT_GATEWAY 3 / 3 - //64 PID_MAC_ADDRESS 3 / x - //65 PID_SYSTEM_SETUP_MULTICAST_ADDRESS 3 / x - //66 PID_ROUTING_MULTICAST_ADDRESS 3 / 3 - //67 PID_TTL 3 / 3 - //68 PID_KNXNETIP_DEVICE_CAPABILITIES 3 / x - //76 PID_FRIENDLY_NAME 3 / 3 + new DataProperty(PID_IP_ASSIGNMENT_METHOD, true, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv3), + new DataProperty(PID_IP_CAPABILITIES, true, PDT_BITSET8, 1, ReadLv3 | WriteLv1), + new CallbackProperty(this, PID_CURRENT_IP_ADDRESS, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0, + [](IpParameterObject* io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t + { + if(start == 0) + return 1; + + pushInt(io->_platform.currentIpAddress(), data); + return 1; + }), + new CallbackProperty(this, PID_CURRENT_SUBNET_MASK, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0, + [](IpParameterObject* io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t + { + if(start == 0) + return 1; + + pushInt(io->_platform.currentSubnetMask(), data); + return 1; + }), + new CallbackProperty(this, PID_CURRENT_DEFAULT_GATEWAY, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0, + [](IpParameterObject* io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t + { + if(start == 0) + return 1; + + pushInt(io->_platform.currentDefaultGateway(), data); + return 1; + }), + new DataProperty(PID_IP_ADDRESS, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3), + new DataProperty(PID_SUBNET_MASK, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3), + new DataProperty(PID_DEFAULT_GATEWAY, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3), + new CallbackProperty(this, PID_MAC_ADDRESS, false, PDT_GENERIC_06, 1, ReadLv3 | WriteLv0, + [](IpParameterObject* io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t + { + if(start == 0) + return 1; + + io->_platform.macAddress(data); + return 1; + }), + new CallbackProperty(this, PID_SYSTEM_SETUP_MULTICAST_ADDRESS, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0, + [](IpParameterObject* io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t + { + if(start == 0) + return 1; + + pushInt(DEFAULT_MULTICAST_ADDR, data); + return 1; + }), + new DataProperty(PID_ROUTING_MULTICAST_ADDRESS, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3, DEFAULT_MULTICAST_ADDR), + new DataProperty(PID_TTL, true, PDT_UNSIGNED_CHAR, 1, ReadLv3 | WriteLv3, (uint8_t)16), + new CallbackProperty(this, PID_KNXNETIP_DEVICE_CAPABILITIES, false, PDT_BITSET16, 1, ReadLv3 | WriteLv0, + [](IpParameterObject* io, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t + { + if(start == 0) + return 1; + + pushWord(0x1, data); + return 1; + }), + new DataProperty(PID_FRIENDLY_NAME, true, PDT_UNSIGNED_CHAR, 30, ReadLv3 | WriteLv3) }; initializeProperties(sizeof(properties), properties); } -void IpParameterObject::readProperty(PropertyID propertyId, uint16_t start, uint8_t& count, uint8_t* data) -{ - switch (propertyId) - { - case PID_IP_ASSIGNMENT_METHOD: - data[0] = _ipAssignmentMethod; - break; - case PID_IP_CAPABILITIES: - data[0] = _ipCapabilities; - break; - case PID_CURRENT_IP_ADDRESS: - pushInt(_platform.currentIpAddress(), data); - break; - case PID_CURRENT_SUBNET_MASK: - pushInt(_platform.currentSubnetMask(), data); - break; - case PID_CURRENT_DEFAULT_GATEWAY: - pushInt(_platform.currentDefaultGateway(), data); - break; - case PID_IP_ADDRESS: - pushInt(_ipAddress, data); - break; - case PID_SUBNET_MASK: - pushInt(_subnetMask, data); - break; - case PID_DEFAULT_GATEWAY: - pushInt(_defaultGateway, data); - break; - case PID_MAC_ADDRESS: - { - uint8_t macAddr[6] = { 0, 0, 0, 0, 0, 0 }; - _platform.macAddress(macAddr); - pushByteArray(macAddr, 6, data); - break; - } - case PID_SYSTEM_SETUP_MULTICAST_ADDRESS: - pushInt(DEFAULT_MULTICAST_ADDR, data); - break; - case PID_ROUTING_MULTICAST_ADDRESS: - pushInt(_multicastAddress, data); - break; - case PID_TTL: - data[0] = ttl(); - break; - case PID_KNXNETIP_DEVICE_CAPABILITIES: - data[0] = 0x1; - break; - case PID_FRIENDLY_NAME: - for (uint8_t i = start; i < start + count; i++) - data[i-start] = _friendlyName[i-1]; - break; - default: - InterfaceObject::readProperty(propertyId, start, count, data); - break; - } -} - -void IpParameterObject::writeProperty(PropertyID id, uint16_t start, uint8_t* data, uint8_t& count) -{ - switch (id) - { - case PID_IP_ASSIGNMENT_METHOD: - _ipAssignmentMethod = data[0]; - break; - case PID_IP_ADDRESS: - _ipAddress = getInt(data); - break; - case PID_SUBNET_MASK: - _subnetMask = getInt(data); - break; - case PID_DEFAULT_GATEWAY: - _defaultGateway = getInt(data); - break; - case PID_ROUTING_MULTICAST_ADDRESS: - _multicastAddress = getInt(data); - break; - case PID_TTL: - _ttl = data[0]; - break; - case PID_FRIENDLY_NAME: - for (uint8_t i = start; i < start + count; i++) - _friendlyName[i-1] = data[i - start]; - break; - default: - InterfaceObject::writeProperty(id, start, data, count); - break; - } -} - -uint8_t IpParameterObject::propertySize(PropertyID id) -{ - switch (id) - { - case PID_IP_ASSIGNMENT_METHOD: - case PID_LOAD_STATE_CONTROL: - case PID_IP_CAPABILITIES: - case PID_TTL: - case PID_KNXNETIP_DEVICE_CAPABILITIES: - case PID_FRIENDLY_NAME: - return 1; - case PID_KNX_INDIVIDUAL_ADDRESS: - return 2; - case PID_CURRENT_IP_ADDRESS: - case PID_CURRENT_SUBNET_MASK: - case PID_CURRENT_DEFAULT_GATEWAY: - case PID_IP_ADDRESS: - case PID_SUBNET_MASK: - case PID_DEFAULT_GATEWAY: - case PID_SYSTEM_SETUP_MULTICAST_ADDRESS: - case PID_ROUTING_MULTICAST_ADDRESS: - return 4; - case PID_MAC_ADDRESS: - return 6; - } - return InterfaceObject::propertySize(id); -} - -uint8_t* IpParameterObject::save(uint8_t* buffer) -{ - buffer = pushWord(_projectInstallationId, buffer); - buffer = pushByte(_ipAssignmentMethod, buffer); - buffer = pushByte(_ipCapabilities, buffer); - buffer = pushInt(_ipAddress, buffer); - buffer = pushInt(_subnetMask, buffer); - buffer = pushInt(_defaultGateway, buffer); - buffer = pushInt(_multicastAddress, buffer); - buffer = pushByte(_ttl, buffer); - buffer = pushByteArray((uint8_t*)_friendlyName, 30, buffer); - - return buffer; -} - -uint8_t* IpParameterObject::restore(uint8_t* buffer) -{ - buffer = popWord(_projectInstallationId, buffer); - buffer = popByte(_ipAssignmentMethod, buffer); - buffer = popByte(_ipCapabilities, buffer); - buffer = popInt(_ipAddress, buffer); - buffer = popInt(_subnetMask, buffer); - buffer = popInt(_defaultGateway, buffer); - buffer = popInt(_multicastAddress, buffer); - buffer = popByte(_ttl, buffer); - buffer = popByteArray((uint8_t*)_friendlyName, 30, buffer); - - return buffer; -} - uint32_t IpParameterObject::multicastAddress() const { - if (_multicastAddress == 0) - return DEFAULT_MULTICAST_ADDR; + const Property* prop = property(PID_ROUTING_MULTICAST_ADDRESS); - return _multicastAddress; -} + uint8_t data[4]; + uint8_t count = prop->read(1, 1, data); -static PropertyDescription _propertyDescriptions[] = -{ - { PID_OBJECT_TYPE, false, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv0 }, - { PID_PROJECT_INSTALLATION_ID, true, PDT_UNSIGNED_INT, 1, ReadLv3 | WriteLv3 }, -}; -static uint8_t _propertyDescriptionCount = sizeof(_propertyDescriptions) / sizeof(PropertyDescription); + uint32_t value = DEFAULT_MULTICAST_ADDR; + if (count == 1) + popInt(value, data); -uint8_t IpParameterObject::propertyDescriptionCount() -{ - return _propertyDescriptionCount; -} - - -PropertyDescription* IpParameterObject::propertyDescriptions() -{ - return _propertyDescriptions; + return value; } uint16_t IpParameterObject::saveSize() diff --git a/src/knx/property.cpp b/src/knx/property.cpp index f72cd63..54141e6 100644 --- a/src/knx/property.cpp +++ b/src/knx/property.cpp @@ -3,32 +3,32 @@ #include -PropertyID Property::Id() +PropertyID Property::Id() const { return _id; } -bool Property::WriteEnable() +bool Property::WriteEnable() const { return _writeEnable; } -PropertyDataType Property::Type() +PropertyDataType Property::Type() const { return _type; } -uint16_t Property::MaxElements() +uint16_t Property::MaxElements() const { return _maxElements; } -uint8_t Property::Access() +uint8_t Property::Access() const { return _access; } -uint8_t Property::ElementSize() +uint8_t Property::ElementSize() const { switch (_type) { diff --git a/src/knx/property.h b/src/knx/property.h index 510a533..c581ad5 100644 --- a/src/knx/property.h +++ b/src/knx/property.h @@ -230,13 +230,13 @@ class Property : public SaveRestore public: Property(PropertyID id, bool writeEnable, PropertyDataType type, uint16_t maxElements, uint8_t access); virtual ~Property(); - PropertyID Id(); - bool WriteEnable(); - PropertyDataType Type(); - uint16_t MaxElements(); - uint8_t Access(); - uint8_t ElementSize(); - virtual uint8_t read(uint16_t start, uint8_t count, uint8_t* data) = 0; + PropertyID Id() const; + bool WriteEnable() const; + PropertyDataType Type() const; + uint16_t MaxElements() const; + uint8_t Access() const; + uint8_t ElementSize() const; + virtual uint8_t read(uint16_t start, uint8_t count, uint8_t* data) const = 0; virtual uint8_t write(uint16_t start, uint8_t count, uint8_t* data) = 0; protected: PropertyID _id; diff --git a/src/knx/save_restore.h b/src/knx/save_restore.h index fe39286..7d3e2f8 100644 --- a/src/knx/save_restore.h +++ b/src/knx/save_restore.h @@ -34,7 +34,7 @@ class SaveRestore } /** - * @return The number of byte the object needs to save its state. + * @return The maximum number of bytes the object needs to save its state. */ virtual uint16_t saveSize() {