From e1269bcb312aad517100ab3db08818588da65284 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 21 Jun 2020 16:02:37 +0200 Subject: [PATCH] refactor read_value. added read_bitvalue --- src/devices/boiler.cpp | 73 ++++++++++++------------ src/devices/solar.cpp | 22 ++++---- src/devices/thermostat.cpp | 43 +++++++------- src/helpers.cpp | 19 ++++--- src/telegram.cpp | 111 +------------------------------------ src/telegram.h | 53 ++++++++++++------ src/test/test.cpp | 7 +-- src/version.h | 2 +- 8 files changed, 124 insertions(+), 206 deletions(-) diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp index 56e999aaa..a9c6b44bf 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -471,12 +471,12 @@ void Boiler::process_UBAMonitorFast(std::shared_ptr telegram) { telegram->read_value(selBurnPow_, 3); // burn power max setting telegram->read_value(curBurnPow_, 4); - telegram->read_value(burnGas_, 7, 0); - telegram->read_value(fanWork_, 7, 2); - telegram->read_value(ignWork_, 7, 3); - telegram->read_value(heatPmp_, 7, 5); - telegram->read_value(wWHeat_, 7, 6); - telegram->read_value(wWCirc_, 7, 7); + telegram->read_bitvalue(burnGas_, 7, 0); + telegram->read_bitvalue(fanWork_, 7, 2); + telegram->read_bitvalue(ignWork_, 7, 3); + telegram->read_bitvalue(heatPmp_, 7, 5); + telegram->read_bitvalue(wWHeat_, 7, 6); + telegram->read_bitvalue(wWCirc_, 7, 7); // warm water storage sensors (if present) // wwStorageTemp2 is also used by some brands as the boiler temperature - see https://github.com/proddy/EMS-ESP/issues/206 @@ -506,7 +506,7 @@ void Boiler::process_UBAMonitorFast(std::shared_ptr telegram) { * received only after requested (not broadcasted) */ void Boiler::process_UBATotalUptime(std::shared_ptr telegram) { - telegram->read_value(UBAuptime_, 0); + telegram->read_value(UBAuptime_, 0, 3); // force to 3 bytes } /* @@ -527,13 +527,15 @@ void Boiler::process_UBAMonitorWW(std::shared_ptr telegram) { telegram->read_value(wWCurTmp_, 1); telegram->read_value(wWCurTmp2_, 3); telegram->read_value(wWCurFlow_, 9); - telegram->read_value(wWWorkM_, 10); - telegram->read_value(wWStarts_, 13); - telegram->read_value(wWOneTime_, 5, 1); - telegram->read_value(wWDesinfecting_, 5, 2); - telegram->read_value(wWReadiness_, 5, 3); - telegram->read_value(wWRecharging_, 5, 4); - telegram->read_value(wWTemperatureOK_, 5, 5); + + telegram->read_value(wWWorkM_, 10, 3); // force to 3 bytes + telegram->read_value(wWStarts_, 13, 3); // force to 3 bytes + + telegram->read_bitvalue(wWOneTime_, 5, 1); + telegram->read_bitvalue(wWDesinfecting_, 5, 2); + telegram->read_bitvalue(wWReadiness_, 5, 3); + telegram->read_bitvalue(wWRecharging_, 5, 4); + telegram->read_bitvalue(wWTemperatureOK_, 5, 5); } /* @@ -542,8 +544,8 @@ void Boiler::process_UBAMonitorWW(std::shared_ptr telegram) { */ void Boiler::process_UBAMonitorFastPlus(std::shared_ptr telegram) { telegram->read_value(selFlowTemp_, 6); - telegram->read_value(burnGas_, 11, 0); - telegram->read_value(wWHeat_, 11, 2); + telegram->read_bitvalue(burnGas_, 11, 0); + telegram->read_bitvalue(wWHeat_, 11, 2); telegram->read_value(curBurnPow_, 10); telegram->read_value(selBurnPow_, 9); telegram->read_value(curFlowTemp_, 7); @@ -573,9 +575,9 @@ void Boiler::process_UBAMonitorSlow(std::shared_ptr telegram) { telegram->read_value(exhaustTemp_, 4); telegram->read_value(switchTemp_, 25); // only if there is a mixing module present telegram->read_value(pumpMod_, 9); - telegram->read_value(burnStarts_, 10); - telegram->read_value(burnWorkMin_, 13); - telegram->read_value(heatWorkMin_, 19); + telegram->read_value(burnStarts_, 10, 3); // force to 3 bytes + telegram->read_value(burnWorkMin_, 13, 3); // force to 3 bytes + telegram->read_value(heatWorkMin_, 19, 3); // force to 3 bytes } /* @@ -589,13 +591,13 @@ void Boiler::process_UBAMonitorSlowPlus2(std::shared_ptr telegra * UBAMonitorSlowPlus - type 0xE5 - central heating monitor EMS+ */ void Boiler::process_UBAMonitorSlowPlus(std::shared_ptr telegram) { - telegram->read_value(fanWork_, 2, 2); - telegram->read_value(ignWork_, 2, 3); - telegram->read_value(heatPmp_, 2, 5); - telegram->read_value(wWCirc_, 2, 7); - telegram->read_value(burnStarts_, 10); - telegram->read_value(burnWorkMin_, 13); - telegram->read_value(heatWorkMin_, 19); + telegram->read_bitvalue(fanWork_, 2, 2); + telegram->read_bitvalue(ignWork_, 2, 3); + telegram->read_bitvalue(heatPmp_, 2, 5); + telegram->read_bitvalue(wWCirc_, 2, 7); + telegram->read_value(burnStarts_, 10, 3); // force to 3 bytes + telegram->read_value(burnWorkMin_, 13, 3); // force to 3 bytes + telegram->read_value(heatWorkMin_, 19, 3); // force to 3 bytes telegram->read_value(pumpMod_, 25); } @@ -605,15 +607,18 @@ void Boiler::process_UBADHWStatus(std::shared_ptr telegram) { telegram->read_value(wWSetTmp_, 0); telegram->read_value(wWCurTmp_, 1); telegram->read_value(wWCurTmp2_, 3); - telegram->read_value(wWWorkM_, 17); - telegram->read_value(wWStarts_, 14); - telegram->read_value(wWOneTime_, 12, 2); - telegram->read_value(wWDesinfecting_, 12, 3); - telegram->read_value(wWReadiness_, 12, 4); - telegram->read_value(wWRecharging_, 13, 4); - telegram->read_value(wWTemperatureOK_, 13, 5); + + telegram->read_value(wWWorkM_, 17, 3); // force to 3 bytes + telegram->read_value(wWStarts_, 14, 3); // force to 3 bytes + + telegram->read_bitvalue(wWOneTime_, 12, 2); + telegram->read_bitvalue(wWDesinfecting_, 12, 3); + telegram->read_bitvalue(wWReadiness_, 12, 4); + telegram->read_bitvalue(wWRecharging_, 13, 4); + telegram->read_bitvalue(wWTemperatureOK_, 13, 5); + telegram->read_bitvalue(wWCircPump_, 13, 2); + telegram->read_value(wWActivated_, 20); - telegram->read_value(wWCircPump_, 13, 2); telegram->read_value(wWSelTemp_, 10); telegram->read_value(wWDisinfectTemp_, 9); } diff --git a/src/devices/solar.cpp b/src/devices/solar.cpp index ba4f0bbff..3f314cc97 100644 --- a/src/devices/solar.cpp +++ b/src/devices/solar.cpp @@ -136,7 +136,7 @@ void Solar::process_SM10Monitor(std::shared_ptr telegram) { telegram->read_value(collectorTemp_, 2); // collector temp from SM10, is *10 telegram->read_value(bottomTemp_, 5); // bottom temp from SM10, is *10 telegram->read_value(pumpModulation_, 4); // modulation solar pump - telegram->read_value(pump_, 7, 1); + telegram->read_bitvalue(pump_, 7, 1); telegram->read_value(pumpWorkMin_, 8); } @@ -191,8 +191,8 @@ void Solar::process_SM100Status(std::shared_ptr telegram) { * byte 10 = PS1 Solar circuit pump for collector array 1: test=01, on=04 and off=03 */ void Solar::process_SM100Status2(std::shared_ptr telegram) { - telegram->read_value(valveStatus_, 4, 2); // on if bit 2 set - telegram->read_value(pump_, 10, 2); // on if bit 2 set + telegram->read_bitvalue(valveStatus_, 4, 2); // on if bit 2 set + telegram->read_bitvalue(pump_, 10, 2); // on if bit 2 set } /* @@ -200,9 +200,9 @@ void Solar::process_SM100Status2(std::shared_ptr telegram) { * e.g. 30 00 FF 00 02 8E 00 00 00 00 00 00 06 C5 00 00 76 35 */ void Solar::process_SM100Energy(std::shared_ptr telegram) { - telegram->read_value32(energyLastHour_, 0); // last hour / 10 in Wh - telegram->read_value32(energyToday_, 4); // todays in Wh - telegram->read_value32(energyTotal_, 8); // total / 10 in kWh + telegram->read_value(energyLastHour_, 0); // last hour / 10 in Wh + telegram->read_value(energyToday_, 4); // todays in Wh + telegram->read_value(energyTotal_, 8); // total / 10 in kWh } /* @@ -210,11 +210,11 @@ void Solar::process_SM100Energy(std::shared_ptr telegram) { * e.g. B0 00 FF 00 00 03 32 00 00 00 00 13 00 D6 00 00 00 FB D0 F0 */ void Solar::process_ISM1StatusMessage(std::shared_ptr telegram) { - telegram->read_value(collectorTemp_, 4); // Collector Temperature - telegram->read_value(bottomTemp_, 6); // Temperature Bottom of Solar Boiler - telegram->read_value32(energyLastHour_, 0); // Solar Energy produced in last hour - is * 10 and handled in ems-esp.cpp - telegram->read_value(pump_, 8, 0); // Solar pump on (1) or off (0) - telegram->read_value(pumpWorkMin_, 10); + telegram->read_value(collectorTemp_, 4); // Collector Temperature + telegram->read_value(bottomTemp_, 6); // Temperature Bottom of Solar Boiler + telegram->read_value(energyLastHour_, 0); // Solar Energy produced in last hour - is * 10 and handled in ems-esp.cpp + telegram->read_bitvalue(pump_, 8, 0); // Solar pump on (1) or off (0) + telegram->read_value(pumpWorkMin_, 10, 3); // force to 3 bytes } /* diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index be31f29f5..e8b4f0080 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -948,9 +948,9 @@ void Thermostat::process_RC20Set(std::shared_ptr telegram) { void Thermostat::process_RC20Monitor_2(std::shared_ptr telegram) { std::shared_ptr hc = heating_circuit(telegram); - telegram->read_value(hc->mode_type, 0, 7); // day/night MSB 7th bit is day - telegram->read_value8(hc->setpoint_roomTemp, 2); // is * 2, force as single byte - telegram->read_value(hc->curr_roomTemp, 3); // is * 10 + telegram->read_bitvalue(hc->mode_type, 0, 7); // day/night MSB 7th bit is day + telegram->read_value(hc->setpoint_roomTemp, 2, 1); // is * 2, force as single byte + telegram->read_value(hc->curr_roomTemp, 3); // is * 10 } // 0xAD - for reading the mode from the RC20/ES72 thermostat (0x17) @@ -971,8 +971,8 @@ void Thermostat::process_RC20Remote(std::shared_ptr telegram) { void Thermostat::process_RC10Monitor(std::shared_ptr telegram) { std::shared_ptr hc = heating_circuit(telegram); - telegram->read_value8(hc->setpoint_roomTemp, 1); // is * 2, force as single byte - telegram->read_value(hc->curr_roomTemp, 2); // is * 10 + telegram->read_value(hc->setpoint_roomTemp, 1, 1); // is * 2, force as single byte + telegram->read_value(hc->curr_roomTemp, 2); // is * 10 } #pragma GCC diagnostic push @@ -1001,8 +1001,8 @@ void Thermostat::process_RCOutdoorTemp(std::shared_ptr telegram) void Thermostat::process_RC20Monitor(std::shared_ptr telegram) { std::shared_ptr hc = heating_circuit(telegram); - telegram->read_value8(hc->setpoint_roomTemp, 1); // is * 2, force as single byte - telegram->read_value(hc->curr_roomTemp, 2); // is * 10 + telegram->read_value(hc->setpoint_roomTemp, 1, 1); // is * 2, force as single byte + telegram->read_value(hc->curr_roomTemp, 2); // is * 10 } // type 0x0A - data from the Nefit Easy/TC100 thermostat (0x18) - 31 bytes long @@ -1031,8 +1031,9 @@ void Thermostat::process_JunkersMonitor(std::shared_ptr telegram telegram->read_value(hc->curr_roomTemp, 4); // value is * 10 telegram->read_value(hc->setpoint_roomTemp, 2); // value is * 10 - telegram->read_value(hc->mode_type, 0, 0); // first bit 1=day, 0=night - telegram->read_value(hc->mode, 1); // 1 = manual, 2 = auto + + telegram->read_bitvalue(hc->mode_type, 0, 0); // first bit 1=day, 0=night + telegram->read_value(hc->mode, 1); // 1 = manual, 2 = auto } // type 0x02A5 - data from the Nefit RC1010/3000 thermostat (0x18) and RC300/310s on 0x10 @@ -1049,8 +1050,8 @@ void Thermostat::process_RC300Monitor(std::shared_ptr telegram) telegram->read_value(hc->curr_roomTemp, 0); // is * 10 } - telegram->read_value(hc->mode_type, 10, 1); - telegram->read_value(hc->mode, 10, 0); // bit 1, mode (auto=1 or manual=0) + telegram->read_bitvalue(hc->mode_type, 10, 1); + telegram->read_bitvalue(hc->mode, 10, 0); // bit 1, mode (auto=1 or manual=0) // if manual, take the current setpoint temp at pos 6 // if auto, take the next setpoint temp at pos 7 @@ -1065,7 +1066,7 @@ void Thermostat::process_RC300Monitor(std::shared_ptr telegram) pos = 3; } - telegram->read_value8(hc->setpoint_roomTemp, pos); // is * 2, force as single byte + telegram->read_value(hc->setpoint_roomTemp, pos, 1); // is * 2, force as single byte } // type 0x02B9 EMS+ for reading from RC300/RC310 thermostat @@ -1077,8 +1078,8 @@ void Thermostat::process_RC300Set(std::shared_ptr telegram) { // comfort is position 2 // I think auto is position 8? // actual setpoint taken from RC300Monitor (Michael 12.06.2020) - // telegram->read_value8(hc->setpoint_roomTemp, 8); // single byte conversion, value is * 2 - auto? - // telegram->read_value8(hc->setpoint_roomTemp, 10); // single byte conversion, value is * 2 - manual + // telegram->read_value(hc->setpoint_roomTemp, 8, 1); // single byte conversion, value is * 2 - auto? + // telegram->read_value(hc->setpoint_roomTemp, 10, 1); // single byte conversion, value is * 2 - manual // check why mode is both in the Monitor and Set for the RC300. It'll be read twice! // telegram->read_value(hc->mode, 0); // Auto = xFF, Manual = x00 eg. 10 00 FF 08 01 B9 FF @@ -1101,7 +1102,7 @@ void Thermostat::process_RC300WWmode(std::shared_ptr telegram) { void Thermostat::process_RC30Monitor(std::shared_ptr telegram) { std::shared_ptr hc = heating_circuit(telegram); - telegram->read_value8(hc->setpoint_roomTemp, 1); // is * 2, force as single byte + telegram->read_value(hc->setpoint_roomTemp, 1, 1); // is * 2, force as single byte telegram->read_value(hc->curr_roomTemp, 2); } @@ -1123,11 +1124,13 @@ void Thermostat::process_RC35Monitor(std::shared_ptr telegram) { std::shared_ptr hc = heating_circuit(telegram); - telegram->read_value8(hc->setpoint_roomTemp, 2); // is * 2, force to single byte, is 0 in summermode - telegram->read_value(hc->curr_roomTemp, 3); // is * 10 - or 0x7D00 if thermostat is mounted on boiler - telegram->read_value(hc->mode_type, 1, 1); - telegram->read_value(hc->summer_mode, 1, 0); - telegram->read_value(hc->holiday_mode, 0, 5); + telegram->read_value(hc->setpoint_roomTemp, 2, 1); // is * 2, force to single byte, is 0 in summermode + telegram->read_value(hc->curr_roomTemp, 3); // is * 10 - or 0x7D00 if thermostat is mounted on boiler + + telegram->read_bitvalue(hc->mode_type, 1, 1); + telegram->read_bitvalue(hc->summer_mode, 1, 0); + telegram->read_bitvalue(hc->holiday_mode, 0, 5); + telegram->read_value(hc->circuitcalctemp, 14); } diff --git a/src/helpers.cpp b/src/helpers.cpp index ed495cc2f..644db4b6c 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -126,7 +126,7 @@ char * Helpers::smallitoa(char * result, const uint16_t value) { char * Helpers::render_value(char * result, uint8_t value, uint8_t format) { result[0] = '\0'; - // check if its a boolean + // special check if its a boolean if (format == EMS_VALUE_BOOL) { if (value == EMS_VALUE_BOOL_OFF) { strlcpy(result, "off", 5); @@ -138,7 +138,7 @@ char * Helpers::render_value(char * result, uint8_t value, uint8_t format) { return result; } - if (value == EMS_VALUE_UINT_NOTSET) { + if (!hasValue(value)) { return nullptr; } @@ -189,8 +189,7 @@ char * Helpers::render_value(char * result, const float value, const uint8_t for char * Helpers::render_value(char * result, const int16_t value, const uint8_t format) { result[0] = '\0'; - // remove errors or invalid values, 0x7D00 and higher - if ((value == EMS_VALUE_SHORT_NOTSET) || (value == EMS_VALUE_SHORT_INVALID) || (value == EMS_VALUE_USHORT_NOTSET)) { + if (!hasValue(value)) { return nullptr; } @@ -232,7 +231,7 @@ char * Helpers::render_value(char * result, const int16_t value, const uint8_t f char * Helpers::render_value(char * result, const uint16_t value, const uint8_t format) { result[0] = '\0'; - if ((value == EMS_VALUE_USHORT_NOTSET) || (value == EMS_VALUE_USHORT_INVALID)) { + if (!hasValue(value)) { return nullptr; } @@ -244,7 +243,7 @@ char * Helpers::render_value(char * result, const uint16_t value, const uint8_t char * Helpers::render_value(char * result, const int8_t value, const uint8_t format) { result[0] = '\0'; - if (value == EMS_VALUE_INT_NOTSET) { + if (!hasValue(value)) { return nullptr; } @@ -256,7 +255,7 @@ char * Helpers::render_value(char * result, const int8_t value, const uint8_t fo char * Helpers::render_value(char * result, const uint32_t value, const uint8_t format) { result[0] = '\0'; - if ((value == EMS_VALUE_ULONG_NOTSET) || (value == EMS_VALUE_ULONG_INVALID)) { + if (!hasValue(value)) { return nullptr; } @@ -358,12 +357,14 @@ bool Helpers::hasValue(const int8_t v) { return (v != EMS_VALUE_INT_NOTSET); } +// for short these are typically 0x8300, 0x7D00 and sometimes 0x8000 +// so we just check for anything > 0x70 bool Helpers::hasValue(const int16_t v) { - return (v != EMS_VALUE_SHORT_NOTSET && v != EMS_VALUE_USHORT_NOTSET && v != EMS_VALUE_SHORT_INVALID && v != EMS_VALUE_USHORT_INVALID); + return ((v >> 8) < 0x70); } bool Helpers::hasValue(const uint16_t v) { - return (v != EMS_VALUE_SHORT_NOTSET && v != EMS_VALUE_USHORT_NOTSET && v != EMS_VALUE_SHORT_INVALID && v != EMS_VALUE_USHORT_INVALID); + return ((v >> 8) < 0x70); } bool Helpers::hasValue(const uint32_t v) { diff --git a/src/telegram.cpp b/src/telegram.cpp index 2f44a8bfa..b2cc765a8 100644 --- a/src/telegram.cpp +++ b/src/telegram.cpp @@ -99,107 +99,6 @@ std::string Telegram::to_string(const uint8_t * telegram, uint8_t length) const return Helpers::data_to_hex(telegram, length); } -// validate we have data at the offset (index) requested -// get adjusted index position based on offset -// if offset is 0, it takes the whole telegram. if it's for example 1 it'll show the 2nd data item and -// everything after it -// returns -1 if out of bounds -int8_t Telegram::_getDataPosition(const uint8_t index, const uint8_t size) const { - return ((index - offset + size - 1) >= message_length) ? -1 : (index - offset); -} - -// unsigned byte -void Telegram::read_value(uint8_t & param, const uint8_t index) const { - int8_t pos = _getDataPosition(index, sizeof(param)); - if (pos < 0) { - return; - } - param = (uint8_t)message_data[pos]; -} - -// signed byte -void Telegram::read_value(int8_t & param, const uint8_t index) const { - int8_t pos = _getDataPosition(index, sizeof(param)); - if (pos < 0) { - return; - } - param = (int8_t)message_data[pos]; -} - -// unsigned short -void Telegram::read_value(uint16_t & param, const uint8_t index) const { - int8_t pos = _getDataPosition(index, sizeof(param)); - if (pos < 0) { - return; - } - - uint16_t value = (message_data[pos] << 8) + message_data[pos + 1]; - - // check for undefined/unset values, 0x8000, 0x8300, 0x7D00 - if ((value == EMS_VALUE_USHORT_NOTSET) || (value == EMS_VALUE_USHORT_INVALID)) { - value = EMS_VALUE_USHORT_NOTSET; // make sure we render this right - } - - param = value; -} - -// signed short -void Telegram::read_value(int16_t & param, const uint8_t index) const { - int8_t pos = _getDataPosition(index, sizeof(param)); - if (pos < 0) { - return; - } - - int16_t value = (message_data[pos] << 8) + message_data[pos + 1]; - - // check for undefined/unset values, 0x8000, 0x8300, 0x7D00 - if ((value == EMS_VALUE_SHORT_NOTSET) || (value == EMS_VALUE_SHORT_INVALID)) { - value = EMS_VALUE_SHORT_NOTSET; // make sure we render this right - } - - param = value; -} - -// Long 24 bit -void Telegram::read_value(uint32_t & param, const uint8_t index) const { - int8_t pos = _getDataPosition(index, 3); - if (pos < 0) { - return; - } - - param = (uint32_t)((message_data[pos] << 16) + (message_data[pos + 1] << 8) + (message_data[pos + 2])); -} - -// Long 32 bit -void Telegram::read_value32(uint32_t & param, const uint8_t index) const { - int8_t pos = _getDataPosition(index, sizeof(param)); - if (pos < 0) { - return; - } - - param = (uint32_t)((message_data[pos] << 24) + (message_data[pos + 1] << 16) + (message_data[pos + 2] << 8) + (message_data[pos + 3])); -} - -// bit from an unsigned byte -void Telegram::read_value(uint8_t & param, const uint8_t index, const uint8_t bit) const { - int8_t pos = _getDataPosition(index, sizeof(param)); - if (pos < 0) { - return; - } - - param = (uint8_t)(((message_data[pos]) >> (bit)) & 0x01); -} - -// convert signed short to single 8 byte, for setpoint thermostat temperatures that don't store their temps in 2 bytes -void Telegram::read_value8(int16_t & param, const uint8_t index) const { - int8_t pos = _getDataPosition(index, 1); - if (pos < 0) { - return; - } - - param = message_data[pos]; -} - RxService::QueuedRxTelegram::QueuedRxTelegram(uint16_t id, std::shared_ptr && telegram) : id_(id) , telegram_(std::move(telegram)) { @@ -214,14 +113,6 @@ void RxService::flush_rx_queue() { // Rx loop, run as many times as you can // processes all telegrams on the queue. Assumes there are valid (i.e. CRC checked) void RxService::loop() { - /* -#ifndef EMSESP_STANDALONE - give rx some breathing space if ((uuid::get_uptime() - last_rx_check_) < RX_LOOP_WAIT) { - return; - } - last_rx_check_ = uuid::get_uptime(); -#endif -*/ while (!rx_telegrams_.empty()) { auto telegram = rx_telegrams_.front().telegram_; @@ -270,7 +161,7 @@ void RxService::add(uint8_t * data, uint8_t length) { uint8_t message_length; // length of the message block, excluding CRC // work out depending on the type, where the data message block starts and the message length - // EMS 1 has type_id always in data[2], if it gets a ems+ inquiery it will reply with FF but short length + // EMS 1 has type_id always in data[2], if it gets a ems+ inquiry it will reply with FF but short length // i.e. sending 0B A1 FF 00 01 D8 20 CRC to a MM10 Mixer (ems1.0), the reply is 21 0B FF 00 CRC // see: https://github.com/proddy/EMS-ESP/issues/380#issuecomment-633663007 if (data[2] < 0xF0 || length < 6) { diff --git a/src/telegram.h b/src/telegram.h index 3aa7719ef..613f0c027 100644 --- a/src/telegram.h +++ b/src/telegram.h @@ -41,15 +41,12 @@ static constexpr uint8_t EMS_VALUE_BOOL = 0xFF; // boolean static constexpr uint8_t EMS_VALUE_BOOL_OFF = 0x00; // boolean false. True can be 0x01 or 0xFF sometimes. -static constexpr uint8_t EMS_VALUE_BOOL_NOTSET = 0xFE; // random number for booleans, that's not 0, 1 or FF -static constexpr uint8_t EMS_VALUE_UINT_NOTSET = 0xFF; // for 8-bit unsigned ints/bytes -static constexpr int8_t EMS_VALUE_INT_NOTSET = 0x7F; // for signed 8-bit ints/bytes -static constexpr int16_t EMS_VALUE_SHORT_NOTSET = 0x8300; // -32000: for 2-byte signed shorts -static constexpr uint16_t EMS_VALUE_USHORT_NOTSET = 0x7D00; // 32000: for 2-byte unsigned shorts -static constexpr uint16_t EMS_VALUE_USHORT_INVALID = 0x8000; -static constexpr int16_t EMS_VALUE_SHORT_INVALID = 0x8000; -static constexpr uint32_t EMS_VALUE_ULONG_NOTSET = 0xFFFFFFFF; // for 3-byte and 4-byte longs -static constexpr uint32_t EMS_VALUE_ULONG_INVALID = 0x80000000; +static constexpr uint8_t EMS_VALUE_BOOL_NOTSET = 0xFE; // random number for booleans, that's not 0, 1 or FF +static constexpr uint8_t EMS_VALUE_UINT_NOTSET = 0xFF; // for 8-bit unsigned ints/bytes +static constexpr int8_t EMS_VALUE_INT_NOTSET = 0x7F; // for signed 8-bit ints/bytes +static constexpr int16_t EMS_VALUE_SHORT_NOTSET = 0x8300; // -32000: for 2-byte signed shorts +static constexpr uint16_t EMS_VALUE_USHORT_NOTSET = 0x7D00; // 32000: for 2-byte unsigned shorts +static constexpr uint32_t EMS_VALUE_ULONG_NOTSET = 0xFFFFFFFF; // for 3-byte and 4-byte longs static constexpr uint8_t EMS_MAX_TELEGRAM_LENGTH = 32; // max length of a complete EMS telegram static constexpr uint8_t EMS_MAX_TELEGRAM_MESSAGE_LENGTH = 27; // max length of message block, assuming EMS1.0 @@ -82,14 +79,36 @@ class Telegram { std::string to_string() const; std::string to_string(const uint8_t * telegram, uint8_t length) const; - void read_value(uint16_t & param, const uint8_t index) const; - void read_value(uint32_t & param, const uint8_t index) const; - void read_value32(uint32_t & param, const uint8_t index) const; - void read_value(uint8_t & param, const uint8_t index, const uint8_t bit) const; - void read_value(uint8_t & param, const uint8_t index) const; - void read_value(int16_t & param, const uint8_t index) const; - void read_value8(int16_t & param, const uint8_t index) const; - void read_value(int8_t & param, const uint8_t index) const; + // reads a bit value from a given telegram position + void read_bitvalue(uint8_t & value, const uint8_t index, const uint8_t bit) const { + if ((index - offset) >= message_length) { + return; // out of bounds + } + + value = (uint8_t)(((message_data[index]) >> (bit)) & 0x01); + } + + // read values from a telegram. We always store the value, regardless if its garbage + template + // assuming negative numbers are stored as 2's-complement + // https://medium.com/@LeeJulija/how-integers-are-stored-in-memory-using-twos-complement-5ba04d61a56c + // 2-compliment : https://www.rapidtables.com/convert/number/decimal-to-hex.html + // https://en.wikipedia.org/wiki/Two%27s_complement + // s is to override number of bytes read (e.g. use 3 to simulat a uint24_t) + void read_value(Value & value, const uint8_t index, uint8_t s = 0) const { + uint8_t size = (!s) ? sizeof(Value) : s; + int8_t abs_index = ((index - offset + size - 1) >= message_length) ? -1 : (index - offset); + if (abs_index < 0) { + return; // out of bounds, we don't change the value + } + + value = 0; + for (uint8_t i = 0; i < size; i++) { + // shift + value = (value << 8) + message_data[abs_index + i]; + } + } + private: int8_t _getDataPosition(const uint8_t index, const uint8_t size) const; diff --git a/src/test/test.cpp b/src/test/test.cpp index 7388fd654..db3287b10 100644 --- a/src/test/test.cpp +++ b/src/test/test.cpp @@ -26,7 +26,6 @@ namespace emsesp { // used with the 'test' command, under su/admin void Test::run_test(uuid::console::Shell & shell, const std::string & command) { if ((command == "render") || (command == "r")) { - uint8_t test1 = 12; int8_t test2 = -12; uint16_t test3 = 456; @@ -86,7 +85,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) { shell.printfln("int16: expecting %02X, got:%02X", 0x0203, int16b); int16_t int16b8 = EMS_VALUE_SHORT_NOTSET; - telegram->read_value(int16b8, 1, 1); // override to 1 byte + telegram->read_value(int16b8, 1, 1); // force to 1 byte shell.printfln("int16 1 byte: expecting %02X, got:%02X", 0x02, int16b8); uint32_t uint32b = EMS_VALUE_ULONG_NOTSET; @@ -107,10 +106,10 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) { // check read bit uint8_t uint8bitb = EMS_VALUE_UINT_NOTSET; - telegram->read_bit(uint8bitb, 1, 1); // value is 0x02 = 0000 0010 + telegram->read_bitvalue(uint8bitb, 1, 1); // value is 0x02 = 0000 0010 shell.printfln("uint8 bit read: expecting 1, got:%d", uint8bitb); uint8bitb = EMS_VALUE_UINT_NOTSET; - telegram->read_bit(uint8bitb, 0, 0); // value is 0x01 = 0000 0001 + telegram->read_bitvalue(uint8bitb, 0, 0); // value is 0x01 = 0000 0001 shell.printfln("uint8 bit read: expecting 1, got:%d", uint8bitb); shell.loop_all(); diff --git a/src/version.h b/src/version.h index 44de94ce8..2a0b6766b 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "2.0.0a24" +#define EMSESP_APP_VERSION "2.0.0a25"