Merge branch 'development' into neopool-dev

This commit is contained in:
Norbert Richter 2021-01-25 17:25:43 +01:00
commit 48a5acbc5d
No known key found for this signature in database
GPG Key ID: 6628701A626FA674
17 changed files with 205 additions and 116 deletions

View File

@ -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; i<len; i++) {
if (buf1->get8(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; i<len; i++) {
if (buf1->get8(i) != buf2->get8(i)) { return false; }
}
return true;
}

View File

@ -20,6 +20,7 @@
#include "ext_printf.h"
#include <Arduino.h>
#include <IPAddress.h>
#include <SBuffer.hpp>
/*********************************************************************************************\
* 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,42 @@ 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);
snprintf_P(ip_str, 16, PSTR("%u.%u.%u.%u"), cur_val & 0xFF, (cur_val >> 8) & 0xFF, (cur_val >> 16) & 0xFF, (cur_val >> 24) & 0xFF);
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 +283,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
@ -271,20 +335,22 @@ int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list
va_arg(va, int32_t); // munch one 32 bits argument and leave it unchanged
// we take the hypothesis here that passing 64 bits arguments is always unsupported in ESP8266
}
fmt++;
}
}
#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;
}

View File

@ -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

View File

@ -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);

View File

@ -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)

View File

@ -53,6 +53,7 @@
#include <ESP8266httpUpdate.h> // Ota
#include <StreamString.h> // Webserver, Updater
#include <ext_printf.h>
#include <SBuffer.hpp>
#include <JsonParser.h>
#include <JsonGenerator.h>
#ifdef USE_ARDUINO_OTA

View File

@ -484,6 +484,8 @@ void StartWebserver(int type, IPAddress ipweb)
#else
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"),
NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", ipweb.toString().c_str());
// AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %_I"),
// NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", (uint32_t)ipweb);
#endif // LWIP_IPV6 = 1
TasmotaGlobal.rules_flag.http_init = 1;
}
@ -1587,12 +1589,12 @@ void ModuleSaveSettings(void)
} else {
if (ValidGPIO(i, template_gp.io[i])) {
Settings.my_gp.io[i] = WebGetGpioArg(i);
gpios += F(", "); gpios += String(i); gpios += F(" "); gpios += String(Settings.my_gp.io[i]);
gpios += F(", IO"); gpios += String(i); gpios += F(" "); gpios += String(Settings.my_gp.io[i]);
}
}
}
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_MODULE "%s " D_CMND_MODULE "%s"), ModuleName().c_str(), gpios.c_str());
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MODULE "%s " D_CMND_MODULE "%s"), ModuleName().c_str(), gpios.c_str());
}
/*-------------------------------------------------------------------------------------------*/

View File

@ -397,6 +397,25 @@ void DomoticzSensor(uint8_t idx, uint32_t value) {
DomoticzSensor(idx, data);
}
void DomoticzFloatSensor(uint8_t idx, float value) {
uint32_t resolution = 1;
/*
switch (idx) {
case DZ_TEMP: resolution = Settings.flag2.temperature_resolution; break;
case DZ_POWER_ENERGY: resolution = Settings.flag2.wattage_resolution; break;
case DZ_VOLTAGE: resolution = Settings.flag2.voltage_resolution; break;
case DZ_CURRENT: resolution = Settings.flag2.current_resolution; break;
}
*/
if (DZ_TEMP == idx) { resolution = Settings.flag2.temperature_resolution; }
else if (DZ_POWER_ENERGY == idx) { resolution = Settings.flag2.wattage_resolution; }
else if (DZ_VOLTAGE == idx) { resolution = Settings.flag2.voltage_resolution; }
else if (DZ_CURRENT == idx) { resolution = Settings.flag2.current_resolution; }
char data[FLOATSZ];
dtostrfd(value, resolution, data);
DomoticzSensor(idx, data);
}
//void DomoticzTempHumPressureSensor(float temp, float hum, float baro = -1);
void DomoticzTempHumPressureSensor(float temp, float hum, float baro) {
char temperature[FLOATSZ];

View File

@ -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);

View File

@ -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; }

View File

@ -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();

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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()'

View File

@ -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

View File

@ -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