diff --git a/src/ebusd/knxhandler.cpp b/src/ebusd/knxhandler.cpp index db100bd6..8d257408 100644 --- a/src/ebusd/knxhandler.cpp +++ b/src/ebusd/knxhandler.cpp @@ -317,42 +317,6 @@ result_t getFieldLength(const SingleDataField *field, dtlf_t *length) { return RESULT_OK; } -uint32_t floatToInt16(float val) { - // (0.01*m)(2^e) format with sign, 12 bits mantissa (incl. sign), 4 bits exponent - if (val == 0) { - return 0; - } - bool negative = val < 0; - if (negative) { - val = -val; - } - val = roundf(val*100.0f); - int exp = ilogb(val)-10; - if (exp < -10 || exp > 15) { - return 0x7fff; // invalid value DPT 9 - } - auto shift = exp > 0 ? exp : 0; - auto sig = static_cast(val * exp2(-shift)); - uint32_t value = static_cast(shift << 11) | (negative ? 0x800-sig : sig); - if (negative) { - return value | 0x8000; - } - return value; -} - -float int16ToFloat(uint16_t val) { - if (val == 0) { - return 0; - } - if (val == 0x7fff) { - return static_cast(0xffffffff); // NaN - } - bool negative = val&0x8000; - int exp = (val>>11)&0xf; - int sig = val&0x7ff; - return static_cast((negative ? sig-0x800 : sig) * exp2(exp) * 0.01); -} - result_t KnxHandler::sendGroupValue(knx_addr_t dest, apci_t apci, dtlf_t& lengthFlag, unsigned int value, const SingleDataField *field) const { if (!m_con || !m_con->isConnected() || !m_con->getAddress()) { @@ -382,7 +346,7 @@ const SingleDataField *field) const { return ret; } else if (lengthFlag.length == 2) { // convert to (0.01*m)(2^e) format with sign, 12 bits mantissa (incl. sign), 4 bits exponent - value = floatToInt16(fval); + value = floatToUint16(fval); } else if (lengthFlag.length == 4) { // convert to IEEE 754 value = floatToUint(fval); @@ -686,8 +650,8 @@ void KnxHandler::handleGroupTelegram(knx_addr_t src, knx_addr_t dest, int len, c if (lengthFlag.isFloat || lengthFlag.hasDivisor) { float fval; if (lengthFlag.length == 2) { - // convert from (0.01*m)(2^e) format with sign, 12 bits mantissa (incl. sign), 4 bits exponent - fval = int16ToFloat(static_cast(value)); + // convert from (0.01*m)(2^e) format + fval = uint16ToFloat(static_cast(value)); } else if (lengthFlag.length == 4) { // convert from IEEE 754 bool negative = (value & (1u << 31)) != 0; diff --git a/src/lib/ebus/datatype.cpp b/src/lib/ebus/datatype.cpp index 6320f944..160b01a9 100755 --- a/src/lib/ebus/datatype.cpp +++ b/src/lib/ebus/datatype.cpp @@ -95,6 +95,34 @@ uint32_t floatToUint(float val) { #endif } +float uint16ToFloat(uint16_t val) { + if (val == 0) { + return 0; + } + if (val == 0x7fff) { + return static_cast(0xffffffff); // NaN + } + bool negative = val&0x8000; + int exp = (val>>11)&0xf; + int sig = val&0x7ff; + return static_cast((negative ? sig-0x800 : sig) * exp2(exp) * 0.01); +} + +uint16_t floatToUint16(float value) { + // (0.01*m)(2^e) format with sign, 12 bits mantissa (incl. sign), 4 bits exponent + if (value == 0) { + return 0; + } + bool negative = value < 0; + double val = round(value*(negative ? -100.0 : 100.0)); + int exp = ilogb(val)-10; + if (exp < -10 || exp > 15) { + return 0x7fff; // invalid value DPT 9 + } + auto shift = exp > 0 ? exp : 0; + auto sig = static_cast(val * exp2(-shift)); + return static_cast((shift << 11) | (negative ? 0x8000 | (0x800-sig) : sig)); +} bool DataType::dump(OutputFormat outputFormat, size_t length, bool appendDivisor, ostream* output) const { if (outputFormat & OF_JSON) { diff --git a/src/lib/ebus/datatype.h b/src/lib/ebus/datatype.h index 9dee87cd..e3bf9cba 100755 --- a/src/lib/ebus/datatype.h +++ b/src/lib/ebus/datatype.h @@ -194,10 +194,26 @@ float uintToFloat(unsigned int value, bool negative); /** * Format a float value to the 32 bit representation (IEEE 754). - * @param val the float value. + * @param value the float value. * @return the 32 bit representation of the float value, or 0xffffffff if NaN. */ -uint32_t floatToUint(float val); +uint32_t floatToUint(float value); + +/** + * Parse a float value with precision of 2 decimal from 16 bit format with + * sign, 11 bit mantissa, 4 bit exponent as (0.01*m)(2^e). + * @param value the 16 bit representation of the float value. + * @return the float value. + */ +float uint16ToFloat(uint16_t value); + +/** + * Format a float value with precision of 2 decimal from 16 bit format with + * sign, 11 bit mantissa, 4 bit exponent as (0.01*m)(2^e). + * @param value the float value. + * @return the 16 bit representation of the float value, or 0xffff if NaN. + */ +uint16_t floatToUint16(float value); /** * Base class for all kinds of data types.