Program Listing for File dptconvert.cpp
↰ Return to documentation for file (src/knx/dptconvert.cpp)
#include "dptconvert.h"
#include "bits.h"
#include <cmath>
#include <cstdlib>
#include <cstring>
#define ASSERT_PAYLOAD(x) \
if (payload_length != (x)) \
return false
#define ENSURE_PAYLOAD(x)
bool KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
if (payload_length > 0)
{
// DPT 1.* - Binary
if (datatype.mainGroup == 1 && datatype.subGroup >= 1 && datatype.subGroup <= 23 && datatype.subGroup != 20 && !datatype.index)
return busValueToBinary(payload, payload_length, datatype, value);
// DPT 2.* - Binary Control
if (datatype.mainGroup == 2 && datatype.subGroup >= 1 && datatype.subGroup <= 12 && datatype.index <= 1)
return busValueToBinaryControl(payload, payload_length, datatype, value);
// DPT 3.* - Step Control
if (datatype.mainGroup == 3 && datatype.subGroup >= 7 && datatype.subGroup <= 8 && datatype.index <= 1)
return busValueToStepControl(payload, payload_length, datatype, value);
// DPT 4.* - Character
if (datatype.mainGroup == 4 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && !datatype.index)
return busValueToCharacter(payload, payload_length, datatype, value);
// DPT 5.* - Unsigned 8 Bit Integer
if (datatype.mainGroup == 5 && ((datatype.subGroup >= 1 && datatype.subGroup <= 6 && datatype.subGroup != 2) || datatype.subGroup == 10) && !datatype.index)
return busValueToUnsigned8(payload, payload_length, datatype, value);
// DPT 6.001/6.010 - Signed 8 Bit Integer
if (datatype.mainGroup == 6 && (datatype.subGroup == 1 || datatype.subGroup == 10) && !datatype.index)
return busValueToSigned8(payload, payload_length, datatype, value);
// DPT 6.020 - Status with Mode
if (datatype.mainGroup == 6 && datatype.subGroup == 20 && datatype.index <= 5)
return busValueToStatusAndMode(payload, payload_length, datatype, value);
// DPT 7.001/7.010/7.011/7.012/7.013/7.600 - Unsigned 16 Bit Integer
if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13) || (datatype.subGroup == 600)) && !datatype.index)
return busValueToUnsigned16(payload, payload_length, datatype, value);
// DPT 7.002-DPT 7.007 - Time Period
if (datatype.mainGroup == 7 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
return busValueToTimePeriod(payload, payload_length, datatype, value);
// DPT 8.001/8.010/8.011 - Signed 16 Bit Integer
if (datatype.mainGroup == 8 && (datatype.subGroup == 1 || datatype.subGroup == 10 || datatype.subGroup == 11) && !datatype.index)
return busValueToSigned16(payload, payload_length, datatype, value);
// DPT 8.002-DPT 8.007 - Time Delta
if (datatype.mainGroup == 8 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
return busValueToTimeDelta(payload, payload_length, datatype, value);
// DPT 9.* - 16 Bit Float
if (datatype.mainGroup == 9 && ((datatype.subGroup >= 1 && datatype.subGroup <= 11) || (datatype.subGroup >= 20 && datatype.subGroup <= 29)) && !datatype.index)
return busValueToFloat16(payload, payload_length, datatype, value);
// DPT 10.* - Time and Weekday
if (datatype.mainGroup == 10 && datatype.subGroup == 1 && datatype.index <= 1)
return busValueToTime(payload, payload_length, datatype, value);
// DPT 11.* - Date
if (datatype.mainGroup == 11 && datatype.subGroup == 1 && !datatype.index)
return busValueToDate(payload, payload_length, datatype, value);
// DPT 12.* - Unsigned 32 Bit Integer
if (datatype.mainGroup == 12 && datatype.subGroup == 1 && !datatype.index)
return busValueToUnsigned32(payload, payload_length, datatype, value);
// DPT 13.001/13.002/13.010-13.015 - Signed 32 Bit Integer
if (datatype.mainGroup == 13 && (datatype.subGroup == 1 || datatype.subGroup == 2 || (datatype.subGroup >= 10 && datatype.subGroup <= 15)) && !datatype.index)
return busValueToSigned32(payload, payload_length, datatype, value);
// DPT 13.100 - Long Time Period
if (datatype.mainGroup == 13 && datatype.subGroup == 100 && !datatype.index)
return busValueToLongTimePeriod(payload, payload_length, datatype, value);
// DPT 14.* - 32 Bit Float
if (datatype.mainGroup == 14 && datatype.subGroup <= 79 && !datatype.index)
return busValueToFloat32(payload, payload_length, datatype, value);
// DPT 15.* - Access Data
if (datatype.mainGroup == 15 && !datatype.subGroup && datatype.index <= 5)
return busValueToAccess(payload, payload_length, datatype, value);
// DPT 16.* - String
if (datatype.mainGroup == 16 && datatype.subGroup <= 1 && !datatype.index)
return busValueToString(payload, payload_length, datatype, value);
// DPT 17.* - Scene Number
if (datatype.mainGroup == 17 && datatype.subGroup == 1 && !datatype.index)
return busValueToScene(payload, payload_length, datatype, value);
// DPT 18.* - Scene Control
if (datatype.mainGroup == 18 && datatype.subGroup == 1 && datatype.index <= 1)
return busValueToSceneControl(payload, payload_length, datatype, value);
// DPT 19.* - Date and Time
if (datatype.mainGroup == 19 && datatype.subGroup == 1 && (datatype.index <= 3 || datatype.index == 9 || datatype.index == 10))
return busValueToDateTime(payload, payload_length, datatype, value);
// DPT 20.* - HVAC Control mode Unsigned 8 Bit Integer
if (datatype.mainGroup == 20 && !datatype.index)
return busValueToUnsigned8(payload, payload_length, datatype, value);
// DPT 26.* - Scene Info
if (datatype.mainGroup == 26 && datatype.subGroup == 1 && datatype.index <= 1)
return busValueToSceneInfo(payload, payload_length, datatype, value);
// DPT 27.001 - 32 Bit field
if (datatype.mainGroup == 27 && datatype.subGroup == 1 && !datatype.index)
return busValueToSigned32(payload, payload_length, datatype, value);
// DPT 28.* - Unicode String
if (datatype.mainGroup == 28 && datatype.subGroup == 1 && !datatype.index)
return busValueToUnicode(payload, payload_length, datatype, value);
// DPT 29.* - Signed 64 Bit Integer
if (datatype.mainGroup == 29 && datatype.subGroup >= 10 && datatype.subGroup <= 12 && !datatype.index)
return busValueToSigned64(payload, payload_length, datatype, value);
// DPT 219.* - Alarm Info
if (datatype.mainGroup == 219 && datatype.subGroup == 1 && datatype.index <= 10)
return busValueToAlarmInfo(payload, payload_length, datatype, value);
// DPT 221.* - Serial Number
if (datatype.mainGroup == 221 && datatype.subGroup == 1 && datatype.index <= 1)
return busValueToSerialNumber(payload, payload_length, datatype, value);
// DPT 217.* - Version
if (datatype.mainGroup == 217 && datatype.subGroup == 1 && datatype.index <= 2)
return busValueToVersion(payload, payload_length, datatype, value);
// DPT 225.001/225.002 - Scaling Speed and Scaling Step Time
if (datatype.mainGroup == 225 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && datatype.index <= 1)
return busValueToScaling(payload, payload_length, datatype, value);
// DPT 225.003 - Next Tariff
if (datatype.mainGroup == 225 && datatype.subGroup == 3 && datatype.index <= 1)
return busValueToTariff(payload, payload_length, datatype, value);
// DPT 231.* - Locale
if (datatype.mainGroup == 231 && datatype.subGroup == 1 && datatype.index <= 1)
return busValueToLocale(payload, payload_length, datatype, value);
// DPT 232.600 - RGB
if (datatype.mainGroup == 232 && datatype.subGroup == 600 && !datatype.index)
return busValueToRGB(payload, payload_length, datatype, value);
// DPT 234.* - Language and Region
if (datatype.mainGroup == 234 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && !datatype.index)
return busValueToLocale(payload, payload_length, datatype, value);
// DPT 235.* - Active Energy
if (datatype.mainGroup == 235 && datatype.subGroup == 1 && datatype.index <= 3)
return busValueToActiveEnergy(payload, payload_length, datatype, value);
// DPT 238.* - Scene Config
if (datatype.mainGroup == 238 && datatype.subGroup == 1 && datatype.index <= 2)
return busValueToSceneConfig(payload, payload_length, datatype, value);
// DPT 239.* - Flagged Scaling
if (datatype.mainGroup == 239 && datatype.subGroup == 1 && datatype.index <= 1)
return busValueToFlaggedScaling(payload, payload_length, datatype, value);
// DPT 251.600 - RGBW
if (datatype.mainGroup == 251 && datatype.subGroup == 600 && datatype.index <= 1)
return busValueToRGBW(payload, payload_length, datatype, value);
}
return false;
}
bool KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
if (datatype.mainGroup == 1 && datatype.subGroup >= 1 && datatype.subGroup <= 23 && datatype.subGroup != 20 && !datatype.index)
return valueToBusValueBinary(value, payload, payload_length, datatype);
// DPT 2.* - Binary Control
if (datatype.mainGroup == 2 && datatype.subGroup >= 1 && datatype.subGroup <= 12 && datatype.index <= 1)
return valueToBusValueBinaryControl(value, payload, payload_length, datatype);
// DPT 3.* - Step Control
if (datatype.mainGroup == 3 && datatype.subGroup >= 7 && datatype.subGroup <= 8 && datatype.index <= 1)
return valueToBusValueStepControl(value, payload, payload_length, datatype);
// DPT 4.* - Character
if (datatype.mainGroup == 4 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && !datatype.index)
return valueToBusValueCharacter(value, payload, payload_length, datatype);
// DPT 5.* - Unsigned 8 Bit Integer
if (datatype.mainGroup == 5 && ((datatype.subGroup >= 1 && datatype.subGroup <= 6 && datatype.subGroup != 2) || datatype.subGroup == 10) && !datatype.index)
return valueToBusValueUnsigned8(value, payload, payload_length, datatype);
// DPT 6.001/6.010 - Signed 8 Bit Integer
if (datatype.mainGroup == 6 && (datatype.subGroup == 1 || datatype.subGroup == 10) && !datatype.index)
return valueToBusValueSigned8(value, payload, payload_length, datatype);
// DPT 6.020 - Status with Mode
if (datatype.mainGroup == 6 && datatype.subGroup == 20 && datatype.index <= 5)
return valueToBusValueStatusAndMode(value, payload, payload_length, datatype);
// DPT 7.001/7.010/7.011/7.012/7.013/7.600 - Unsigned 16 Bit Integer
if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13) || datatype.subGroup == 600) && !datatype.index)
return valueToBusValueUnsigned16(value, payload, payload_length, datatype);
// DPT 7.002-DPT 7.007 - Time Period
if (datatype.mainGroup == 7 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
return valueToBusValueTimePeriod(value, payload, payload_length, datatype);
// DPT 8.001/8.010/8.011 - Signed 16 Bit Integer
if (datatype.mainGroup == 8 && (datatype.subGroup == 1 || datatype.subGroup == 10 || datatype.subGroup == 11) && !datatype.index)
return valueToBusValueSigned16(value, payload, payload_length, datatype);
// DPT 8.002-DPT 8.007 - Time Delta
if (datatype.mainGroup == 8 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
return valueToBusValueTimeDelta(value, payload, payload_length, datatype);
// DPT 9.* - 16 Bit Float
if (datatype.mainGroup == 9 && ((datatype.subGroup >= 1 && datatype.subGroup <= 11 ) || (datatype.subGroup >= 20 && datatype.subGroup <= 29)) && !datatype.index)
return valueToBusValueFloat16(value, payload, payload_length, datatype);
// DPT 10.* - Time and Weekday
if (datatype.mainGroup == 10 && datatype.subGroup == 1 && datatype.index <= 1)
return valueToBusValueTime(value, payload, payload_length, datatype);
// DPT 11.* - Date
if (datatype.mainGroup == 11 && datatype.subGroup == 1 && !datatype.index)
return valueToBusValueDate(value, payload, payload_length, datatype);
// DPT 12.* - Unsigned 32 Bit Integer
if (datatype.mainGroup == 12 && datatype.subGroup == 1 && !datatype.index)
return valueToBusValueUnsigned32(value, payload, payload_length, datatype);
// DPT 13.001/13.002/13.010-13.015 - Signed 32 Bit Integer
if (datatype.mainGroup == 13 && (datatype.subGroup == 1 || datatype.subGroup == 2 || (datatype.subGroup >= 10 && datatype.subGroup <= 15)) && !datatype.index)
return valueToBusValueSigned32(value, payload, payload_length, datatype);
// DPT 13.100 - Long Time Period
if (datatype.mainGroup == 13 && datatype.subGroup == 100 && !datatype.index)
return valueToBusValueLongTimePeriod(value, payload, payload_length, datatype);
// DPT 14.* - 32 Bit Float
if (datatype.mainGroup == 14 && datatype.subGroup <= 79 && !datatype.index)
return valueToBusValueFloat32(value, payload, payload_length, datatype);
// DPT 15.* - Access Data
if (datatype.mainGroup == 15 && !datatype.subGroup && datatype.index <= 5)
return valueToBusValueAccess(value, payload, payload_length, datatype);
// DPT 16.* - String
if (datatype.mainGroup == 16 && datatype.subGroup <= 1 && !datatype.index)
return valueToBusValueString(value, payload, payload_length, datatype);
// DPT 17.* - Scene Number
if (datatype.mainGroup == 17 && datatype.subGroup == 1 && !datatype.index)
return valueToBusValueScene(value, payload, payload_length, datatype);
// DPT 18.* - Scene Control
if (datatype.mainGroup == 18 && datatype.subGroup == 1 && datatype.index <= 1)
return valueToBusValueSceneControl(value, payload, payload_length, datatype);
// DPT 19.* - Date and Time
if (datatype.mainGroup == 19 && datatype.subGroup == 1 && (datatype.index <= 3 || datatype.index == 9 || datatype.index == 10))
return valueToBusValueDateTime(value, payload, payload_length, datatype);
// DPT 20.* - HVAC Control mode Unsigned 8 Bit Integer
if (datatype.mainGroup == 20 && !datatype.index)
return valueToBusValueUnsigned8(value, payload, payload_length, datatype);
// DPT 26.* - Scene Info
if (datatype.mainGroup == 26 && datatype.subGroup == 1 && datatype.index <= 1)
return valueToBusValueSceneInfo(value, payload, payload_length, datatype);
// DPT 27.001 - 32 Bit Field
if (datatype.mainGroup == 27 && datatype.subGroup == 1 && !datatype.index)
return valueToBusValueUnsigned32(value, payload, payload_length, datatype);
// DPT 28.* - Unicode String
if (datatype.mainGroup == 28 && datatype.subGroup == 1 && !datatype.index)
return valueToBusValueUnicode(value, payload, payload_length, datatype);
// DPT 29.* - Signed 64 Bit Integer
if (datatype.mainGroup == 29 && datatype.subGroup >= 10 && datatype.subGroup <= 12 && !datatype.index)
return valueToBusValueSigned64(value, payload, payload_length, datatype);
// DPT 219.* - Alarm Info
if (datatype.mainGroup == 219 && datatype.subGroup == 1 && datatype.index <= 10)
return valueToBusValueAlarmInfo(value, payload, payload_length, datatype);
// DPT 221.* - Serial Number
if (datatype.mainGroup == 221 && datatype.subGroup == 1 && datatype.index <= 1)
return valueToBusValueSerialNumber(value, payload, payload_length, datatype);
// DPT 217.* - Version
if (datatype.mainGroup == 217 && datatype.subGroup == 1 && datatype.index <= 2)
return valueToBusValueVersion(value, payload, payload_length, datatype);
// DPT 225.001/225.002 - Scaling Speed and Scaling Step Time
if (datatype.mainGroup == 225 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && datatype.index <= 1)
return valueToBusValueScaling(value, payload, payload_length, datatype);
// DPT 225.003 - Next Tariff
if (datatype.mainGroup == 225 && datatype.subGroup == 3 && datatype.index <= 1)
return valueToBusValueTariff(value, payload, payload_length, datatype);
// DPT 231.* - Locale
if (datatype.mainGroup == 231 && datatype.subGroup == 1 && datatype.index <= 1)
return valueToBusValueLocale(value, payload, payload_length, datatype);
// DPT 232.600 - RGB
if (datatype.mainGroup == 232 && datatype.subGroup == 600 && !datatype.index)
return valueToBusValueRGB(value, payload, payload_length, datatype);
// DPT 234.* - Language and Region
if (datatype.mainGroup == 234 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && !datatype.index)
return valueToBusValueLocale(value, payload, payload_length, datatype);
// DPT 235.* - Active Energy
if (datatype.mainGroup == 235 && datatype.subGroup == 1 && datatype.index <= 3)
return valueToBusValueActiveEnergy(value, payload, payload_length, datatype);
// DPT 238.* - Scene Config
if (datatype.mainGroup == 238 && datatype.subGroup == 1 && datatype.index <= 2)
return valueToBusValueSceneConfig(value, payload, payload_length, datatype);
// DPT 239.* - Flagged Scaling
if (datatype.mainGroup == 239 && datatype.subGroup == 1 && datatype.index <= 1)
return valueToBusValueFlaggedScaling(value, payload, payload_length, datatype);
// DPT 251.600 - RGBW
if (datatype.mainGroup == 251 && datatype.subGroup == 600 && datatype.index <= 1)
return valueToBusValueRGBW(value, payload, payload_length, datatype);
return false;
}
bool busValueToBinary(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(1);
value = bitFromPayload(payload, 7);
return true;
}
bool busValueToBinaryControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(1);
value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x03);
return true;
}
bool busValueToStepControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(1);
value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x0F);
return true;
}
bool busValueToCharacter(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(1);
int8_t charValue = signed8FromPayload(payload, 0);
if (datatype.subGroup == 1 && (charValue & 0x80))
return false;
if (datatype.subGroup == 2)
{
value = (uint8_t)charValue;
return true;
}
value = charValue;
return true;
}
bool busValueToUnsigned8(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(1);
switch (datatype.subGroup)
{
case 1:
value = (uint8_t)round(unsigned8FromPayload(payload, 0) * 100.0 / 255.0);
return true;
case 3:
value = (uint8_t)round(unsigned8FromPayload(payload, 0) * 360.0 / 255.0);
return true;
case 6:
{
uint8_t numValue = unsigned8FromPayload(payload, 0);
if (numValue == 0xFF)
return false;
value = numValue;
return true;
}
}
value = unsigned8FromPayload(payload, 0);
return true;
}
bool busValueToSigned8(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(1);
value = (uint8_t)(unsigned8FromPayload(payload, 0));
return true;
}
bool busValueToStatusAndMode(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(1);
if (datatype.index < 5)
{
value = bitFromPayload(payload, datatype.index);
return true;
}
else if (datatype.index == 5)
{
value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x07);
return true;
}
return false;
}
bool busValueToUnsigned16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(2);
value = unsigned16FromPayload(payload, 0);
return true;
}
bool busValueToTimePeriod(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(2);
int64_t duration = unsigned16FromPayload(payload, 0);
value = duration;
return true;
}
bool busValueToSigned16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(2);
if (datatype.subGroup == 10)
{
value = signed16FromPayload(payload, 0) / 100.0;
return true;
}
value = signed16FromPayload(payload, 0);
return true;
}
bool busValueToTimeDelta(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(2);
int64_t duration = signed16FromPayload(payload, 0);
value = duration;
return true;
}
bool busValueToFloat16(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(2);
if (unsigned16FromPayload(payload, 0) == 0x7FFF)
return false;
value = float16FromPayload(payload, 0);
return true;
}
bool busValueToTime(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(3);
switch (datatype.index)
{
case 0:
value = (uint8_t)((unsigned8FromPayload(payload, 0) >> 5) & 0x07);
return true;
case 1:
{
unsigned char hours = unsigned8FromPayload(payload, 0) & 0x1F;
unsigned char weekDay = (unsigned8FromPayload(payload, 0) & 0xE0) >> 5;
unsigned char minutes = unsigned8FromPayload(payload, 1) & 0x3F;
unsigned char seconds = unsigned8FromPayload(payload, 2) & 0x3F;
if (hours > 23 || minutes > 59 || seconds > 59)
return false;
struct tm tmp;
memset(&tmp, 0, sizeof(tmp));
tmp.tm_hour = hours;
tmp.tm_wday = weekDay;
tmp.tm_min = minutes;
tmp.tm_sec = seconds;
value = tmp;
return true;
}
}
return false;
}
bool busValueToDate(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(3);
unsigned short year = unsigned8FromPayload(payload, 2) & 0x7F;
unsigned char month = unsigned8FromPayload(payload, 1) & 0x0F;
unsigned char day = unsigned8FromPayload(payload, 0) & 0x1F;
if (year > 99 || month < 1 || month > 12 || day < 1)
return false;
struct tm tmp;
memset(&tmp, 0, sizeof(tmp));
year += year >= 90 ? 1900 : 2000;
tmp.tm_mday = day;
tmp.tm_year = year;
tmp.tm_mon = month;
value = tmp;
return true;
}
bool busValueToUnsigned32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(4);
value = unsigned32FromPayload(payload, 0);
return true;
}
bool busValueToSigned32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(4);
value = signed32FromPayload(payload, 0);
return true;
}
bool busValueToLongTimePeriod(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(4);
value = signed32FromPayload(payload, 0);
return true;
}
bool busValueToFloat32(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(4);
value = float32FromPayload(payload, 0);
return true;
}
bool busValueToAccess(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(4);
switch (datatype.index)
{
case 0:
{
int32_t digits = 0;
for (int n = 0, factor = 100000; n < 6; ++n, factor /= 10)
{
unsigned char digit = bcdFromPayload(payload, n);
if (digit > 9)
return false;
digits += digit * factor;
}
value = digits;
return true;
}
case 1:
case 2:
case 3:
case 4:
value = bitFromPayload(payload, 23 + datatype.index);
return true;
case 5:
value = bcdFromPayload(payload, 7);
return true;
}
return false;
}
bool busValueToString(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(14);
for (int n = 0; n < 14; ++n)
{
auto value = signed8FromPayload(payload, n);
if (!datatype.subGroup && (value & 0x80))
return false;
}
value = (const char*) payload;
return true;
}
bool busValueToScene(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(1);
value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x3F);
return true;
}
bool busValueToSceneControl(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(1);
switch (datatype.index)
{
case 0:
{
value = bitFromPayload(payload, 0);
return true;
}
case 1:
{
value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x3F);
return true;
}
}
return false;
}
bool busValueToSceneInfo(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(1);
switch (datatype.index)
{
case 0:
{
value = bitFromPayload(payload, 1);
return true;
}
case 1:
{
value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x3F);
return true;
}
}
return false;
}
bool busValueToSceneConfig(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(1);
switch (datatype.index)
{
case 0:
{
value = (uint8_t)(unsigned8FromPayload(payload, 0) & 0x3F);
return true;
}
case 1:
case 2:
{
value = bitFromPayload(payload, 2 - datatype.index);
return true;
}
}
return false;
}
bool busValueToDateTime(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(8);
if (datatype.index == 3)
{
value = bitFromPayload(payload, 48);
return true;
}
if (!bitFromPayload(payload, 48))
{
switch (datatype.index)
{
case 0:
{
if (bitFromPayload(payload, 51) || bitFromPayload(payload, 52))
return false;
unsigned short year = unsigned8FromPayload(payload, 0) + 1900;
unsigned short month = unsigned8FromPayload(payload, 1) & 0x0F;
unsigned short day = unsigned8FromPayload(payload, 2) & 0x1F;
unsigned short hours = unsigned8FromPayload(payload, 3) & 0x1F;
unsigned short minutes = unsigned8FromPayload(payload, 4) & 0x3F;
unsigned short seconds = unsigned8FromPayload(payload, 5) & 0x3F;
if ((month < 1 || month > 12 || day < 1))
return false;
if ((hours > 24 || minutes > 59 || seconds > 59))
return false;
struct tm tmp;
memset(&tmp, 0, sizeof(tmp));
tmp.tm_sec = seconds;
tmp.tm_min = minutes;
tmp.tm_hour = hours;
tmp.tm_mday = day;
tmp.tm_mon = month;
tmp.tm_year = year;
value = tmp;
return true;
}
case 1:
{
if (bitFromPayload(payload, 53))
return false;
value = (uint8_t)((unsigned8FromPayload(payload, 3) >> 5) & 0x07);
return true;
}
case 2:
{
if (bitFromPayload(payload, 50))
return false;
value = bitFromPayload(payload, 49);
return true;
}
case 9:
{
value = bitFromPayload(payload, 55);
return true;
}
case 10:
{
value = bitFromPayload(payload, 56);
return true;
}
}
}
return false;
}
bool busValueToUnicode(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
//TODO
return false;
}
bool busValueToSigned64(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(8);
value = signed64FromPayload(payload, 0);
return true;
}
bool busValueToAlarmInfo(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(6);
switch (datatype.index)
{
case 1:
{
unsigned char prio = unsigned8FromPayload(payload, 1);
if (prio > 3)
return false;
value = prio;
return true;
}
case 0:
case 2:
case 3:
value = unsigned8FromPayload(payload, datatype.index);
return true;
case 4:
case 5:
case 6:
case 7:
value = bitFromPayload(payload, 43 - datatype.index);
return true;
case 8:
case 9:
case 10:
value = bitFromPayload(payload, 55 - datatype.index);
return true;
}
return false;
}
bool busValueToSerialNumber(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(6);
switch (datatype.index)
{
case 0:
value = unsigned16FromPayload(payload, 0);
return true;
case 1:
value = unsigned32FromPayload(payload, 2);
return true;
}
return false;
}
bool busValueToVersion(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(2);
switch (datatype.index)
{
case 0:
value = (uint8_t)((unsigned8FromPayload(payload, 0) >> 3) & 0x1F);
return true;
case 1:
value = (uint16_t)((unsigned16FromPayload(payload, 0) >> 6) & 0x1F);
return true;
case 2:
value = (uint8_t)(unsigned8FromPayload(payload, 1) & 0x3F);
return true;
}
return false;
}
bool busValueToScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(3);
switch (datatype.index)
{
case 0:
value = unsigned16FromPayload(payload, 0);
return true;
case 1:
value = (uint8_t)(unsigned8FromPayload(payload, 2) * 100.0 / 255.0);
return true;
}
return false;
}
bool busValueToTariff(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(3);
switch (datatype.index)
{
case 0:
value = unsigned16FromPayload(payload, 0);
return true;
case 1:
{
uint8_t tariff = unsigned8FromPayload(payload, 2);
if (tariff > 254)
return false;
value = tariff;
return true;
}
}
return false;
}
bool busValueToLocale(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(datatype.mainGroup == 231 ? 4 : 2);
if (!datatype.index || (datatype.mainGroup == 231 && datatype.index == 1))
{
char code[2];
code[0] = unsigned8FromPayload(payload, datatype.index * 2);
code[1] = unsigned8FromPayload(payload, datatype.index * 2 + 1);
value = code;
return true;
}
return false;
}
bool busValueToRGB(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(3);
uint32_t rgb = (unsigned16FromPayload(payload, 0) << 8) | unsigned8FromPayload(payload, 2);
value = rgb;
return true;
}
bool busValueToRGBW(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(6);
switch (datatype.index)
{
case 0: // The RGBW value
{
uint32_t rgbw = unsigned32FromPayload(payload, 0);
value = rgbw;
return true;
}
case 1: // The mask bits only
{
value = unsigned8FromPayload(payload, 5);
return true;
}
}
return false;
}
bool busValueToFlaggedScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(2);
switch (datatype.index)
{
case 0:
value = (uint8_t)(unsigned8FromPayload(payload, 0) * 100.0 / 255.0);
return true;
case 1:
value = bitFromPayload(payload, 15);
return true;
}
return false;
}
bool busValueToActiveEnergy(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(6);
switch (datatype.index)
{
case 0:
value = signed32FromPayload(payload, 0);
return true;
case 1:
value = unsigned8FromPayload(payload, 4);
return true;
case 2:
case 3:
value = bitFromPayload(payload, datatype.index + 44);
return true;
}
return false;
}
//-------------------------------------------------------------------------------------------------------------------------------------
bool valueToBusValueBinary(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
bitToPayload(payload, payload_length, 7, value);
return true;
}
bool valueToBusValueBinaryControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0x03);
return true;
}
bool valueToBusValueStepControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0x0F);
return true;
}
bool valueToBusValueCharacter(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
if ((uint64_t)value > INT64_C(255) || (datatype.subGroup == 1 && (uint64_t)value > INT64_C(127)))
return false;
unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF);
return true;
}
bool valueToBusValueUnsigned8(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
if ((int64_t)value < INT64_C(0))
return false;
switch (datatype.subGroup)
{
case 1:
{
if ((double)value > 100.0)
return false;
unsigned8ToPayload(payload, payload_length, 0, round((double)value * 255.0 / 100.0), 0xFF);
break;
}
case 3:
{
if ((double)value > 360.0)
return false;
unsigned8ToPayload(payload, payload_length, 0, round((double)value * 255.0 / 360.0), 0xFF);
break;
}
case 6:
{
if ((int64_t)value > INT64_C(254))
return false;
unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF);
break;
}
default:
{
if ((int64_t)value > INT64_C(255))
return false;
unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF);
}
}
return true;
}
bool valueToBusValueSigned8(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
if ((int64_t)value < INT64_C(-128) || (int64_t)value > INT64_C(127))
return false;
signed8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF);
return true;
}
bool valueToBusValueStatusAndMode(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
if (datatype.index < 5)
bitToPayload(payload, payload_length, datatype.index, value);
else if (datatype.index == 5)
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(7))
return false;
unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0x07);
}
else
return false;
return true;
}
bool valueToBusValueUnsigned16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(65535))
return false;
unsigned16ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFFFF);
return true;
}
bool valueToBusValueTimePeriod(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
struct tm tmp = value;
time_t timeSinceEpoch = mktime(&tmp);
if (timeSinceEpoch < INT64_C(0) || timeSinceEpoch > INT64_C(65535))
return false;
unsigned16ToPayload(payload, payload_length, 0, timeSinceEpoch, 0xFFFF);
return true;
}
bool valueToBusValueSigned16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
if ((int64_t)value < INT64_C(-32768) || (int64_t)value > INT64_C(32767))
return false;
if (datatype.subGroup == 10)
{
if ((double)value < -327.68 || (double)value > 327.67)
return false;
signed16ToPayload(payload, payload_length, 0, (int16_t)((double)value * 100.0), 0xFFFF);
}
else
signed16ToPayload(payload, payload_length, 0, (uint64_t)value, 0xffff);
return true;
}
bool valueToBusValueTimeDelta(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
struct tm tmp = value;
time_t timeSinceEpoch = mktime(&tmp);
if (timeSinceEpoch < INT64_C(-32768) || timeSinceEpoch > INT64_C(32767))
return false;
signed16ToPayload(payload, payload_length, 0, timeSinceEpoch, 0xFFFF);
return true;
}
bool valueToBusValueFloat16(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
double numValue = value;
// bigger values like 670760.0 result in 0x7FFF which denotes invalid data.
// I'm not sure if the GO shouldn't be updated to this value instead
if (numValue > 670433.28)
return false;
if (numValue < -671088.64)
return false;
switch (datatype.subGroup)
{
case 1:
if (numValue < -273.0)
return false;
break;
case 2:
case 3:
case 10:
case 11:
case 20:
case 21:
case 22:
case 23:
case 24:
case 25:
if (numValue < -670760.0)
return false;
break;
case 4:
case 5:
case 6:
case 7:
case 8:
case 28:
if (numValue < 0.0)
return false;
break;
case 27:
if (numValue < -459.6)
return false;
break;
}
float16ToPayload(payload, payload_length, 0, numValue, 0xFFFF);
return true;
}
bool valueToBusValueTime(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch (datatype.index)
{
case 0:
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(7))
return false;
ENSURE_PAYLOAD(3);
unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value << 5, 0xE0);
break;
}
case 1:
{
struct tm tmp = value;
unsigned8ToPayload(payload, payload_length, 0, tmp.tm_hour, 0x1F);
unsigned8ToPayload(payload, payload_length, 1, tmp.tm_min, 0x3F);
unsigned8ToPayload(payload, payload_length, 2, tmp.tm_sec, 0x3F);
break;
}
default:
return false;
}
return true;
}
bool valueToBusValueDate(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
struct tm tmp = value;
if (tmp.tm_year < 1990 || tmp.tm_year > 2089)
return false;
unsigned8ToPayload(payload, payload_length, 0, tmp.tm_mday, 0x1F);
unsigned8ToPayload(payload, payload_length, 1, tmp.tm_mon, 0x0F);
unsigned8ToPayload(payload, payload_length, 2, tmp.tm_year % 100, 0x7F);
return true;
}
bool valueToBusValueUnsigned32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(4294967295))
return false;
unsigned32ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFFFFFFFF);
return true;
}
bool valueToBusValueSigned32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
if ((int64_t)value < INT64_C(-2147483648) || (int64_t)value > INT64_C(2147483647))
return false;
signed32ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFFFFFFFF);
return true;
}
bool valueToBusValueLongTimePeriod(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
if ((int64_t)value < INT64_C(-2147483648) || (int64_t)value > INT64_C(2147483647))
return false;
signed32ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFFFFFFFF);
return true;
}
bool valueToBusValueFloat32(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
double numValue = value;
if (numValue < (-8388608.0 * pow(2, 255)) || numValue > (8388607.0 * pow(2, 255)))
return false;
float32ToPayload(payload, payload_length, 0, numValue, 0xFFFFFFFF);
return true;
}
bool valueToBusValueAccess(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch (datatype.index)
{
case 0:
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(999999))
return false;
ENSURE_PAYLOAD(4);
for (int n = 0, factor = 100000; n < 6; ++n, factor /= 10)
bcdToPayload(payload, payload_length, n, ((uint64_t)value / factor) % 10);
break;
}
case 1:
case 2:
case 3:
case 4:
bitToPayload(payload, payload_length, 23 + datatype.index, value);
break;
case 5:
{
if ((uint64_t)value > INT64_C(15))
return false;
bcdToPayload(payload, payload_length, 7, (uint64_t)value);
break;
}
default:
return false;
}
return true;
}
bool valueToBusValueString(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
const char* strValue = value;
uint8_t val = strValue[0];
for (int n = 0; n < 14; n++)
{
if (val)
val = strValue[n]; //string terminator 0x00 will stop further assignments and init the remainig payload with zero
unsigned8ToPayload(payload, payload_length, n, val, 0xff);
}
return true;
}
bool valueToBusValueScene(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(63))
return false;
unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF);
return true;
}
bool valueToBusValueSceneControl(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch (datatype.index)
{
case 0:
bitToPayload(payload, payload_length, 0, value);
break;
case 1:
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(63))
return false;
unsigned8ToPayload(payload, payload_length, 0, (int64_t)value, 0x3F);
break;
}
default:
return false;
}
return true;
}
bool valueToBusValueSceneInfo(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch (datatype.index)
{
case 0:
bitToPayload(payload, payload_length, 1, value);
break;
case 1:
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(63))
return false;
unsigned8ToPayload(payload, payload_length, 0, (int64_t)value, 0x3F);
break;
}
default:
return false;
}
return true;
}
bool valueToBusValueSceneConfig(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch (datatype.index)
{
case 0:
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(63))
return false;
unsigned8ToPayload(payload, payload_length, 0, (int64_t)value, 0x3F);
break;
}
case 1:
case 2:
bitToPayload(payload, payload_length, 2 - datatype.index, value);
break;
default:
return false;
}
return true;
}
bool valueToBusValueDateTime(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch (datatype.index)
{
case 0:
{
struct tm local = value;
time_t time = mktime(&local);
if (!time) //TODO add check if date or time is invalid
return false;
ENSURE_PAYLOAD(8);
struct tm tmp = value;
bitToPayload(payload, payload_length, 51, false);
bitToPayload(payload, payload_length, 52, false);
unsigned8ToPayload(payload, payload_length, 0, tmp.tm_year - 1900, 0xFF);
unsigned8ToPayload(payload, payload_length, 1, tmp.tm_mon, 0x0F);
unsigned8ToPayload(payload, payload_length, 2, tmp.tm_mday, 0x1F);
bitToPayload(payload, payload_length, 54, false);
unsigned8ToPayload(payload, payload_length, 3, tmp.tm_hour, 0x1F);
unsigned8ToPayload(payload, payload_length, 4, tmp.tm_min, 0x3F);
unsigned8ToPayload(payload, payload_length, 5, tmp.tm_sec, 0x3F);
break;
}
case 1:
{
ENSURE_PAYLOAD(8);
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(7))
bitToPayload(payload, payload_length, 53, true);
else
{
bitToPayload(payload, payload_length, 53, false);
unsigned8ToPayload(payload, payload_length, 3, (int64_t)value << 5, 0xE0);
}
break;
}
case 2:
{
ENSURE_PAYLOAD(8);
bitToPayload(payload, payload_length, 49, value);
bitToPayload(payload, payload_length, 50, false);
break;
}
case 3:
{
ENSURE_PAYLOAD(8);
bitToPayload(payload, payload_length, 48, value);
break;
}
case 9:
{
ENSURE_PAYLOAD(8);
bitToPayload(payload, payload_length, 55, value);
break;
}
case 10:
{
bitToPayload(payload, payload_length, 56, value);
break;
}
default:
return false;
}
return true;
}
bool valueToBusValueUnicode(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
//TODO
return false;
}
bool valueToBusValueSigned64(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
signed64ToPayload(payload, payload_length, 0, (int64_t)value, UINT64_C(0xFFFFFFFFFFFFFFFF));
return true;
}
bool valueToBusValueAlarmInfo(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch (datatype.index)
{
case 1:
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(3))
return false;
ENSURE_PAYLOAD(6);
unsigned8ToPayload(payload, payload_length, 1, (int64_t)value, 0xFF);
break;
}
case 0:
case 2:
case 3:
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(255))
return false;
ENSURE_PAYLOAD(6);
unsigned8ToPayload(payload, payload_length, datatype.index, (int64_t)value, 0xFF);
break;
}
case 4:
case 5:
case 6:
case 7:
{
ENSURE_PAYLOAD(6);
bitToPayload(payload, payload_length, 43 - datatype.index, value);
break;
}
case 8:
case 9:
case 10:
{
ENSURE_PAYLOAD(6);
bitToPayload(payload, payload_length, 55 - datatype.index, value);
break;
}
default:
return false;
}
return true;
}
bool valueToBusValueSerialNumber(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch (datatype.index)
{
case 0:
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(65535))
return false;
ENSURE_PAYLOAD(6);
unsigned16ToPayload(payload, payload_length, 0, (int64_t)value, 0xFFFF);
break;
}
case 1:
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(4294967295))
return false;
ENSURE_PAYLOAD(6);
unsigned32ToPayload(payload, payload_length, 2, (int64_t)value, 0xFFFF);
break;
}
default:
return false;
}
return true;
}
bool valueToBusValueVersion(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch (datatype.index)
{
case 0:
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(31))
return false;
ENSURE_PAYLOAD(2);
unsigned8ToPayload(payload, payload_length, 0, (int64_t)value << 3, 0xF8);
break;
}
case 1:
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(31))
return false;
unsigned16ToPayload(payload, payload_length, 0, (int64_t)value << 6, 0x07C0);
break;
}
case 2:
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(63))
return false;
unsigned8ToPayload(payload, payload_length, 1, (int64_t)value, 0x3F);
break;
}
default:
return false;
}
return true;
}
bool valueToBusValueScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch (datatype.index)
{
case 0:
{
uint32_t duration = value;
if (duration > INT64_C(65535))
return false;
ENSURE_PAYLOAD(3);
unsigned16ToPayload(payload, payload_length, 0, duration, 0xFFFF);
return true;
}
case 1:
{
if ((double)value < 0.0 || (double)value > 100.0)
return false;
unsigned8ToPayload(payload, payload_length, 2, round((double)value * 255.0 / 100.0), 0xff);
break;
}
}
return true;
}
bool valueToBusValueTariff(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch (datatype.index)
{
case 0:
{
uint32_t duration = value;
if (duration > INT64_C(65535))
return false;
ENSURE_PAYLOAD(3);
unsigned16ToPayload(payload, payload_length, 0, duration, 0xFFFF);
return true;
}
case 1:
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(254))
return false;
unsigned8ToPayload(payload, payload_length, 2, (int64_t)value, 0xff);
break;
}
}
return true;
}
bool valueToBusValueLocale(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
int strl = strlen(value);
if (strl != 2)
return false;
if (!datatype.index || (datatype.mainGroup == 231 && datatype.index == 1))
{
ENSURE_PAYLOAD(datatype.mainGroup == 231 ? 4 : 2);
unsigned8ToPayload(payload, payload_length, datatype.index * 2, ((const char*)value)[0], 0xff);
unsigned8ToPayload(payload, payload_length, datatype.index * 2 + 1, ((const char*)value)[1], 0xff);
return true;
}
return false;
}
bool valueToBusValueRGB(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(0xffffff))
return false;
unsigned int rgb = (int64_t)value;
unsigned16ToPayload(payload, payload_length, 0, rgb >> 8, 0xffff);
unsigned8ToPayload(payload, payload_length, 2, rgb & 0xff, 0xff);
return true;
}
bool valueToBusValueRGBW(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch (datatype.index)
{
case 0: // RGBW
{
uint32_t rgbw = (uint32_t)value;
unsigned32ToPayload(payload, payload_length, 0, rgbw, 0xffffffff); // RGBW
break;
}
case 1: // Mask bits
{
unsigned8ToPayload(payload, payload_length, 5, (uint8_t)value, 0x0f);
break;
}
}
return true;
}
bool valueToBusValueFlaggedScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch (datatype.index)
{
case 0:
{
if ((double)value < 0.0 || (double)value > 100.0)
return false;
ENSURE_PAYLOAD(2);
unsigned8ToPayload(payload, payload_length, 0, round((double)value * 255.0 / 100.0), 0xff);
break;
}
case 1:
bitToPayload(payload, payload_length, 15, value);
break;
default:
return false;
}
return true;
}
bool valueToBusValueActiveEnergy(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch (datatype.index)
{
case 0:
{
if ((int64_t)value < INT64_C(-2147483648) || (int64_t)value > INT64_C(2147483647))
return false;
ENSURE_PAYLOAD(6);
signed32ToPayload(payload, payload_length, 0, (int64_t)value, 0xffffffff);
break;
}
case 1:
{
if ((int64_t)value < INT64_C(0) || (int64_t)value > INT64_C(254))
return false;
ENSURE_PAYLOAD(6);
unsigned8ToPayload(payload, payload_length, 4, (int64_t)value, 0xff);
break;
}
case 2:
case 3:
bitToPayload(payload, payload_length, datatype.index + 44, value);
break;
default:
return false;
}
return true;
}
// Helper functions
bool bitFromPayload(const uint8_t* payload, int index)
{
int bit = payload[index / 8] & (1 << (7 - (index % 8)));
return bit ? true : false;
}
uint8_t unsigned8FromPayload(const uint8_t* payload, int index)
{
return (uint8_t)payload[index];
}
int8_t signed8FromPayload(const uint8_t* payload, int index)
{
return (int8_t)payload[index];
}
uint16_t unsigned16FromPayload(const uint8_t* payload, int index)
{
return ((((uint16_t)payload[index]) << 8) & 0xFF00) | (((uint16_t)payload[index + 1]) & 0x00FF);
}
int16_t signed16FromPayload(const uint8_t* payload, int index)
{
return ((((uint16_t)payload[index]) << 8) & 0xFF00) | (((uint16_t)payload[index + 1]) & 0x00FF);
}
uint32_t unsigned32FromPayload(const uint8_t* payload, int index)
{
return ((((uint32_t)payload[index]) << 24) & 0xFF000000) |
((((uint32_t)payload[index + 1]) << 16) & 0x00FF0000) |
((((uint32_t)payload[index + 2]) << 8) & 0x0000FF00) |
(((uint32_t)payload[index + 3]) & 0x000000FF);
}
int32_t signed32FromPayload(const uint8_t* payload, int index)
{
return (int32_t)unsigned32FromPayload(payload, index);
}
uint64_t unsigned64FromPayload(const uint8_t* payload, int index)
{
return ((((uint64_t)payload[index]) << 56) & 0xFF00000000000000) |
((((uint64_t)payload[index + 1]) << 48) & 0x00FF000000000000) |
((((uint64_t)payload[index + 2]) << 40) & 0x0000FF0000000000) |
((((uint64_t)payload[index + 3]) << 32) & 0x000000FF00000000) |
((((uint64_t)payload[index + 4]) << 24) & 0x00000000FF000000) |
((((uint64_t)payload[index + 5]) << 16) & 0x0000000000FF0000) |
((((uint64_t)payload[index + 6]) << 8) & 0x000000000000FF00) |
(((uint64_t)payload[index + 7]) & 0x00000000000000FF);
}
double float16FromPayload(const uint8_t* payload, int index)
{
uint16_t mantissa = unsigned16FromPayload(payload, index) & 0x87FF;
if (mantissa & 0x8000)
return ((~mantissa & 0x07FF) + 1.0) * -0.01 * (1 << ((payload[index] >> 3) & 0x0F));
return mantissa * 0.01 * (1 << ((payload[index] >> 3) & 0x0F));
}
float float32FromPayload(const uint8_t* payload, int index)
{
union
{
float f;
uint32_t i;
} area;
area.i = unsigned32FromPayload(payload, index);
return area.f;
}
double float64FromPayload(const uint8_t* payload, int index)
{
union
{
double f;
uint64_t i;
} area;
area.i = unsigned64FromPayload(payload, index);
return area.f;
}
int64_t signed64FromPayload(const uint8_t* payload, int index)
{
return ((((uint64_t)payload[index]) << 56) & UINT64_C(0xFF00000000000000)) |
((((uint64_t)payload[index + 1]) << 48) & UINT64_C(0x00FF000000000000)) |
((((uint64_t)payload[index + 2]) << 40) & UINT64_C(0x0000FF0000000000)) |
((((uint64_t)payload[index + 3]) << 32) & UINT64_C(0x000000FF00000000)) |
((((uint64_t)payload[index + 4]) << 24) & UINT64_C(0x00000000FF000000)) |
((((uint64_t)payload[index + 5]) << 16) & UINT64_C(0x0000000000FF0000)) |
((((uint64_t)payload[index + 6]) << 8) & UINT64_C(0x000000000000FF00)) |
(((uint64_t)payload[index + 7]) & UINT64_C(0x00000000000000FF));
}
uint8_t bcdFromPayload(const uint8_t* payload, int index)
{
if (index % 2)
return (uint8_t)(payload[index / 2] & 0x0F);
return (uint8_t)((payload[index / 2] >> 4) & 0x0F);
}
void bitToPayload(uint8_t* payload, size_t payload_length, int index, bool value)
{
ENSURE_PAYLOAD(index / 8 + 1);
payload[index / 8] = (payload[index / 8] & ~(1 << (7 - (index % 8)))) | (value ? (1 << (7 - (index % 8))) : 0);
}
void unsigned8ToPayload(uint8_t* payload, size_t payload_length, int index, uint8_t value, uint8_t mask)
{
ENSURE_PAYLOAD(index + 1);
payload[index] = (payload[index] & ~mask) | (value & mask);
}
void signed8ToPayload(uint8_t* payload, size_t payload_length, int index, int8_t value, uint8_t mask)
{
ENSURE_PAYLOAD(index + 1);
payload[index] = (payload[index] & ~mask) | (value & mask);
}
void unsigned16ToPayload(uint8_t* payload, size_t payload_length, int index, uint16_t value, uint16_t mask)
{
ENSURE_PAYLOAD(index + 2);
payload[index] = (payload[index] & (~mask >> 8)) | ((value >> 8) & (mask >> 8));
payload[index + 1] = (payload[index + 1] & ~mask) | (value & mask);
}
void signed16ToPayload(uint8_t* payload, size_t payload_length, int index, int16_t value, uint16_t mask)
{
ENSURE_PAYLOAD(index + 2);
payload[index] = (payload[index] & (~mask >> 8)) | ((value >> 8) & (mask >> 8));
payload[index + 1] = (payload[index + 1] & ~mask) | (value & mask);
}
void unsigned32ToPayload(uint8_t* payload, size_t payload_length, int index, uint32_t value, uint32_t mask)
{
ENSURE_PAYLOAD(index + 4);
payload[index] = (payload[index] & (~mask >> 24)) | ((value >> 24) & (mask >> 24));
payload[index + 1] = (payload[index + 1] & (~mask >> 16)) | ((value >> 16) & (mask >> 16));
payload[index + 2] = (payload[index + 2] & (~mask >> 8)) | ((value >> 8) & (mask >> 8));
payload[index + 3] = (payload[index + 3] & ~mask) | (value & mask);
}
void signed32ToPayload(uint8_t* payload, size_t payload_length, int index, int32_t value, uint32_t mask)
{
ENSURE_PAYLOAD(index + 4);
payload[index] = (payload[index] & (~mask >> 24)) | ((value >> 24) & (mask >> 24));
payload[index + 1] = (payload[index + 1] & (~mask >> 16)) | ((value >> 16) & (mask >> 16));
payload[index + 2] = (payload[index + 2] & (~mask >> 8)) | ((value >> 8) & (mask >> 8));
payload[index + 3] = (payload[index + 3] & ~mask) | (value & mask);
}
void float16ToPayload(uint8_t* payload, size_t payload_length, int index, double value, uint16_t mask)
{
bool wasNegative = false;
if (value < 0)
{
wasNegative = true;
value *= -1;
}
value *= 100.0;
unsigned short exponent = 0;
if (value > 2048)
exponent = ceil(log2(value) - 11.0);
short mantissa = roundf(value / (1 << exponent));
// above calculation causes mantissa overflow for values of the form 2^n, where n>11
if (mantissa >= 0x800)
{
exponent++;
mantissa = roundf(value / (1 << exponent));
}
if (wasNegative)
mantissa *= -1;
// println(mantissa);
signed16ToPayload(payload, payload_length, index, mantissa, mask);
unsigned8ToPayload(payload, payload_length, index, exponent << 3, 0x78 & (mask >> 8));
}
void float32ToPayload(uint8_t* payload, size_t payload_length, int index, double value, uint32_t mask)
{
union
{
float f;
uint32_t i;
} num;
num.f = value;
unsigned32ToPayload(payload, payload_length, index, num.i, mask);
}
void signed64ToPayload(uint8_t* payload, size_t payload_length, int index, int64_t value, uint64_t mask)
{
ENSURE_PAYLOAD(index + 8);
payload[index] = (payload[index] & (~mask >> 56)) | ((value >> 56) & (mask >> 56));
payload[index + 1] = (payload[index + 1] & (~mask >> 48)) | ((value >> 48) & (mask >> 48));
payload[index + 2] = (payload[index + 2] & (~mask >> 40)) | ((value >> 40) & (mask >> 40));
payload[index + 3] = (payload[index + 3] & (~mask >> 32)) | ((value >> 32) & (mask >> 32));
payload[index + 4] = (payload[index + 4] & (~mask >> 24)) | ((value >> 24) & (mask >> 24));
payload[index + 5] = (payload[index + 5] & (~mask >> 16)) | ((value >> 16) & (mask >> 16));
payload[index + 6] = (payload[index + 6] & (~mask >> 8)) | ((value >> 8) & (mask >> 8));
payload[index + 7] = (payload[index + 7] & ~mask) | (value & mask);
}
void bcdToPayload(uint8_t* payload, size_t payload_length, int index, uint8_t value)
{
ENSURE_PAYLOAD(index / 2 + 1);
if (index % 2)
payload[index / 2] = (payload[index / 2] & 0xF0) | (value & 0x0F);
else
payload[index / 2] = (payload[index / 2] & 0x0F) | ((value << 4) & 0xF0);
}