diff --git a/tasmota/support_static_buffer.ino b/lib/default/Ext-printf/src/SBuffer.hpp similarity index 93% rename from tasmota/support_static_buffer.ino rename to lib/default/Ext-printf/src/SBuffer.hpp index 2c3b8887c..57b662554 100644 --- a/tasmota/support_static_buffer.ino +++ b/lib/default/Ext-printf/src/SBuffer.hpp @@ -237,6 +237,21 @@ public: return buf2; } + // nullptr accepted + static bool equalsSBuffer(const class SBuffer * buf1, const class SBuffer * buf2) { + if (buf1 == buf2) { return true; } + if (!buf1 && (buf2->len() == 0)) { return true; } + if (!buf2 && (buf1->len() == 0)) { return true; } + if (!buf1 || !buf2) { return false; } // at least one buf is not empty + // we know that both buf1 and buf2 are non-null + if (buf1->len() != buf2->len()) { return false; } + size_t len = buf1->len(); + for (uint32_t i=0; iget8(i) != buf2->get8(i)) { return false; } + } + return true; + } + protected: static uint8_t asc2byte(char chr) { @@ -269,18 +284,3 @@ public: _buf = nullptr; } } PreAllocatedSBuffer; - -// nullptr accepted -bool equalsSBuffer(const class SBuffer * buf1, const class SBuffer * buf2) { - if (buf1 == buf2) { return true; } - if (!buf1 && (buf2->len() == 0)) { return true; } - if (!buf2 && (buf1->len() == 0)) { return true; } - if (!buf1 || !buf2) { return false; } // at least one buf is not empty - // we know that both buf1 and buf2 are non-null - if (buf1->len() != buf2->len()) { return false; } - size_t len = buf1->len(); - for (uint32_t i=0; iget8(i) != buf2->get8(i)) { return false; } - } - return true; -} \ No newline at end of file diff --git a/lib/default/Ext-printf/src/ext_printf.cpp b/lib/default/Ext-printf/src/ext_printf.cpp index 908aae11a..b8dbfa2b4 100644 --- a/lib/default/Ext-printf/src/ext_printf.cpp +++ b/lib/default/Ext-printf/src/ext_printf.cpp @@ -20,6 +20,7 @@ #include "ext_printf.h" #include #include +#include /*********************************************************************************************\ * va_list extended support @@ -139,6 +140,26 @@ char * U64toHex(uint64_t value, char *str) { return str; } +// see https://stackoverflow.com/questions/6357031/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-in-c +// char* ToHex_P(unsigned char * in, size_t insz, char * out, size_t outsz, char inbetween = '\0'); in tasmota_globals.h +char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, char inbetween = '\0') { + // ToHex_P(in, insz, out, outz) -> "12345667" + // ToHex_P(in, insz, out, outz, ' ') -> "12 34 56 67" + // ToHex_P(in, insz, out, outz, ':') -> "12:34:56:67" + static const char * hex PROGMEM = "0123456789ABCDEF"; + int between = (inbetween) ? 3 : 2; + const unsigned char * pin = in; + char * pout = out; + for (; pin < in+insz; pout += between, pin++) { + pout[0] = pgm_read_byte(&hex[(pgm_read_byte(pin)>>4) & 0xF]); + pout[1] = pgm_read_byte(&hex[ pgm_read_byte(pin) & 0xF]); + if (inbetween) { pout[2] = inbetween; } + if (pout + 3 - out > outsz) { break; } // Better to truncate output string than overflow buffer + } + pout[(inbetween && insz) ? -1 : 0] = 0; // Discard last inbetween if any input + return out; +} + /*********************************************************************************************\ * snprintf extended * @@ -166,10 +187,11 @@ int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list const uint32_t ALLOC_SIZE = 12; static char * allocs[ALLOC_SIZE] = {}; // initialized to zeroes uint32_t alloc_idx = 0; - int32_t decimals = -2; // default to 2 decimals and remove trailing zeros static char hex[20]; // buffer used for 64 bits, favor RAM instead of stack to remove pressure for (; *fmt != 0; ++fmt) { + int32_t decimals = -2; // default to 2 decimals and remove trailing zeros + int32_t * decimals_ptr = nullptr; if (alloc_idx >= ALLOC_SIZE) { break; } // buffer is full, don't continue parsing if (*fmt == '%') { fmt++; @@ -177,8 +199,11 @@ int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list if (*fmt == '\0') { break; } // end of string if (*fmt == '%') { continue; } // actual '%' char if (*fmt == '*') { - va_arg(va, int32_t); // skip width argument as int + decimals = va_arg(va, int32_t); // skip width argument as int + decimals_ptr = va_cur_ptr4(va, int32_t); // pointer to value on stack + const char ** cur_val_ptr = va_cur_ptr4(va, const char*); // pointer to value on stack fmt++; + // Serial.printf("> decimals=%d, decimals_ptr=0x%08X\n", decimals, decimals_ptr); } if (*fmt < 'A') { decimals = strtol(fmt, nullptr, 10); @@ -189,6 +214,12 @@ int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list } if (*fmt == '_') { // extension + if (decimals_ptr) { + // Serial.printf(">2 decimals=%d, decimals_ptr=0x%08X\n", decimals, decimals_ptr); + *decimals_ptr = 0; // if '*' was used, make sure we replace the value with zero for snprintf() + *(fmt_start++) = '-'; // in this case replace with `%-*s` + *(fmt_start++) = '*'; + } for (; fmt_start <= fmt; fmt_start++) { *fmt_start = '0'; } @@ -198,14 +229,43 @@ int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list const char ** cur_val_ptr = va_cur_ptr4(va, const char*); // pointer to value on stack char * new_val_str = (char*) ""; switch (*fmt) { + case 'H': // Hex, decimals indicates the length, default 2 + { + if (decimals < 0) { decimals = 0; } + if (decimals > 0) { + char * hex_char = (char*) malloc(decimals*2 + 2); + ToHex_P((const uint8_t *)cur_val, decimals, hex_char, decimals*2 + 2); + new_val_str = hex_char; + allocs[alloc_idx++] = new_val_str; + // Serial.printf("> hex=%s\n", hex_char); + } + } + break; + case 'B': // Pointer to SBuffer + { + const SBuffer & buf = *(const SBuffer*)cur_val; + size_t buf_len = (&buf != nullptr) ? buf.len() : 0; + if (buf_len) { + char * hex_char = (char*) malloc(buf_len*2 + 2); + ToHex_P(buf.getBuffer(), buf_len, hex_char, buf_len*2 + 2); + new_val_str = hex_char; + allocs[alloc_idx++] = new_val_str; + } + } + break; // case 'D': // decimals = *(int32_t*)cur_val_ptr; // break; // `%_I` ouputs an IPv4 32 bits address passed as u32 into a decimal dotted format case 'I': // Input is `uint32_t` 32 bits IP address, output is decimal dotted address - new_val_str = copyStr(IPAddress(cur_val).toString().c_str()); - allocs[alloc_idx++] = new_val_str; + { + char * ip_str = (char*) malloc(16); + IPAddress ip(cur_val); + sprintf_P(ip_str, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]); + new_val_str = ip_str; + allocs[alloc_idx++] = new_val_str; + } break; // `%_f` or `%*_f` outputs a float with optionan number of decimals passed as first argument if `*` is present @@ -224,21 +284,26 @@ int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list decimals = -decimals; truncate = true; } - dtostrf(*(float*)cur_val, (decimals + 2), decimals, hex); + float number = *(float*)cur_val; + if (isnan(number) || isinf(number)) { + new_val_str = (char*) "null"; + } else { + dtostrf(*(float*)cur_val, (decimals + 2), decimals, hex); - if (truncate) { - uint32_t last = strlen(hex) - 1; - // remove trailing zeros - while (hex[last] == '0') { - hex[last--] = 0; // remove last char - } - // remove trailing dot - if (hex[last] == '.') { - hex[last] = 0; + if (truncate) { + uint32_t last = strlen(hex) - 1; + // remove trailing zeros + while (hex[last] == '0') { + hex[last--] = 0; // remove last char + } + // remove trailing dot + if (hex[last] == '.') { + hex[last] = 0; + } } + new_val_str = copyStr(hex); + allocs[alloc_idx++] = new_val_str; } - new_val_str = copyStr(hex); - allocs[alloc_idx++] = new_val_str; } break; // '%_X' outputs a 64 bits unsigned int to uppercase HEX with 16 digits @@ -277,14 +342,17 @@ int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list #else // defined(ESP8266) || defined(ESP32) #error "ext_printf is not suppoerted on this platform" #endif // defined(ESP8266) || defined(ESP32) + // Serial.printf("> format_final=%s\n", fmt_cpy); Serial.flush(); int32_t ret = vsnprintf_P(buf, buf_len, fmt_cpy, va_cpy); va_end(va_cpy); + + // disallocated all temporary strings for (uint32_t i = 0; i < alloc_idx; i++) { - free(allocs[i]); + free(allocs[i]); // it is ok to call free() on nullptr so we don't test for nullptr first allocs[i] = nullptr; } - free(fmt_cpy); + free(fmt_cpy); // free the local copy of the format string return ret; } diff --git a/lib/default/Ext-printf/src/ext_printf.h b/lib/default/Ext-printf/src/ext_printf.h index 6dc4d4061..82313cfc7 100644 --- a/lib/default/Ext-printf/src/ext_printf.h +++ b/lib/default/Ext-printf/src/ext_printf.h @@ -27,6 +27,8 @@ int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list va); int32_t ext_snprintf_P(char * buf, size_t buf_len, const char * fmt, ...); +char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, char inbetween); + // void test_ext_snprintf_P(void); #endif // EXT_PRINTF_H \ No newline at end of file diff --git a/lib/default/Ext-printf/test/test_ext_printf.cpp b/lib/default/Ext-printf/test/test_ext_printf.cpp index d29e9e8e7..f8b7b2ff9 100644 --- a/lib/default/Ext-printf/test/test_ext_printf.cpp +++ b/lib/default/Ext-printf/test/test_ext_printf.cpp @@ -64,12 +64,16 @@ void test_ext_snprintf_P(void) { ext_snprintf_P(c, sizeof(c), "Float default=%1_f, int(3)=%4_f, int(3)=%-4_f, int(3)=%-4_f, 6dec=%-8_f", &fpi, &f3, &f3, &f31, &fpi); Serial.printf("--> out=%s\n", c); + ext_snprintf_P(c, sizeof(c), "Float default=%*_f, int(3)=%*_f, int(3)=%*_f, int(3)=%*_f, 6dec=%*_f", 1, &fpi, 4, &f3, -4, &f3, -4, &f31, -8, &fpi); + Serial.printf("--> out=%s\n", c); uint64_t u641 = 0x1122334455667788LL; uint64_t u642 = 0x0123456789ABCDEFLL; uint64_t u643 = 0xFEDCBA9876543210LL; ext_snprintf_P(c, sizeof(c), "Int64 0x%_X 0x%_X 0x%_X", &u641, &u642, &u643); Serial.printf("--> out=%s\n", c); + // ext_snprintf_P(c, sizeof(c), "Float default=%*_f, int(3)=%*_f, int(3)=%*_f, int(3)=%*_f, 6dec=%*_f", &fpi, &f3, &f3, &f31, &fpi); + // String string("Foobar"); // ext_snprintf_P(c, sizeof(c), "String 0x%08X %_s", &string, &string); // Serial.printf("--> out=%s\n", c); diff --git a/tasmota/support.ino b/tasmota/support.ino index 3d4cd5338..67113d2e8 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -322,27 +322,6 @@ int TextToInt(char *str) return strtol(str, &p, radix); } -// see https://stackoverflow.com/questions/6357031/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-in-c -// char* ToHex_P(unsigned char * in, size_t insz, char * out, size_t outsz, char inbetween = '\0'); in tasmota_globals.h -char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, char inbetween) -{ - // ToHex_P(in, insz, out, outz) -> "12345667" - // ToHex_P(in, insz, out, outz, ' ') -> "12 34 56 67" - // ToHex_P(in, insz, out, outz, ':') -> "12:34:56:67" - static const char * hex = "0123456789ABCDEF"; - int between = (inbetween) ? 3 : 2; - const unsigned char * pin = in; - char * pout = out; - for (; pin < in+insz; pout += between, pin++) { - pout[0] = hex[(pgm_read_byte(pin)>>4) & 0xF]; - pout[1] = hex[ pgm_read_byte(pin) & 0xF]; - if (inbetween) { pout[2] = inbetween; } - if (pout + 3 - out > outsz) { break; } // Better to truncate output string than overflow buffer - } - pout[(inbetween && insz) ? -1 : 0] = 0; // Discard last inbetween if any input - return out; -} - char* dtostrfd(double number, unsigned char prec, char *s) { if ((isnan(number)) || (isinf(number))) { // Fix for JSON output (https://stackoverflow.com/questions/1423081/json-left-out-infinity-and-nan-json-status-in-ecmascript) diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 1a956fd0c..027ee61d6 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -53,6 +53,7 @@ #include // Ota #include // Webserver, Updater #include +#include #include #include #ifdef USE_ARDUINO_OTA diff --git a/tasmota/xdrv_23_zigbee_1_headers.ino b/tasmota/xdrv_23_zigbee_1_headers.ino index f3a88914d..203c16d5e 100644 --- a/tasmota/xdrv_23_zigbee_1_headers.ino +++ b/tasmota/xdrv_23_zigbee_1_headers.ino @@ -45,7 +45,7 @@ public: }; typedef int32_t (*ZB_Func)(uint8_t value); -typedef int32_t (*ZB_RecvMsgFunc)(int32_t res, const class SBuffer &buf); +typedef int32_t (*ZB_RecvMsgFunc)(int32_t res, const SBuffer &buf); // Labels used in the State Machine -- internal only const uint8_t ZIGBEE_LABEL_RESTART = 1; // Restart the state_machine in a different mode @@ -118,6 +118,7 @@ public: struct ZigbeeStatus zigbee; SBuffer *zigbee_buffer = nullptr; +void zigbeeZCLSendCmd(const ZigbeeZCLSendMessage &msg); void ZigbeeZCLSend_Raw(const ZigbeeZCLSendMessage &zcl); bool ZbAppendWriteBuf(SBuffer & buf, const Z_attribute & attr, bool prepend_status_ok = false); diff --git a/tasmota/xdrv_23_zigbee_1z_libs.ino b/tasmota/xdrv_23_zigbee_1z_libs.ino index 7531b003e..c2510a01e 100644 --- a/tasmota/xdrv_23_zigbee_1z_libs.ino +++ b/tasmota/xdrv_23_zigbee_1z_libs.ino @@ -537,7 +537,7 @@ bool Z_attribute::equalsVal(const Z_attribute & attr2) const { if (val.uval32 != attr2.val.uval32) { return false; } } else if (type == Za_type::Za_raw) { // compare 2 Static buffers - return equalsSBuffer(val.bval, attr2.val.bval); + return SBuffer::equalsSBuffer(val.bval, attr2.val.bval); } else if (type == Za_type::Za_str) { // if (val_str_raw != attr2.val_str_raw) { return false; } if (strcmp_PP(val.sval, attr2.val.sval)) { return false; } diff --git a/tasmota/xdrv_23_zigbee_4_persistence.ino b/tasmota/xdrv_23_zigbee_4_persistence.ino index c306cb184..42549ad6b 100644 --- a/tasmota/xdrv_23_zigbee_4_persistence.ino +++ b/tasmota/xdrv_23_zigbee_4_persistence.ino @@ -136,7 +136,7 @@ bool hibernateDeviceConfiguration(SBuffer & buf, const class Z_Data_Set & data, return found; } -class SBuffer hibernateDevicev2(const struct Z_Device &device) { +SBuffer hibernateDevicev2(const struct Z_Device &device) { SBuffer buf(128); buf.add8(0x00); // overall length, will be updated later @@ -178,7 +178,7 @@ class SBuffer hibernateDevicev2(const struct Z_Device &device) { return buf; } -class SBuffer hibernateDevices(void) { +SBuffer hibernateDevices(void) { SBuffer buf(2048); size_t devices_size = zigbee_devices.devicesSize(); diff --git a/tasmota/xdrv_23_zigbee_4b_eeprom.ino b/tasmota/xdrv_23_zigbee_4b_eeprom.ino index 6acada897..68f768783 100644 --- a/tasmota/xdrv_23_zigbee_4b_eeprom.ino +++ b/tasmota/xdrv_23_zigbee_4b_eeprom.ino @@ -74,7 +74,7 @@ bool hydrateDeviceData(class Z_Device & device, const SBuffer & buf, size_t star // negative means error // positive is the segment length -int32_t hydrateSingleDevice(const class SBuffer & buf, size_t start, size_t len) { +int32_t hydrateSingleDevice(const SBuffer & buf, size_t start, size_t len) { uint8_t segment_len = buf.get8(start); if ((segment_len < 4) || (start + segment_len > len)) { AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "invalid segment_len=%d"), segment_len); @@ -154,7 +154,7 @@ bool hydrateDevicesDataFromEEPROM(void) { #endif // USE_ZIGBEE_EZSP } -class SBuffer hibernateDeviceData(const struct Z_Device & device, bool mqtt = false) { +SBuffer hibernateDeviceData(const struct Z_Device & device, bool mqtt = false) { SBuffer buf(192); // If we have zero information about the device, just skip ir diff --git a/tasmota/xdrv_23_zigbee_5_converters.ino b/tasmota/xdrv_23_zigbee_5_converters.ino index 3380d2fc0..b1e94a84c 100644 --- a/tasmota/xdrv_23_zigbee_5_converters.ino +++ b/tasmota/xdrv_23_zigbee_5_converters.ino @@ -869,7 +869,7 @@ uint8_t toPercentageCR2032(uint32_t voltage) { // Adds to buf: // - n bytes: value (typically between 1 and 4 bytes, or bigger for strings) // returns number of bytes of attribute, or <0 if error -int32_t encodeSingleAttribute(class SBuffer &buf, double val_d, const char *val_str, uint8_t attrtype) { +int32_t encodeSingleAttribute(SBuffer &buf, double val_d, const char *val_str, uint8_t attrtype) { uint32_t len = Z_getDatatypeLen(attrtype); // pre-compute length, overloaded for variable length attributes uint32_t u32 = val_d; int32_t i32 = val_d; diff --git a/tasmota/xdrv_23_zigbee_6_commands.ino b/tasmota/xdrv_23_zigbee_6_commands.ino index a8566705a..ea0196368 100644 --- a/tasmota/xdrv_23_zigbee_6_commands.ino +++ b/tasmota/xdrv_23_zigbee_6_commands.ino @@ -82,6 +82,7 @@ const Z_CommandConverter Z_Commands[] PROGMEM = { { Z_(HueSat), 0x0300, 0x06, 0x01, Z_(xxyy0A00) }, // Hue, Sat { Z_(Color), 0x0300, 0x07, 0x01, Z_(xxxxyyyy0A00) }, // x, y (uint16) { Z_(CT), 0x0300, 0x0A, 0x01, Z_(xxxx0A00) }, // Color Temperature Mireds (uint16) + { Z_(RGB), 0x0300, 0xF0, 0x81, Z_() }, // synthetic commands converting RGB to XY { Z_(ShutterOpen), 0x0102, 0x00, 0x01, Z_() }, { Z_(ShutterClose), 0x0102, 0x01, 0x01, Z_() }, { Z_(ShutterStop), 0x0102, 0x02, 0x01, Z_() }, @@ -282,7 +283,7 @@ void convertClusterSpecific(class Z_attribute_list &attr_list, uint16_t cluster, uint8_t conv_direction; Z_XYZ_Var xyz; -//AddLog_P(LOG_LEVEL_INFO, PSTR(">>> len = %d - %02X%02X%02X"), payload.len(), payload.get8(0), payload.get8(1), payload.get8(2)); + //AddLog_P(LOG_LEVEL_INFO, PSTR(">>> len = %d - %02X%02X%02X"), payload.len(), payload.get8(0), payload.get8(1), payload.get8(2)); for (uint32_t i = 0; i < sizeof(Z_Commands) / sizeof(Z_Commands[0]); i++) { const Z_CommandConverter *conv = &Z_Commands[i]; uint16_t conv_cluster = pgm_read_word(&conv->cluster); @@ -298,18 +299,18 @@ void convertClusterSpecific(class Z_attribute_list &attr_list, uint16_t cluster, // - payload exactly matches conv->param (conv->param may be longer) // - payload matches conv->param until 'x', 'y' or 'z' const char * p = Z_strings + pgm_read_word(&conv->param_offset); - //AddLog_P(LOG_LEVEL_INFO, PSTR(">>>++1 param = %s"), p); + //AddLog_P(LOG_LEVEL_INFO, PSTR(">>>++1 param = %s"), p); bool match = true; for (uint8_t i = 0; i < payload.len(); i++) { const char c1 = pgm_read_byte(p); // const char c2 = pgm_read_byte(p+1); - //AddLog_P(LOG_LEVEL_INFO, PSTR(">>>++2 c1 = %c, c2 = %c"), c1, c2); + //AddLog_P(LOG_LEVEL_INFO, PSTR(">>>++2 c1 = %c, c2 = %c"), c1, c2); if ((0x00 == c1) || isXYZ(c1)) { break; } const char * p2 = p; uint32_t nextbyte = parseHex_P(&p2, 2); - //AddLog_P(LOG_LEVEL_INFO, PSTR(">>>++3 parseHex_P = %02X"), nextbyte); + //AddLog_P(LOG_LEVEL_INFO, PSTR(">>>++3 parseHex_P = %02X"), nextbyte); if (nextbyte != payload.get8(i)) { match = false; break; @@ -461,6 +462,12 @@ void convertClusterSpecific(class Z_attribute_list &attr_list, uint16_t cluster, } } +/*********************************************************************************************\ + * + * Tuya Zigbee specific protocol + * +\*********************************************************************************************/ +// Parse a sinlge attribute value and convert to human readable JSON attribute value void parseSingleTuyaAttribute(Z_attribute & attr, const SBuffer &buf, uint32_t i, uint32_t len, int32_t attrtype) { @@ -519,6 +526,11 @@ bool convertTuyaSpecificCluster(class Z_attribute_list &attr_list, uint16_t clus return false; } +/*********************************************************************************************\ + * + * Find commands + * +\*********************************************************************************************/ // Find the command details by command name // Only take commands outgoing, i.e. direction == 0 // If not found: @@ -604,4 +616,11 @@ uint32_t ZigbeeAliasOrNumber(const char *state_text) { } } + +/*********************************************************************************************\ + * + * Send Zigbee commands + * +\*********************************************************************************************/ + #endif // USE_ZIGBEE diff --git a/tasmota/xdrv_23_zigbee_7_0_statemachine.ino b/tasmota/xdrv_23_zigbee_7_0_statemachine.ino index 7c85bc015..72d88a680 100644 --- a/tasmota/xdrv_23_zigbee_7_0_statemachine.ino +++ b/tasmota/xdrv_23_zigbee_7_0_statemachine.ino @@ -1094,7 +1094,7 @@ void ZigbeeStateMachine_Run(void) { // // Process a bytes buffer and call any callback that matches the received message // -int32_t ZigbeeProcessInput(class SBuffer &buf) { +int32_t ZigbeeProcessInput(SBuffer &buf) { if (!zigbee.state_machine) { return -1; } // if state machine is stopped, send 'ignore' message // apply the receive filter, acts as 'startsWith()' diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index 3c1d3e79b..696c7ad1a 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -74,7 +74,7 @@ void EZ_ERROR(uint8_t error_code) { MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); } -int32_t EZ_ReadAPSUnicastMessage(int32_t res, class SBuffer &buf) { +int32_t EZ_ReadAPSUnicastMessage(int32_t res, SBuffer &buf) { // Called when receiving a response from getConfigurationValue // Value is in bytes 2+3 // uint16_t value = buf.get16(2); @@ -88,7 +88,7 @@ int32_t EZ_ReadAPSUnicastMessage(int32_t res, class SBuffer &buf) { // // Handle a "getEui64" incoming message // -int32_t EZ_GetEUI64(int32_t res, class SBuffer &buf) { +int32_t EZ_GetEUI64(int32_t res, SBuffer &buf) { localIEEEAddr = buf.get64(2); return res; } @@ -96,7 +96,7 @@ int32_t EZ_GetEUI64(int32_t res, class SBuffer &buf) { // // Handle a "getEui64" incoming message // -int32_t EZ_GetNodeId(int32_t res, class SBuffer &buf) { +int32_t EZ_GetNodeId(int32_t res, SBuffer &buf) { localShortAddr = buf.get8(2); return res; } @@ -104,7 +104,7 @@ int32_t EZ_GetNodeId(int32_t res, class SBuffer &buf) { // // Handle a "getNetworkParameters" incoming message // -int32_t EZ_NetworkParameters(int32_t res, class SBuffer &buf) { +int32_t EZ_NetworkParameters(int32_t res, SBuffer &buf) { uint8_t node_type = buf.get8(3); // ext panid: 4->11 // panid: 12->13 @@ -128,7 +128,7 @@ int32_t EZ_NetworkParameters(int32_t res, class SBuffer &buf) { // // Analyze response to "getKey" and check NWK key // -int32_t EZ_CheckKeyNWK(int32_t res, class SBuffer &buf) { +int32_t EZ_CheckKeyNWK(int32_t res, SBuffer &buf) { // uint8_t status = buf.get8(2); // uint16_t bitmask = buf.get16(3); uint8_t key_type = buf.get8(5); @@ -147,7 +147,7 @@ int32_t EZ_CheckKeyNWK(int32_t res, class SBuffer &buf) { // // Handle a "incomingRouteErrorHandler" incoming message // -int32_t EZ_RouteError(int32_t res, const class SBuffer &buf) { +int32_t EZ_RouteError(int32_t res, const SBuffer &buf) { uint8_t status = buf.get8(2); uint16_t shortaddr = buf.get16(3); @@ -163,7 +163,7 @@ int32_t EZ_RouteError(int32_t res, const class SBuffer &buf) { // // Handle a "permitJoining" incoming message // -int32_t EZ_PermitJoinRsp(int32_t res, const class SBuffer &buf) { +int32_t EZ_PermitJoinRsp(int32_t res, const SBuffer &buf) { uint8_t status = buf.get8(2); if (status) { // only report if there is an error @@ -187,7 +187,7 @@ void Z_PermitJoinDisable(void) { // // We normally ignore the message, but it's a way to sniff group ids for IKEA remote // In case of a multicast message sent to 0xFFFD with non-null group id, we log the group id -int32_t EZ_MessageSent(int32_t res, const class SBuffer &buf) { +int32_t EZ_MessageSent(int32_t res, const SBuffer &buf) { uint8_t message_type = buf.get8(2); uint16_t dst_addr = buf.get16(3); uint16_t group_addr = buf.get16(13); @@ -247,7 +247,7 @@ void Z_Map(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t end // // Handle a "getEui64" incoming message // -int32_t Z_EZSPGetEUI64(int32_t res, class SBuffer &buf) { +int32_t Z_EZSPGetEUI64(int32_t res, SBuffer &buf) { localIEEEAddr = buf.get64(2); return res; } @@ -255,7 +255,7 @@ int32_t Z_EZSPGetEUI64(int32_t res, class SBuffer &buf) { // // Handle a "getEui64" incoming message // -int32_t Z_EZSPGetNodeId(int32_t res, class SBuffer &buf) { +int32_t Z_EZSPGetNodeId(int32_t res, SBuffer &buf) { localShortAddr = buf.get8(2); return res; } @@ -263,7 +263,7 @@ int32_t Z_EZSPGetNodeId(int32_t res, class SBuffer &buf) { // // Handle a "getNetworkParameters" incoming message // -int32_t Z_EZSPNetworkParameters(int32_t res, class SBuffer &buf) { +int32_t Z_EZSPNetworkParameters(int32_t res, SBuffer &buf) { uint8_t node_type = buf.get8(3); // ext panid: 4->11 // panid: 12->13 @@ -291,7 +291,7 @@ int32_t Z_EZSPNetworkParameters(int32_t res, class SBuffer &buf) { // // Handle a "Receive Device Info" incoming message // -int32_t ZNP_ReceiveDeviceInfo(int32_t res, class SBuffer &buf) { +int32_t ZNP_ReceiveDeviceInfo(int32_t res, SBuffer &buf) { // Ex= 6700.00.6263151D004B1200.0000.07.09.02.83869991 // IEEE Adr (8 bytes) = 0x00124B001D156362 // Short Addr (2 bytes) = 0x0000 @@ -333,7 +333,7 @@ int32_t ZNP_ReceiveDeviceInfo(int32_t res, class SBuffer &buf) { return res; } -int32_t ZNP_CheckNVWrite(int32_t res, class SBuffer &buf) { +int32_t ZNP_CheckNVWrite(int32_t res, SBuffer &buf) { // Check the status after NV Init "ZNP Has Configured" // Good response should be 610700 or 610709 (Success or Created) // We only filter the response on 6107 and check the code in this function @@ -345,7 +345,7 @@ int32_t ZNP_CheckNVWrite(int32_t res, class SBuffer &buf) { } } -int32_t ZNP_Reboot(int32_t res, class SBuffer &buf) { +int32_t ZNP_Reboot(int32_t res, SBuffer &buf) { // print information about the reboot of device // 4180.02.02.00.02.06.03 // @@ -380,7 +380,7 @@ int32_t ZNP_Reboot(int32_t res, class SBuffer &buf) { } #ifdef USE_ZIGBEE_ZNP -int32_t ZNP_ReceiveCheckVersion(int32_t res, class SBuffer &buf) { +int32_t ZNP_ReceiveCheckVersion(int32_t res, SBuffer &buf) { // check that the version is supported // typical version for ZNP 1.2 // 61020200-02.06.03.D9143401.0200000000 @@ -412,7 +412,7 @@ int32_t ZNP_ReceiveCheckVersion(int32_t res, class SBuffer &buf) { #endif // USE_ZIGBEE_ZNP #ifdef USE_ZIGBEE_EZSP -int32_t EZ_ReceiveCheckVersion(int32_t res, class SBuffer &buf) { +int32_t EZ_ReceiveCheckVersion(int32_t res, SBuffer &buf) { uint8_t protocol_version = buf.get8(2); uint8_t stack_type = buf.get8(3); uint16_t stack_version = buf.get16(4); @@ -463,7 +463,7 @@ int32_t EZ_GotoIfResetConfig(uint8_t value) { // If coordinator continue // If router goto ZIGBEE_LABEL_START_ROUTER // If device goto ZIGBEE_LABEL_START_DEVICE -int32_t Z_SwitchDeviceType(int32_t res, class SBuffer &buf) { +int32_t Z_SwitchDeviceType(int32_t res, SBuffer &buf) { switch (Settings.zb_pan_id) { case 0xFFFF: return ZIGBEE_LABEL_INIT_ROUTER; case 0xFFFE: return ZIGBEE_LABEL_INIT_DEVICE; @@ -474,7 +474,7 @@ int32_t Z_SwitchDeviceType(int32_t res, class SBuffer &buf) { // // Helper function, checks if the incoming buffer matches the 2-bytes prefix, i.e. message type in PMEM // -bool Z_ReceiveMatchPrefix(const class SBuffer &buf, const uint8_t *match) { +bool Z_ReceiveMatchPrefix(const SBuffer &buf, const uint8_t *match) { if ( (pgm_read_byte(&match[0]) == buf.get8(0)) && (pgm_read_byte(&match[1]) == buf.get8(1)) ) { return true; @@ -486,7 +486,7 @@ bool Z_ReceiveMatchPrefix(const class SBuffer &buf, const uint8_t *match) { // // Handle Permit Join response // -int32_t ZNP_ReceivePermitJoinStatus(int32_t res, const class SBuffer &buf) { +int32_t ZNP_ReceivePermitJoinStatus(int32_t res, const SBuffer &buf) { // we received a PermitJoin status change uint8_t duration = buf.get8(2); uint8_t status_code; @@ -518,7 +518,7 @@ int32_t ZNP_ReceivePermitJoinStatus(int32_t res, const class SBuffer &buf) { // // ZNP only // -int32_t ZNP_ReceiveNodeDesc(int32_t res, const class SBuffer &buf) { +int32_t ZNP_ReceiveNodeDesc(int32_t res, const SBuffer &buf) { // Received ZDO_NODE_DESC_RSP // Z_ShortAddress srcAddr = buf.get16(2); uint8_t status = buf.get8(4); @@ -560,7 +560,7 @@ int32_t ZNP_ReceiveNodeDesc(int32_t res, const class SBuffer &buf) { // // Porcess Receive Active Endpoint // -int32_t Z_ReceiveActiveEp(int32_t res, const class SBuffer &buf) { +int32_t Z_ReceiveActiveEp(int32_t res, const SBuffer &buf) { // Received ZDO_ACTIVE_EP_RSP #ifdef USE_ZIGBEE_ZNP // Z_ShortAddress srcAddr = buf.get16(2); @@ -672,7 +672,7 @@ void Z_AutoBindDefer(uint16_t shortaddr, uint8_t endpoint, const SBuffer &buf, } } -int32_t Z_ReceiveSimpleDesc(int32_t res, const class SBuffer &buf) { +int32_t Z_ReceiveSimpleDesc(int32_t res, const SBuffer &buf) { #ifdef USE_ZIGBEE_ZNP // Received ZDO_SIMPLE_DESC_RSP // Z_ShortAddress srcAddr = buf.get16(2); @@ -747,7 +747,7 @@ int32_t Z_ReceiveSimpleDesc(int32_t res, const class SBuffer &buf) { // Handle IEEEAddr incoming message // // Same works for both ZNP and EZSP -int32_t Z_ReceiveIEEEAddr(int32_t res, const class SBuffer &buf) { +int32_t Z_ReceiveIEEEAddr(int32_t res, const SBuffer &buf) { #ifdef USE_ZIGBEE_ZNP uint8_t status = buf.get8(2); Z_IEEEAddress ieeeAddr = buf.get64(3); @@ -784,7 +784,7 @@ int32_t Z_ReceiveIEEEAddr(int32_t res, const class SBuffer &buf) { // Report any AF_DATA_CONFIRM message // Ex: {"ZbConfirm":{"Endpoint":1,"Status":0,"StatusMessage":"SUCCESS"}} // -int32_t ZNP_DataConfirm(int32_t res, const class SBuffer &buf) { +int32_t ZNP_DataConfirm(int32_t res, const SBuffer &buf) { uint8_t status = buf.get8(2); uint8_t endpoint = buf.get8(3); //uint8_t transId = buf.get8(4); // unused @@ -815,7 +815,7 @@ int32_t ZNP_DataConfirm(int32_t res, const class SBuffer &buf) { // 0x08: Starting as ZigBee Coordinator // 0x09: Started as ZigBee Coordinator // 0x0A: Device has lost information about its parent -int32_t ZNP_ReceiveStateChange(int32_t res, const class SBuffer &buf) { +int32_t ZNP_ReceiveStateChange(int32_t res, const SBuffer &buf) { uint8_t state = buf.get8(2); const char * msg = nullptr; @@ -865,7 +865,7 @@ int32_t ZNP_ReceiveStateChange(int32_t res, const class SBuffer &buf) { // This message is also received when a previously paired device is powered up // Send back Active Ep Req message // -int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf) { +int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const SBuffer &buf) { #ifdef USE_ZIGBEE_ZNP // Z_ShortAddress srcAddr = buf.get16(2); Z_ShortAddress nwkAddr = buf.get16(4); @@ -915,7 +915,7 @@ int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf) { // Handle Receive TC Dev Ind incoming message // 45CA // -int32_t ZNP_ReceiveTCDevInd(int32_t res, const class SBuffer &buf) { +int32_t ZNP_ReceiveTCDevInd(int32_t res, const SBuffer &buf) { Z_ShortAddress srcAddr = buf.get16(2); Z_IEEEAddress ieeeAddr = buf.get64(4); Z_ShortAddress parentNw = buf.get16(12); @@ -937,7 +937,7 @@ int32_t ZNP_ReceiveTCDevInd(int32_t res, const class SBuffer &buf) { // // Handle Bind Rsp incoming message // -int32_t Z_BindRsp(int32_t res, const class SBuffer &buf) { +int32_t Z_BindRsp(int32_t res, const SBuffer &buf) { #ifdef USE_ZIGBEE_ZNP Z_ShortAddress nwkAddr = buf.get16(2); uint8_t status = buf.get8(4); @@ -970,7 +970,7 @@ int32_t Z_BindRsp(int32_t res, const class SBuffer &buf) { // // Handle Unbind Rsp incoming message // -int32_t Z_UnbindRsp(int32_t res, const class SBuffer &buf) { +int32_t Z_UnbindRsp(int32_t res, const SBuffer &buf) { #ifdef USE_ZIGBEE_ZNP Z_ShortAddress nwkAddr = buf.get16(2); uint8_t status = buf.get8(4); @@ -1003,7 +1003,7 @@ int32_t Z_UnbindRsp(int32_t res, const class SBuffer &buf) { // // Handle MgMt Bind Rsp incoming message // -int32_t Z_MgmtBindRsp(int32_t res, const class SBuffer &buf) { +int32_t Z_MgmtBindRsp(int32_t res, const SBuffer &buf) { return Z_Mgmt_Lqi_Bind_Rsp(res, buf, false); } @@ -1043,7 +1043,7 @@ const char * Z_DeviceType(uint32_t value) { // // If the response has a follow-up, send more requests automatically // -int32_t Z_Mgmt_Lqi_Bind_Rsp(int32_t res, const class SBuffer &buf, boolean lqi) { +int32_t Z_Mgmt_Lqi_Bind_Rsp(int32_t res, const SBuffer &buf, boolean lqi) { #ifdef USE_ZIGBEE_ZNP uint16_t shortaddr = buf.get16(2); uint8_t status = buf.get8(4); @@ -1202,7 +1202,7 @@ int32_t Z_Mgmt_Lqi_Bind_Rsp(int32_t res, const class SBuffer &buf, boolean lqi) // // Handle MgMt Bind Rsp incoming message // -int32_t Z_MgmtLqiRsp(int32_t res, const class SBuffer &buf) { +int32_t Z_MgmtLqiRsp(int32_t res, const SBuffer &buf) { return Z_Mgmt_Lqi_Bind_Rsp(res, buf, true); } @@ -1211,7 +1211,7 @@ int32_t Z_MgmtLqiRsp(int32_t res, const class SBuffer &buf) { // Handle Parent Annonce Rsp incoming message // // rsp: true = ZDO_Parent_annce_rsp, false = ZDO_Parent_annce -int32_t EZ_ParentAnnceRsp(int32_t res, const class SBuffer &buf, bool rsp) { +int32_t EZ_ParentAnnceRsp(int32_t res, const SBuffer &buf, bool rsp) { size_t prefix_len; uint8_t status; uint8_t num_children; @@ -1570,7 +1570,7 @@ void Z_AutoConfigReportingForCluster(uint16_t shortaddr, uint16_t groupaddr, uin // 2400 // #ifdef USE_ZIGBEE_EZSP -int32_t EZ_ReceiveTCJoinHandler(int32_t res, const class SBuffer &buf) { +int32_t EZ_ReceiveTCJoinHandler(int32_t res, const SBuffer &buf) { uint16_t srcAddr = buf.get16(2); uint64_t ieeeAddr = buf.get64(4); uint8_t status = buf.get8(12); @@ -1743,7 +1743,7 @@ void EZ_SendZDO(uint16_t shortaddr, uint16_t cmd, const unsigned char *payload, * Send specific EZSP messages \*********************************************************************************************/ -int32_t EZ_IncomingMessage(int32_t res, const class SBuffer &buf) { +int32_t EZ_IncomingMessage(int32_t res, const SBuffer &buf) { uint8_t msgtype = buf.get8(2); // see EZSP_EmberIncomingMessageType bool wasbroadcast = (msgtype >= EMBER_INCOMING_MULTICAST) && (msgtype <= EMBER_INCOMING_BROADCAST_LOOPBACK); uint16_t profileid = buf.get16(3); // HA = 0x0104, ZDO = 0x0000 @@ -1837,7 +1837,7 @@ int32_t EZ_Reset_Device(uint8_t value) { * Default resolver \*********************************************************************************************/ -int32_t EZ_Recv_Default(int32_t res, const class SBuffer &buf) { +int32_t EZ_Recv_Default(int32_t res, const SBuffer &buf) { // Default message handler for new messages if (zigbee.init_phase) { // if still during initialization phase, ignore any unexpected message @@ -1907,7 +1907,7 @@ int32_t ZNP_Reset_Device(uint8_t value) { return 0; // continue } -int32_t ZNP_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) { +int32_t ZNP_ReceiveAfIncomingMessage(int32_t res, const SBuffer &buf) { uint16_t groupid = buf.get16(2); uint16_t clusterid = buf.get16(4); uint16_t srcaddr = buf.get16(6); @@ -1968,7 +1968,7 @@ const Z_Dispatcher Z_DispatchTable[] PROGMEM = { * Default resolver \*********************************************************************************************/ -int32_t ZNP_Recv_Default(int32_t res, const class SBuffer &buf) { +int32_t ZNP_Recv_Default(int32_t res, const SBuffer &buf) { // Default message handler for new messages if (zigbee.init_phase) { // if still during initialization phase, ignore any unexpected message diff --git a/tasmota/xdrv_23_zigbee_9_serial.ino b/tasmota/xdrv_23_zigbee_9_serial.ino index 19592de94..ccd8d2da9 100644 --- a/tasmota/xdrv_23_zigbee_9_serial.ino +++ b/tasmota/xdrv_23_zigbee_9_serial.ino @@ -134,25 +134,21 @@ void ZigbeeInputLoop(void) { } if (zigbee_buffer->len() && (millis() > (zigbee_polling_window + ZIGBEE_POLLING))) { - char hex_char[(zigbee_buffer->len() * 2) + 2]; - ToHex_P((unsigned char*)zigbee_buffer->getBuffer(), zigbee_buffer->len(), hex_char, sizeof(hex_char)); - // AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "Bytes follow_read_metric = %0d"), ZigbeeSerial->getLoopReadMetric()); // buffer received, now check integrity if (zigbee_buffer->len() != zigbee_frame_len) { // Len is not correct, log and reject frame - AddLog_P(LOG_LEVEL_INFO, PSTR(D_JSON_ZIGBEEZNPRECEIVED ": received frame of wrong size %s, len %d, expected %d"), hex_char, zigbee_buffer->len(), zigbee_frame_len); + AddLog_P(LOG_LEVEL_INFO, PSTR(D_JSON_ZIGBEEZNPRECEIVED ": received frame of wrong size %_B, len %d, expected %d"), &zigbee_buffer, zigbee_buffer->len(), zigbee_frame_len); } else if (0x00 != fcs) { // FCS is wrong, packet is corrupt, log and reject frame - AddLog_P(LOG_LEVEL_INFO, PSTR(D_JSON_ZIGBEEZNPRECEIVED ": received bad FCS frame %s, %d"), hex_char, fcs); + AddLog_P(LOG_LEVEL_INFO, PSTR(D_JSON_ZIGBEEZNPRECEIVED ": received bad FCS frame %_B, %d"), &zigbee_buffer, fcs); } else { // frame is correct //AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR(D_JSON_ZIGBEEZNPRECEIVED ": received correct frame %s"), hex_char); SBuffer znp_buffer = zigbee_buffer->subBuffer(2, zigbee_frame_len - 3); // remove SOF, LEN and FCS - ToHex_P((unsigned char*)znp_buffer.getBuffer(), znp_buffer.len(), hex_char, sizeof(hex_char)); - Response_P(PSTR("{\"" D_JSON_ZIGBEEZNPRECEIVED "\":\"%s\"}"), hex_char); + Response_P(PSTR("{\"" D_JSON_ZIGBEEZNPRECEIVED "\":\"%_B\"}"), &znp_buffer); if (Settings.flag3.tuya_serial_mqtt_publish) { MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_SENSOR)); } else { @@ -552,7 +548,7 @@ void ZigbeeEZSPSendDATA(const uint8_t *msg, size_t len) { } // Receive a high-level EZSP command/response, starting with 16-bits frame ID -void ZigbeeProcessInputEZSP(class SBuffer &buf) { +void ZigbeeProcessInputEZSP(SBuffer &buf) { // verify errors in first 2 bytes. // TODO // uint8_t sequence_num = buf.get8(0); @@ -632,7 +628,7 @@ void EZSP_HandleAck(uint8_t new_ack) { } // Receive raw ASH frame (CRC was removed, data unstuffed) but still contains frame numbers -void ZigbeeProcessInputRaw(class SBuffer &buf) { +void ZigbeeProcessInputRaw(SBuffer &buf) { uint8_t control_byte = buf.get8(0); uint8_t ack_num = control_byte & 0x07; // keep 3 LSB if (control_byte & 0x80) { // non DATA frame