From 31d1add07e1a7ad721a03b9be9d763b493c331c2 Mon Sep 17 00:00:00 2001 From: Tom Kooij Date: Fri, 30 Dec 2022 16:56:18 +0100 Subject: [PATCH 1/4] Raw bytes can be signed or unsigned. Cast "signed raw bytes" to signed integer first, before casting to float and applying a divider. Example: datatype = 0x92 (1-0-010-010) datatype & 0x80 (bit 8) => signed value datatype & 0x38 (bits 654) => length => 2 bytes datatype & 0x07 (bits 321) => divider => 2 datatype 0x92 value 0xFC18 datatype signed, length 2, divider 2. signed int value -1000: value -10.00 --- software/NRG_itho_wifi/src/IthoSystem.cpp | 44 ++++++++++++++++------- software/NRG_itho_wifi/src/IthoSystem.h | 2 ++ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/software/NRG_itho_wifi/src/IthoSystem.cpp b/software/NRG_itho_wifi/src/IthoSystem.cpp index 5611fd4b..1501135f 100644 --- a/software/NRG_itho_wifi/src/IthoSystem.cpp +++ b/software/NRG_itho_wifi/src/IthoSystem.cpp @@ -711,6 +711,14 @@ void sendQueryStatusFormat(bool updateweb) } else { + if ((i2cbuf[6 + i] & 0x80) == 0) + { // unsigned value + ithoStatus.back().is_signed = false; + } + else + { + ithoStatus.back().is_signed = true; + } ithoStatus.back().type = ithoDeviceStatus::is_float; ithoStatus.back().divider = quick_pow10((i2cbuf[6 + i] & 0x07)); } @@ -732,6 +740,7 @@ void sendQueryStatusFormat(bool updateweb) if (i2cbuf[6 + i] == 0x0F) { ithoStatus.back().type = ithoDeviceStatus::is_float; + ithoStatus.back().is_signed = false; ithoStatus.back().length = 1; ithoStatus.back().divider = 2; } @@ -818,18 +827,9 @@ void sendQueryStatus(bool updateweb) } if (ithoStat.type == ithoDeviceStatus::is_int) { - if (ithoStat.length == 4) - { - tempVal = static_cast(tempVal); - } - if (ithoStat.length == 2) - { - tempVal = static_cast(tempVal); - } - if (ithoStat.length == 1) - { - tempVal = static_cast(tempVal); - } + + tempVal = cast_to_signed_int(tempVal, ithoStat.length); + if (ithoStat.value.intval == tempVal) { ithoStat.updated = 0; @@ -842,6 +842,7 @@ void sendQueryStatus(bool updateweb) } if (ithoStat.type == ithoDeviceStatus::is_float) { + double t = ithoStat.value.floatval * ithoStat.divider; if (static_cast(t) == tempVal) // better compare needed of float val, worst case this will result in an extra update of the value, so limited impact { @@ -850,6 +851,11 @@ void sendQueryStatus(bool updateweb) else { ithoStat.updated = 1; + if (ithoStat.is_signed) + { + // interpret raw bytes as signed integer + tempVal = cast_to_signed_int(tempVal, ithoStat.length); + } ithoStat.value.floatval = static_cast(tempVal) / ithoStat.divider; } } @@ -1789,3 +1795,17 @@ std::string i2cbuf2string(const uint8_t *data, size_t len) } return s; } + +int cast_to_signed_int(int val, int length) +{ + switch (length) { + case 4: + return static_cast(val); + case 2: + return static_cast(val); + case 1: + return static_cast(val); + default: + return 0; + } +} \ No newline at end of file diff --git a/software/NRG_itho_wifi/src/IthoSystem.h b/software/NRG_itho_wifi/src/IthoSystem.h index d8516c59..577fbe99 100644 --- a/software/NRG_itho_wifi/src/IthoSystem.h +++ b/software/NRG_itho_wifi/src/IthoSystem.h @@ -59,6 +59,7 @@ struct ithoDeviceStatus } value; uint32_t divider; uint8_t updated; + bool is_signed; // used for floats only ithoDeviceStatus() : updated(0){}; }; @@ -146,3 +147,4 @@ void filterReset(); void IthoPWMcommand(uint16_t value, volatile uint16_t *ithoCurrentVal, bool *updateIthoMQTT); int quick_pow10(int n); std::string i2cbuf2string(const uint8_t *data, size_t len); +int cast_to_signed_int(int val, int length); From f7b914aea1097da90901b0cfe1c68fb47af80a3c Mon Sep 17 00:00:00 2001 From: Tom Kooij Date: Sun, 1 Jan 2023 10:38:15 +0100 Subject: [PATCH 2/4] Refactor itho datatype handling Itho datatype (single byte) 7-654-3210 bit 7: signed (1), unsigned (0) 654: length of raw data 3210: (4 LSBs): divider Exception 0x5B: two byte unsigned int. --- software/NRG_itho_wifi/src/IthoSystem.cpp | 103 ++++++++---------- software/NRG_itho_wifi/src/IthoSystem.h | 6 +- .../NRG_itho_wifi/src/generic_functions.cpp | 4 - 3 files changed, 50 insertions(+), 63 deletions(-) diff --git a/software/NRG_itho_wifi/src/IthoSystem.cpp b/software/NRG_itho_wifi/src/IthoSystem.cpp index 1501135f..4ef4a8c4 100644 --- a/software/NRG_itho_wifi/src/IthoSystem.cpp +++ b/software/NRG_itho_wifi/src/IthoSystem.cpp @@ -697,57 +697,25 @@ void sendQueryStatusFormat(bool updateweb) // char fStringBuf[32]; // getSatusLabel(i, ithoDeviceptr, currentItho_fwversion(), fStringBuf); - ithoStatus.back().divider = 0; - if ((i2cbuf[6 + i] & 0x07) == 0) + ithoStatus.back().is_signed = get_signed_from_datatype(i2cbuf[6 + i]); + ithoStatus.back().length = get_length_from_datatype(i2cbuf[6 + i]); + ithoStatus.back().divider = get_divider_from_datatype(i2cbuf[6 + i]); + + if (ithoStatus.back().divider == 1.) { // integer value - if ((i2cbuf[6 + i] & 0x80) == 0) - { // unsigned value - ithoStatus.back().type = ithoDeviceStatus::is_uint; - } - else - { ithoStatus.back().type = ithoDeviceStatus::is_int; - } } else { - if ((i2cbuf[6 + i] & 0x80) == 0) - { // unsigned value - ithoStatus.back().is_signed = false; - } - else - { - ithoStatus.back().is_signed = true; - } ithoStatus.back().type = ithoDeviceStatus::is_float; - ithoStatus.back().divider = quick_pow10((i2cbuf[6 + i] & 0x07)); - } - if (((i2cbuf[6 + i] >> 3) & 0x07) == 0) - { - ithoStatus.back().length = 1; } - else - { - ithoStatus.back().length = (i2cbuf[6 + i] >> 3) & 0x07; - } - // special cases - if (i2cbuf[6 + i] == 0x0C || i2cbuf[6 + i] == 0x6C) - { - ithoStatus.back().type = ithoDeviceStatus::is_byte; - ithoStatus.back().length = 1; - } - if (i2cbuf[6 + i] == 0x0F) - { - ithoStatus.back().type = ithoDeviceStatus::is_float; - ithoStatus.back().is_signed = false; - ithoStatus.back().length = 1; - ithoStatus.back().divider = 2; - } if (i2cbuf[6 + i] == 0x5B) { - ithoStatus.back().type = ithoDeviceStatus::is_uint; + // legacy itho: 0x5B -> 0x10 + ithoStatus.back().type = ithoDeviceStatus::is_int; ithoStatus.back().length = 2; + ithoStatus.back().is_signed = false; } } } @@ -813,23 +781,13 @@ void sendQueryStatus(bool updateweb) ithoStat.value.byteval = (byte)tempVal; } } - if (ithoStat.type == ithoDeviceStatus::is_uint) + if (ithoStat.type == ithoDeviceStatus::is_int) { - if (ithoStat.value.uintval == tempVal) - { - ithoStat.updated = 0; - } - else + if (ithoStat.is_signed) { - ithoStat.updated = 1; - ithoStat.value.uintval = tempVal; + // interpret raw bytes as signed integer + tempVal = cast_to_signed_int(tempVal, ithoStat.length); } - } - if (ithoStat.type == ithoDeviceStatus::is_int) - { - - tempVal = cast_to_signed_int(tempVal, ithoStat.length); - if (ithoStat.value.intval == tempVal) { ithoStat.updated = 0; @@ -841,8 +799,7 @@ void sendQueryStatus(bool updateweb) } } if (ithoStat.type == ithoDeviceStatus::is_float) - { - + { double t = ithoStat.value.floatval * ithoStat.divider; if (static_cast(t) == tempVal) // better compare needed of float val, worst case this will result in an extra update of the value, so limited impact { @@ -1808,4 +1765,36 @@ int cast_to_signed_int(int val, int length) default: return 0; } -} \ No newline at end of file +} + +// Itho datatype +// bit 7: signed (1), unsigned (0) +// bit 6,5,4 : length +// bit 3,2,1,0 : divider +float get_divider_from_datatype(int8_t datatype) { + + const float _divider[] = + { + 1., 10., 100., 1000., 1E+4, 1E+5, + 1E+6, 1E+7, 1E+8, 0.1, 0.01, + 1., 1., 1., 256., 2. + }; + return _divider[datatype & 0x0f]; +} + +uint8_t get_length_from_datatype(int8_t datatype) { + + switch(datatype & 0x70) { + case 0x10: + return 2; + case 0x20: + case 0x70: + return 4; + default: + return 1; + } +} + +bool get_signed_from_datatype(int8_t datatype) { + return datatype & 0x80; +} diff --git a/software/NRG_itho_wifi/src/IthoSystem.h b/software/NRG_itho_wifi/src/IthoSystem.h index 577fbe99..f85864ec 100644 --- a/software/NRG_itho_wifi/src/IthoSystem.h +++ b/software/NRG_itho_wifi/src/IthoSystem.h @@ -44,7 +44,6 @@ struct ithoDeviceStatus { is_byte, is_int, - is_uint, is_float, is_string } type; @@ -57,7 +56,7 @@ struct ithoDeviceStatus double floatval; const char *stringval; } value; - uint32_t divider; + float divider; uint8_t updated; bool is_signed; // used for floats only ithoDeviceStatus() : updated(0){}; @@ -148,3 +147,6 @@ void IthoPWMcommand(uint16_t value, volatile uint16_t *ithoCurrentVal, bool *upd int quick_pow10(int n); std::string i2cbuf2string(const uint8_t *data, size_t len); int cast_to_signed_int(int val, int length); +float get_divider_from_datatype(int8_t datatype); +uint8_t get_length_from_datatype(int8_t datatype); +bool get_signed_from_datatype(int8_t datatype); diff --git a/software/NRG_itho_wifi/src/generic_functions.cpp b/software/NRG_itho_wifi/src/generic_functions.cpp index f80eb660..f71a1a25 100644 --- a/software/NRG_itho_wifi/src/generic_functions.cpp +++ b/software/NRG_itho_wifi/src/generic_functions.cpp @@ -79,10 +79,6 @@ void getIthoStatusJSON(JsonObject root) { root[ithoStat.name] = ithoStat.value.byteval; } - else if (ithoStat.type == ithoDeviceStatus::is_uint) - { - root[ithoStat.name] = ithoStat.value.uintval; - } else if (ithoStat.type == ithoDeviceStatus::is_int) { root[ithoStat.name] = ithoStat.value.intval; From 1a540a3684337d87850c0b14d97c552c87892ba6 Mon Sep 17 00:00:00 2001 From: Tom Kooij Date: Thu, 5 Jan 2023 10:46:06 +0100 Subject: [PATCH 3/4] Let divider be int32_t Dividers index 9 and 10 should 0.1 and 0.01 These seem to be never used. We set them to 1 so the divider can be integer. --- software/NRG_itho_wifi/src/IthoSystem.cpp | 13 +++++++------ software/NRG_itho_wifi/src/IthoSystem.h | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/software/NRG_itho_wifi/src/IthoSystem.cpp b/software/NRG_itho_wifi/src/IthoSystem.cpp index 4ef4a8c4..7e9613f3 100644 --- a/software/NRG_itho_wifi/src/IthoSystem.cpp +++ b/software/NRG_itho_wifi/src/IthoSystem.cpp @@ -701,7 +701,7 @@ void sendQueryStatusFormat(bool updateweb) ithoStatus.back().length = get_length_from_datatype(i2cbuf[6 + i]); ithoStatus.back().divider = get_divider_from_datatype(i2cbuf[6 + i]); - if (ithoStatus.back().divider == 1.) + if (ithoStatus.back().divider == 1) { // integer value ithoStatus.back().type = ithoDeviceStatus::is_int; } @@ -1771,13 +1771,14 @@ int cast_to_signed_int(int val, int length) // bit 7: signed (1), unsigned (0) // bit 6,5,4 : length // bit 3,2,1,0 : divider -float get_divider_from_datatype(int8_t datatype) { +uint32_t get_divider_from_datatype(int8_t datatype) { - const float _divider[] = + const uint32_t _divider[] = { - 1., 10., 100., 1000., 1E+4, 1E+5, - 1E+6, 1E+7, 1E+8, 0.1, 0.01, - 1., 1., 1., 256., 2. + 1, 10, 100, 1000, 10000, 100000, + 1000000, 10000000, 100000000, + 1, 1, // dividers index 9 and 10 should be 0.1 and 0.01 + 1, 1, 1, 256, 2 }; return _divider[datatype & 0x0f]; } diff --git a/software/NRG_itho_wifi/src/IthoSystem.h b/software/NRG_itho_wifi/src/IthoSystem.h index f85864ec..903eadf5 100644 --- a/software/NRG_itho_wifi/src/IthoSystem.h +++ b/software/NRG_itho_wifi/src/IthoSystem.h @@ -147,6 +147,6 @@ void IthoPWMcommand(uint16_t value, volatile uint16_t *ithoCurrentVal, bool *upd int quick_pow10(int n); std::string i2cbuf2string(const uint8_t *data, size_t len); int cast_to_signed_int(int val, int length); -float get_divider_from_datatype(int8_t datatype); +uint32_t get_divider_from_datatype(int8_t datatype); uint8_t get_length_from_datatype(int8_t datatype); bool get_signed_from_datatype(int8_t datatype); From d9c3a59f328da113ad32256c84c35fd90717e765 Mon Sep 17 00:00:00 2001 From: Tom Kooij Date: Thu, 5 Jan 2023 11:12:17 +0100 Subject: [PATCH 4/4] Divider is uint32_t --- software/NRG_itho_wifi/src/IthoSystem.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/software/NRG_itho_wifi/src/IthoSystem.h b/software/NRG_itho_wifi/src/IthoSystem.h index 903eadf5..46926ecb 100644 --- a/software/NRG_itho_wifi/src/IthoSystem.h +++ b/software/NRG_itho_wifi/src/IthoSystem.h @@ -56,9 +56,9 @@ struct ithoDeviceStatus double floatval; const char *stringval; } value; - float divider; + uint32_t divider; uint8_t updated; - bool is_signed; // used for floats only + bool is_signed; ithoDeviceStatus() : updated(0){}; };