better rounding and avoid to loose precision, move 16 bit float to datatype

This commit is contained in:
John
2023-12-24 09:53:40 +01:00
parent 2b5bd1b67e
commit f587fea698
3 changed files with 49 additions and 41 deletions
+3 -39
View File
@@ -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<uint32_t>(val * exp2(-shift));
uint32_t value = static_cast<uint32_t>(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<float>(0xffffffff); // NaN
}
bool negative = val&0x8000;
int exp = (val>>11)&0xf;
int sig = val&0x7ff;
return static_cast<float>((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<uint16_t>(value));
// convert from (0.01*m)(2^e) format
fval = uint16ToFloat(static_cast<uint16_t>(value));
} else if (lengthFlag.length == 4) {
// convert from IEEE 754
bool negative = (value & (1u << 31)) != 0;
+28
View File
@@ -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<float>(0xffffffff); // NaN
}
bool negative = val&0x8000;
int exp = (val>>11)&0xf;
int sig = val&0x7ff;
return static_cast<float>((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<uint16_t>(val * exp2(-shift));
return static_cast<uint16_t>((shift << 11) | (negative ? 0x8000 | (0x800-sig) : sig));
}
bool DataType::dump(OutputFormat outputFormat, size_t length, bool appendDivisor, ostream* output) const {
if (outputFormat & OF_JSON) {
+18 -2
View File
@@ -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.