mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-24 11:16:34 +00:00
Merge branch 'arendst:development' into S3_Homekit
This commit is contained in:
commit
574be6b7f0
@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file.
|
||||
## [Unreleased] - Development
|
||||
## [11.0.0.1]
|
||||
### Added
|
||||
- Command ``SspmMap 0`` to reset Sonoff SPM default mapping
|
||||
- Command ``TcpConnect <port><ip_address>`` to add client connection mode (#14874)
|
||||
- ESP32 support for BLE Mi scale V1 (#13517)
|
||||
- ESP32 integrate Homekit in Bluetooth binary (#14818)
|
||||
- ESP32 Berry always enable rules
|
||||
@ -21,6 +23,7 @@ All notable changes to this project will be documented in this file.
|
||||
- GPIO OptionE1 selection regression (#14821)
|
||||
- BL0939, BL0940 and BL0942 energy monitoring buffer miscompares resulting in wrong daily energy values regression from v9.5.0.8 (#14829)
|
||||
- Orno WE517 power meter phase 2 current reactive (#14841)
|
||||
- Wiegand 34-bit rfid reading and presentation (#14834)
|
||||
|
||||
## [Released]
|
||||
|
||||
|
@ -105,6 +105,8 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo
|
||||
|
||||
## Changelog v11.0.0.1
|
||||
### Added
|
||||
- Command ``SspmMap 0`` to reset Sonoff SPM default mapping
|
||||
- Command ``TcpConnect <port><ip_address>`` to add client connection mode [#14874](https://github.com/arendst/Tasmota/issues/14874)
|
||||
- ESP32 Berry always enable rules
|
||||
- ESP32 Berry bootloop protection
|
||||
- ESP32 support for BLE Mi scale V1 [#13517](https://github.com/arendst/Tasmota/issues/13517)
|
||||
@ -123,6 +125,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo
|
||||
- SSPM energy yesterday when zero
|
||||
- GPIO OptionE1 selection regression [#14821](https://github.com/arendst/Tasmota/issues/14821)
|
||||
- BL0939, BL0940 and BL0942 energy monitoring buffer miscompares resulting in wrong daily energy values regression from v9.5.0.8 [#14829](https://github.com/arendst/Tasmota/issues/14829)
|
||||
- Wiegand 34-bit rfid reading and presentation [#14834](https://github.com/arendst/Tasmota/issues/14834)
|
||||
- Orno WE517 power meter phase 2 current reactive [#14841](https://github.com/arendst/Tasmota/issues/14841)
|
||||
|
||||
### Removed
|
||||
|
@ -210,14 +210,14 @@ void directModeInput(IO_REG_TYPE pin)
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
|
||||
}
|
||||
#elif ESP_IDF_VERSION_MAJOR > 3 // ESP32-S2 needs IDF 4.2 or later
|
||||
int8_t rtc_io = esp32_gpioMux[pin].rtc;
|
||||
uint32_t rtc_reg = (rtc_io != -1)?rtc_io_desc[rtc_io].reg:0;
|
||||
if ( rtc_reg ) // RTC pins PULL settings
|
||||
{
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].mux);
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].pullup | rtc_io_desc[rtc_io].pulldown);
|
||||
}
|
||||
//#elif ESP_IDF_VERSION_MAJOR > 3 // ESP32-S2 needs IDF 4.2 or later
|
||||
// int8_t rtc_io = esp32_gpioMux[pin].rtc;
|
||||
// uint32_t rtc_reg = (rtc_io != -1)?rtc_io_desc[rtc_io].reg:0;
|
||||
// if ( rtc_reg ) // RTC pins PULL settings
|
||||
// {
|
||||
// ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].mux);
|
||||
// ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].pullup | rtc_io_desc[rtc_io].pulldown);
|
||||
// }
|
||||
#endif
|
||||
// Input
|
||||
if ( pin < 32 )
|
||||
@ -225,13 +225,13 @@ void directModeInput(IO_REG_TYPE pin)
|
||||
else
|
||||
GPIO.enable1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
||||
|
||||
uint32_t pinFunction((uint32_t)2 << FUN_DRV_S); // what are the drivers?
|
||||
pinFunction |= FUN_IE; // input enable but required for output as well?
|
||||
pinFunction |= ((uint32_t)PIN_FUNC_GPIO << MCU_SEL_S);
|
||||
// uint32_t pinFunction((uint32_t)2 << FUN_DRV_S); // what are the drivers?
|
||||
// pinFunction |= FUN_IE; // input enable but required for output as well?
|
||||
// pinFunction |= ((uint32_t)PIN_FUNC_GPIO << MCU_SEL_S);
|
||||
|
||||
ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = pinFunction;
|
||||
// ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = pinFunction;
|
||||
|
||||
GPIO.pin[pin].val = 0;
|
||||
// GPIO.pin[pin].val = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -252,14 +252,14 @@ void directModeOutput(IO_REG_TYPE pin)
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
|
||||
}
|
||||
#elif ESP_IDF_VERSION_MAJOR > 3 // ESP32-S2 needs IDF 4.2 or later
|
||||
int8_t rtc_io = esp32_gpioMux[pin].rtc;
|
||||
uint32_t rtc_reg = (rtc_io != -1)?rtc_io_desc[rtc_io].reg:0;
|
||||
if ( rtc_reg ) // RTC pins PULL settings
|
||||
{
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].mux);
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].pullup | rtc_io_desc[rtc_io].pulldown);
|
||||
}
|
||||
//#elif ESP_IDF_VERSION_MAJOR > 3 // ESP32-S2 needs IDF 4.2 or later
|
||||
// int8_t rtc_io = esp32_gpioMux[pin].rtc;
|
||||
// uint32_t rtc_reg = (rtc_io != -1)?rtc_io_desc[rtc_io].reg:0;
|
||||
// if ( rtc_reg ) // RTC pins PULL settings
|
||||
// {
|
||||
// ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].mux);
|
||||
// ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].pullup | rtc_io_desc[rtc_io].pulldown);
|
||||
// }
|
||||
#endif
|
||||
// Output
|
||||
if ( pin < 32 )
|
||||
@ -267,13 +267,13 @@ void directModeOutput(IO_REG_TYPE pin)
|
||||
else // already validated to pins <= 33
|
||||
GPIO.enable1_w1ts.val = ((uint32_t)1 << (pin - 32));
|
||||
|
||||
uint32_t pinFunction((uint32_t)2 << FUN_DRV_S); // what are the drivers?
|
||||
pinFunction |= FUN_IE; // input enable but required for output as well?
|
||||
pinFunction |= ((uint32_t)PIN_FUNC_GPIO << MCU_SEL_S);
|
||||
// uint32_t pinFunction((uint32_t)2 << FUN_DRV_S); // what are the drivers?
|
||||
// pinFunction |= FUN_IE; // input enable but required for output as well?
|
||||
// pinFunction |= ((uint32_t)PIN_FUNC_GPIO << MCU_SEL_S);
|
||||
|
||||
ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = pinFunction;
|
||||
// ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = pinFunction;
|
||||
|
||||
GPIO.pin[pin].val = 0;
|
||||
// GPIO.pin[pin].val = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ be_extern_native_module(cb);
|
||||
/* Tasmota specific */
|
||||
be_extern_native_module(python_compat);
|
||||
be_extern_native_module(re);
|
||||
be_extern_native_module(mqtt);
|
||||
be_extern_native_module(persist);
|
||||
be_extern_native_module(autoconf);
|
||||
be_extern_native_module(tapp);
|
||||
@ -108,6 +109,7 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = {
|
||||
&be_native_module(python_compat),
|
||||
&be_native_module(re),
|
||||
&be_native_module(path),
|
||||
&be_native_module(mqtt),
|
||||
&be_native_module(persist),
|
||||
#ifdef USE_AUTOCONF
|
||||
&be_native_module(autoconf),
|
||||
@ -157,7 +159,7 @@ extern void be_load_wirelib(bvm *vm);
|
||||
extern void be_load_onewirelib(bvm *vm);
|
||||
extern void be_load_serial_lib(bvm *vm);
|
||||
extern void be_load_Driver_class(bvm *vm);
|
||||
extern void be_load_Timer_class(bvm *vm);
|
||||
extern void be_load_Trigger_class(bvm *vm);
|
||||
extern void be_load_I2C_Driver_class(bvm *vm);
|
||||
extern void be_load_AXP192_class(bvm *vm);
|
||||
extern void be_load_md5_lib(bvm *vm);
|
||||
@ -198,7 +200,7 @@ BERRY_API void be_load_custom_libs(bvm *vm)
|
||||
#if !BE_USE_PRECOMPILED_OBJECT
|
||||
/* be_load_xxxlib(vm); */
|
||||
#endif
|
||||
be_load_Timer_class(vm);
|
||||
be_load_Trigger_class(vm);
|
||||
be_load_tasmota_ntvlib(vm);
|
||||
be_load_tasmota_log_reader_class(vm);
|
||||
be_load_Driver_class(vm);
|
||||
|
@ -175,6 +175,14 @@
|
||||
**/
|
||||
#define BE_USE_DEBUG_GC 0
|
||||
|
||||
/* Macro: BE_USE_MEM_ALIGNED
|
||||
* Some embedded processors have special memory areas
|
||||
* with read/write constraints of being aligned to 32 bits boundaries.
|
||||
* This options tries to move such memory areas to this region.
|
||||
* Default: 0
|
||||
**/
|
||||
#define BE_USE_MEM_ALIGNED 1
|
||||
|
||||
/* Macro: BE_USE_XXX_MODULE
|
||||
* These macros control whether the related module is compiled.
|
||||
* When they are true, they will enable related modules. At this
|
||||
@ -215,8 +223,6 @@ extern "C" {
|
||||
extern void berry_free(void *ptr);
|
||||
extern void *berry_realloc(void *ptr, size_t size);
|
||||
extern void *berry_malloc32(size_t size);
|
||||
extern void berry_free32(void *ptr);
|
||||
extern void *berry_realloc32(void *ptr, size_t size);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -100,7 +100,7 @@ extern const bcstring be_const_str_STATE_DEFAULT;
|
||||
extern const bcstring be_const_str_TAP_X3A_X20Loaded_X20Tasmota_X20App_X20_X27_X25s_X27;
|
||||
extern const bcstring be_const_str_Tasmota;
|
||||
extern const bcstring be_const_str_Tele;
|
||||
extern const bcstring be_const_str_Timer;
|
||||
extern const bcstring be_const_str_Trigger;
|
||||
extern const bcstring be_const_str_True;
|
||||
extern const bcstring be_const_str_Unknown;
|
||||
extern const bcstring be_const_str_Unknown_X20command;
|
||||
@ -526,6 +526,7 @@ extern const bcstring be_const_str_length_X20in_X20bits_X20must_X20be_X20between
|
||||
extern const bcstring be_const_str_light;
|
||||
extern const bcstring be_const_str_light_X20must_X20be_X20of_X20class_X20_X27light_state_X27;
|
||||
extern const bcstring be_const_str_light_state;
|
||||
extern const bcstring be_const_str_light_to_id;
|
||||
extern const bcstring be_const_str_lights;
|
||||
extern const bcstring be_const_str_line_dsc;
|
||||
extern const bcstring be_const_str_list;
|
||||
@ -759,6 +760,7 @@ extern const bcstring be_const_str_strftime;
|
||||
extern const bcstring be_const_str_string;
|
||||
extern const bcstring be_const_str_strip;
|
||||
extern const bcstring be_const_str_strptime;
|
||||
extern const bcstring be_const_str_subscribe;
|
||||
extern const bcstring be_const_str_success;
|
||||
extern const bcstring be_const_str_super;
|
||||
extern const bcstring be_const_str_sys;
|
||||
@ -788,6 +790,7 @@ extern const bcstring be_const_str_touch_update;
|
||||
extern const bcstring be_const_str_toupper;
|
||||
extern const bcstring be_const_str_tr;
|
||||
extern const bcstring be_const_str_traceback;
|
||||
extern const bcstring be_const_str_trig;
|
||||
extern const bcstring be_const_str_true;
|
||||
extern const bcstring be_const_str_try;
|
||||
extern const bcstring be_const_str_try_rule;
|
||||
@ -795,6 +798,7 @@ extern const bcstring be_const_str_type;
|
||||
extern const bcstring be_const_str_type_error;
|
||||
extern const bcstring be_const_str_udp;
|
||||
extern const bcstring be_const_str_unknown_X20instruction;
|
||||
extern const bcstring be_const_str_unsubscribe;
|
||||
extern const bcstring be_const_str_update;
|
||||
extern const bcstring be_const_str_upper;
|
||||
extern const bcstring be_const_str_url_encode;
|
||||
|
File diff suppressed because it is too large
Load Diff
19
lib/libesp32/berry/generate/be_fixed_mqtt.h
Normal file
19
lib/libesp32/berry/generate/be_fixed_mqtt.h
Normal file
@ -0,0 +1,19 @@
|
||||
#include "be_constobj.h"
|
||||
|
||||
static be_define_const_map_slots(m_libmqtt_map) {
|
||||
{ be_const_key(unsubscribe, -1), be_const_ctype_func(be_mqtt_unsubscribe) },
|
||||
{ be_const_key(subscribe, -1), be_const_ctype_func(be_mqtt_subscribe) },
|
||||
{ be_const_key(publish, 1), be_const_func(be_mqtt_publish) },
|
||||
};
|
||||
|
||||
static be_define_const_map(
|
||||
m_libmqtt_map,
|
||||
3
|
||||
);
|
||||
|
||||
static be_define_const_module(
|
||||
m_libmqtt,
|
||||
"mqtt"
|
||||
);
|
||||
|
||||
BE_EXPORT_VARIABLE be_define_const_native_module(mqtt);
|
@ -40,6 +40,7 @@ void be_gc_init(bvm *vm)
|
||||
{
|
||||
vm->gc.usage = sizeof(bvm);
|
||||
be_gc_setsteprate(vm, 200);
|
||||
be_gc_init_memory_pools(vm);
|
||||
}
|
||||
|
||||
void be_gc_deleteall(bvm *vm)
|
||||
@ -543,6 +544,8 @@ void be_gc_collect(bvm *vm)
|
||||
return; /* the GC cannot run for some reason */
|
||||
}
|
||||
#if BE_USE_PERF_COUNTERS
|
||||
size_t slors_used_before_gc, slots_allocated_before_gc;
|
||||
be_gc_memory_pools_info(vm, &slors_used_before_gc, &slots_allocated_before_gc);
|
||||
vm->counter_gc_kept = 0;
|
||||
vm->counter_gc_freed = 0;
|
||||
#endif
|
||||
@ -563,8 +566,13 @@ void be_gc_collect(bvm *vm)
|
||||
reset_fixedlist(vm);
|
||||
/* step 5: calculate the next GC threshold */
|
||||
vm->gc.threshold = next_threshold(vm->gc);
|
||||
be_gc_memory_pools(vm); /* free unsued memory pools */
|
||||
#if BE_USE_PERF_COUNTERS
|
||||
if (vm->obshook != NULL) (*vm->obshook)(vm, BE_OBS_GC_END, vm->gc.usage, vm->counter_gc_kept, vm->counter_gc_freed);
|
||||
size_t slors_used_after_gc, slots_allocated_after_gc;
|
||||
be_gc_memory_pools_info(vm, &slors_used_after_gc, &slots_allocated_after_gc);
|
||||
if (vm->obshook != NULL) (*vm->obshook)(vm, BE_OBS_GC_END, vm->gc.usage, vm->counter_gc_kept, vm->counter_gc_freed,
|
||||
slors_used_before_gc, slots_allocated_before_gc,
|
||||
slors_used_after_gc, slots_allocated_after_gc);
|
||||
#else
|
||||
if (vm->obshook != NULL) (*vm->obshook)(vm, BE_OBS_GC_END, vm->gc.usage);
|
||||
#endif
|
||||
|
@ -26,6 +26,12 @@
|
||||
#define realloc BE_EXPLICIT_REALLOC
|
||||
#endif
|
||||
|
||||
static void* malloc_from_pool(bvm *vm, size_t size);
|
||||
static void free_from_pool(bvm *vm, void* ptr, size_t old_size);
|
||||
|
||||
#define POOL16_SIZE 16
|
||||
#define POOL32_SIZE 32
|
||||
|
||||
BERRY_API void* be_os_malloc(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
@ -41,39 +47,310 @@ BERRY_API void* be_os_realloc(void *ptr, size_t size)
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
static void* _realloc(void *ptr, size_t old_size, size_t new_size)
|
||||
{
|
||||
if (old_size == new_size) { /* the block unchanged */
|
||||
return ptr;
|
||||
}
|
||||
if (ptr && new_size) { /* realloc block */
|
||||
return realloc(ptr, new_size);
|
||||
}
|
||||
if (new_size) { /* alloc a new block */
|
||||
be_assert(ptr == NULL && old_size == 0);
|
||||
return malloc(new_size);
|
||||
}
|
||||
be_assert(new_size == 0);
|
||||
|
||||
#if BE_USE_DEBUG_GC
|
||||
memset(ptr, 0xFF, old_size); /* fill the structure with invalid pointers */
|
||||
#endif
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BERRY_API void* be_realloc(bvm *vm, void *ptr, size_t old_size, size_t new_size)
|
||||
{
|
||||
void *block = _realloc(ptr, old_size, new_size);
|
||||
if (!block && new_size) { /* allocation failure */
|
||||
void *block = NULL;
|
||||
// serial_debug("be_realloc ptr=%p old_size=%i new_size=%i\n", ptr, old_size, new_size);
|
||||
|
||||
bbool gc_occured = bfalse; /* if allocation failed, retry after forced GC */
|
||||
if (old_size == new_size) { /* the block unchanged, this also captures creation of a zero byte object */
|
||||
return ptr;
|
||||
}
|
||||
/* from now on, block == NULL means allocation failure */
|
||||
|
||||
while (1) {
|
||||
/* Case 1: new allocation */
|
||||
if (!ptr || (old_size == 0)) {
|
||||
block = malloc_from_pool(vm, new_size);
|
||||
}
|
||||
|
||||
/* Case 2: deallocate */
|
||||
else if (new_size == 0) {
|
||||
#if BE_USE_DEBUG_GC
|
||||
memset(ptr, 0xFF, old_size); /* fill the structure with invalid pointers */
|
||||
#endif
|
||||
free_from_pool(vm, ptr, old_size);
|
||||
break; /* early exit */
|
||||
}
|
||||
|
||||
/* Case 3: reallocate with a different size */
|
||||
else if (new_size && old_size) { // TODO we already know they are not null TODO
|
||||
if (new_size <= POOL32_SIZE || old_size <=POOL32_SIZE) {
|
||||
/* complex case with different pools */
|
||||
if (new_size <= POOL16_SIZE && old_size <= POOL16_SIZE) {
|
||||
// no change of slot
|
||||
block = ptr;
|
||||
break;
|
||||
} else if (new_size > POOL16_SIZE && old_size > POOL16_SIZE && new_size <= POOL32_SIZE && old_size <= POOL32_SIZE) {
|
||||
// no change of slot
|
||||
block = ptr;
|
||||
break;
|
||||
} else {
|
||||
/* one of the buffer is out of pool, the other not */
|
||||
block = malloc_from_pool(vm, new_size);
|
||||
if (block) {
|
||||
/* copy memory */
|
||||
size_t min_size = old_size < new_size ? old_size : new_size;
|
||||
memmove(block, ptr, min_size);
|
||||
// serial_debug("memmove from %p to %p size=%i\n", ptr, block, min_size);
|
||||
free_from_pool(vm, ptr, old_size);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
block = realloc(ptr, new_size);
|
||||
// serial_debug("realloc from %p to %p size=%i", ptr, block, new_size);
|
||||
}
|
||||
} /* end of reallocation */
|
||||
|
||||
/* exit allocator, do we need to GC ? */
|
||||
if (block) { break; } /* all good */
|
||||
if (gc_occured) { /* already tried gc, can't do much anymore */
|
||||
be_throw(vm, BE_MALLOC_FAIL); /* lack of heap space */
|
||||
}
|
||||
// serial_debug("be_realloc force_gc\n");
|
||||
/* force GC now */
|
||||
vm->gc.status |= GC_ALLOC;
|
||||
be_gc_collect(vm); /* try to allocate again after GC */
|
||||
vm->gc.status &= ~GC_ALLOC;
|
||||
block = _realloc(ptr, old_size, new_size);
|
||||
if (!block) { /* lack of heap space */
|
||||
be_throw(vm, BE_MALLOC_FAIL);
|
||||
}
|
||||
gc_occured = btrue; /* don't try again GC */
|
||||
}
|
||||
vm->gc.usage = vm->gc.usage + new_size - old_size; /* update allocated count */
|
||||
|
||||
// serial_debug("be_realloc ret=%p\n", block);
|
||||
return block;
|
||||
}
|
||||
|
||||
BERRY_API void* be_move_to_aligned(bvm *vm, void *ptr, size_t size) {
|
||||
#if BE_USE_MEM_ALIGNED
|
||||
if (size <= POOL32_SIZE) {
|
||||
return ptr; /* if in memory pool, don't move it so be_free() will continue to work */
|
||||
}
|
||||
void* iram = berry_malloc32(size);
|
||||
if (iram) {
|
||||
memcpy(iram, ptr, size); /* new_size is always smaller than initial mem zone */
|
||||
free(ptr); // TODO gc size is now wrong
|
||||
return iram;
|
||||
}
|
||||
#endif
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Special allocator for structures under 32 bytes */
|
||||
typedef uint8_t mem16[16]; /* memory line of 16 bytes */
|
||||
typedef uint8_t mem32[32]; /* memory line of 32 bytes */
|
||||
#define POOL16_SLOTS 31
|
||||
#define POOL16_BITMAP_FULL ((1UL<<POOL16_SLOTS)-1) /* 31 bits set to 1 - 0x7FFFFFFF */
|
||||
#define POOL32_SLOTS 15
|
||||
#define POOL32_BITMAP_FULL ((1UL<<POOL32_SLOTS)-1) /* 15 bits set to 1 - 0x7FFF*/
|
||||
|
||||
typedef struct gc16_t {
|
||||
uint32_t bitmap; /* bitmap or allocated lines, 0 is free */
|
||||
struct gc16_t* next;
|
||||
mem16 lines[POOL16_SLOTS];
|
||||
} gc16_t;
|
||||
|
||||
typedef struct gc32_t {
|
||||
uint32_t bitmap; /* bitmap or allocated lines, 0 is free */
|
||||
struct gc32_t* next;
|
||||
mem32 lines[POOL32_SLOTS];
|
||||
} gc32_t;
|
||||
|
||||
static void* malloc_from_pool(bvm *vm, size_t size) {
|
||||
if (size == 0) return NULL;
|
||||
if (size <= POOL16_SIZE) {
|
||||
/* allocate in pool 16 */
|
||||
gc16_t* pool16 = vm->gc.pool16;
|
||||
while (pool16) {
|
||||
/* look for an empty slot */
|
||||
if (pool16->bitmap != 0x0000) {
|
||||
/* there is a free slot */
|
||||
#ifdef __GNUC__
|
||||
int bit = __builtin_ffs(pool16->bitmap) - 1;
|
||||
#else
|
||||
int bit = ffs(pool16->bitmap) - 1;
|
||||
#endif
|
||||
if (bit >= 0) {
|
||||
/* we found a free slot */
|
||||
// bitClear(pool16->bitmap, bit);
|
||||
pool16->bitmap &= ~(1UL << bit);
|
||||
// serial_debug("malloc_from_pool found slot in pool %p, bit %i, ptr=%p\n", pool16, bit, &pool16->lines[bit]);
|
||||
return &pool16->lines[bit];
|
||||
}
|
||||
}
|
||||
pool16 = pool16->next;
|
||||
}
|
||||
/* no slot available, we allocate a new pool */
|
||||
pool16 = (gc16_t*) malloc(sizeof(gc16_t));
|
||||
if (!pool16) { return NULL; } /* out of memory */
|
||||
pool16->next = vm->gc.pool16;
|
||||
pool16->bitmap = POOL16_BITMAP_FULL - 1; /* allocate first line */
|
||||
vm->gc.pool16 = pool16; /* insert at head of linked list */
|
||||
// serial_debug("malloc_from_pool allocated new pool %p, size=%i p=%p\n", pool16, sizeof(gc16_t), &pool16->lines[0]);
|
||||
return &pool16->lines[0];
|
||||
}
|
||||
|
||||
if (size <= POOL32_SIZE) {
|
||||
/* allocate in pool 32 */
|
||||
gc32_t* pool32 = vm->gc.pool32;
|
||||
while (pool32) {
|
||||
/* look for an empty slot */
|
||||
if (pool32->bitmap != 0x0000) {
|
||||
/* there is a free slot */
|
||||
#ifdef __GNUC__
|
||||
int bit = __builtin_ffs(pool32->bitmap) - 1;
|
||||
#else
|
||||
int bit = ffs(pool32->bitmap) - 1;
|
||||
#endif
|
||||
if (bit >= 0) {
|
||||
/* we found a free slot */
|
||||
// bitClear(pool32->bitmap, bit);
|
||||
pool32->bitmap &= ~(1UL << bit);
|
||||
// serial_debug("malloc_from_pool found slot in pool %p, bit %i, ptr=%p\n", pool32, bit, &pool32->lines[bit]);
|
||||
return &pool32->lines[bit];
|
||||
}
|
||||
}
|
||||
pool32 = pool32->next;
|
||||
}
|
||||
/* no slot available, we allocate a new pool */
|
||||
pool32 = (gc32_t*) malloc(sizeof(gc32_t));
|
||||
if (!pool32) { return NULL; } /* out of memory */
|
||||
pool32->next = vm->gc.pool32;
|
||||
pool32->bitmap = POOL32_BITMAP_FULL - 1; /* allocate first line */
|
||||
vm->gc.pool32 = pool32; /* insert at head of linked list */
|
||||
// serial_debug("malloc_from_pool allocated new pool %p, size=%i p=%p\n", pool32, sizeof(gc32_t), &pool32->lines[0]);
|
||||
return &pool32->lines[0];
|
||||
}
|
||||
|
||||
return malloc(size); /* default to system malloc */
|
||||
}
|
||||
|
||||
static void free_from_pool(bvm *vm, void* ptr, size_t old_size) {
|
||||
if (old_size <= POOL16_SIZE) {
|
||||
gc16_t* pool16 = vm->gc.pool16;
|
||||
while (pool16) {
|
||||
int32_t offset = (uint8_t*)ptr - (uint8_t*) &pool16->lines[0];
|
||||
// serial_debug("free_from_pool ptr=%p pool=%p offset=%i\n", ptr,pool16, offset);
|
||||
if ((offset >= 0) && (offset < POOL16_SLOTS*16) && ((offset & 0x0F) == 0)) {
|
||||
int bit = offset >> 4;
|
||||
// serial_debug("free_from_pool ptr=%p fond pool=%p bit=%i\n", ptr, pool16, bit);
|
||||
// bitSet(pool16->bitmap, bit);
|
||||
pool16->bitmap |= 1UL << bit;
|
||||
return;
|
||||
}
|
||||
pool16 = pool16->next;
|
||||
}
|
||||
}
|
||||
else if (old_size <= POOL32_SIZE) {
|
||||
gc32_t* pool32 = vm->gc.pool32;
|
||||
while (pool32) {
|
||||
int32_t offset = (uint8_t*)ptr - (uint8_t*) &pool32->lines[0];
|
||||
// serial_debug("free_from_pool pool=%p offset=%i\n", pool32, offset);
|
||||
if ((offset >= 0) && (offset < POOL16_SLOTS*16) && ((offset & 0x1F) == 0)) {
|
||||
int bit = offset >> 5;
|
||||
// serial_debug("free_from_pool ptr=%p fond pool=%p bit=%i\n", ptr, pool32, bit);
|
||||
// bitSet(pool32->bitmap, bit);
|
||||
pool32->bitmap |= 1UL << bit;
|
||||
return;
|
||||
}
|
||||
pool32 = pool32->next;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// serial_debug("free_from_pool free=%p\n", ptr);
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
BERRY_API void be_gc_memory_pools(bvm *vm) {
|
||||
gc16_t** prev16 = &vm->gc.pool16;
|
||||
gc16_t* pool16 = vm->gc.pool16;
|
||||
while (pool16) {
|
||||
if (pool16->bitmap == POOL16_BITMAP_FULL) {
|
||||
/* pool is empty, we can free it */
|
||||
*prev16 = pool16->next;
|
||||
gc16_t* pool_to_freed = pool16;
|
||||
pool16 = pool16->next; /* move to next */
|
||||
free(pool_to_freed);
|
||||
} else {
|
||||
prev16 = &pool16->next;
|
||||
pool16 = pool16->next; /* move to next */
|
||||
}
|
||||
}
|
||||
gc32_t** prev32 = &vm->gc.pool32;
|
||||
gc32_t* pool32 = vm->gc.pool32;
|
||||
while (pool32) {
|
||||
if (pool32->bitmap == POOL32_BITMAP_FULL) {
|
||||
/* pool is empty, we can free it */
|
||||
*prev32 = pool32->next;
|
||||
gc32_t* pool_to_freed = pool32;
|
||||
pool32 = pool32->next; /* move to next */
|
||||
free(pool_to_freed);
|
||||
} else {
|
||||
prev32 = &pool32->next;
|
||||
pool32 = pool32->next; /* move to next */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BERRY_API void be_gc_init_memory_pools(bvm *vm) {
|
||||
vm->gc.pool16 = NULL;
|
||||
vm->gc.pool32 = NULL;
|
||||
}
|
||||
|
||||
BERRY_API void be_gc_free_memory_pools(bvm *vm) {
|
||||
gc16_t* pool16 = vm->gc.pool16;
|
||||
while (pool16) {
|
||||
gc16_t* pool_to_freed = pool16;
|
||||
pool16 = pool16->next;
|
||||
be_os_free(pool_to_freed);
|
||||
pool16 = pool16->next;
|
||||
}
|
||||
vm->gc.pool16 = NULL;
|
||||
|
||||
gc32_t* pool32 = vm->gc.pool32;
|
||||
while (pool32) {
|
||||
gc32_t* pool_to_freed = pool32;
|
||||
pool32 = pool32->next;
|
||||
be_os_free(pool_to_freed);
|
||||
pool32 = pool32->next;
|
||||
}
|
||||
vm->gc.pool32 = NULL;
|
||||
}
|
||||
|
||||
/* https://github.com/hcs0/Hackers-Delight/blob/master/pop.c.txt - count number of 1-bits */
|
||||
static int pop0(uint32_t n) {
|
||||
n = (n & 0x55555555u) + ((n >> 1) & 0x55555555u);
|
||||
n = (n & 0x33333333u) + ((n >> 2) & 0x33333333u);
|
||||
n = (n & 0x0f0f0f0fu) + ((n >> 4) & 0x0f0f0f0fu);
|
||||
n = (n & 0x00ff00ffu) + ((n >> 8) & 0x00ff00ffu);
|
||||
n = (n & 0x0000ffffu) + ((n >>16) & 0x0000ffffu);
|
||||
return n;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define count_bits_1(v) __builtin_popcount(v)
|
||||
#else
|
||||
#define count_bits_1(v) pop0(v)
|
||||
#endif
|
||||
|
||||
|
||||
BERRY_API void be_gc_memory_pools_info(bvm *vm, size_t* slots_used, size_t* slots_allocated) {
|
||||
size_t used = 0;
|
||||
size_t allocated = 0;
|
||||
|
||||
gc16_t* pool16 = vm->gc.pool16;
|
||||
while (pool16) {
|
||||
allocated += POOL16_SLOTS;
|
||||
used += POOL16_SLOTS - count_bits_1(pool16->bitmap);
|
||||
pool16 = pool16->next;
|
||||
}
|
||||
|
||||
gc32_t* pool32 = vm->gc.pool32;
|
||||
while (pool32) {
|
||||
allocated += POOL32_SLOTS;
|
||||
used += POOL32_SLOTS - count_bits_1(pool32->bitmap);
|
||||
pool32 = pool32->next;
|
||||
}
|
||||
if (slots_used) { *slots_used = used; }
|
||||
if (slots_allocated) { *slots_allocated = allocated; }
|
||||
}
|
@ -21,6 +21,14 @@ BERRY_API void* be_os_malloc(size_t size);
|
||||
BERRY_API void be_os_free(void *ptr);
|
||||
BERRY_API void* be_os_realloc(void *ptr, size_t size);
|
||||
BERRY_API void* be_realloc(bvm *vm, void *ptr, size_t old_size, size_t new_size);
|
||||
BERRY_API void be_gc_memory_pools(bvm *vm);
|
||||
BERRY_API void be_gc_free_memory_pools(bvm *vm);
|
||||
BERRY_API void be_gc_init_memory_pools(bvm *vm);
|
||||
BERRY_API void be_gc_memory_pools_info(bvm *vm, size_t* slots_used, size_t* slots_allocated);
|
||||
|
||||
/* The following moves a portion of memory to constraint regions with 32-bits read/write acess */
|
||||
/* Effective only if `BE_USE_MEM_ALIGNED` is set to `1`*/
|
||||
BERRY_API void* be_move_to_aligned(bvm *vm, void *ptr, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -312,16 +312,23 @@ static void end_func(bparser *parser)
|
||||
be_code_ret(finfo, NULL); /* append a return to last code */
|
||||
end_block(parser); /* close block */
|
||||
setupvals(finfo); /* close upvals */
|
||||
proto->code = be_vector_release_32(vm, &finfo->code); /* compact all vectors and return NULL if empty */
|
||||
proto->code = be_vector_release(vm, &finfo->code); /* compact all vectors and return NULL if empty */
|
||||
proto->codesize = finfo->pc;
|
||||
proto->ktab = be_vector_release_32(vm, &finfo->kvec);
|
||||
proto->ktab = be_vector_release(vm, &finfo->kvec);
|
||||
proto->nconst = be_vector_count(&finfo->kvec);
|
||||
proto->ptab = be_vector_release(vm, &finfo->pvec);
|
||||
proto->nproto = be_vector_count(&finfo->pvec);
|
||||
#if BE_USE_MEM_ALIGNED
|
||||
proto->code = be_move_to_aligned(vm, proto->code, proto->codesize * sizeof(binstruction)); /* move `code` to 4-bytes aligned memory region */
|
||||
proto->ktab = be_move_to_aligned(vm, proto->ktab, proto->nconst * sizeof(bvalue)); /* move `ktab` to 4-bytes aligned memory region */
|
||||
#endif /* BE_USE_MEM_ALIGNED */
|
||||
#if BE_DEBUG_RUNTIME_INFO
|
||||
proto->lineinfo = be_vector_release_32(vm, &finfo->linevec);
|
||||
proto->lineinfo = be_vector_release(vm, &finfo->linevec); /* move `lineinfo` to 4-bytes aligned memory region */
|
||||
proto->nlineinfo = be_vector_count(&finfo->linevec);
|
||||
#endif
|
||||
#if BE_USE_MEM_ALIGNED
|
||||
proto->lineinfo = be_move_to_aligned(vm, proto->lineinfo, proto->nlineinfo * sizeof(blineinfo));
|
||||
#endif /* BE_USE_MEM_ALIGNED */
|
||||
#endif /* BE_DEBUG_RUNTIME_INFO */
|
||||
#if BE_DEBUG_VAR_INFO
|
||||
proto->varinfo = be_vector_release(vm, &finfo->varvec);
|
||||
proto->nvarinfo = be_vector_count(&finfo->varvec);
|
||||
|
@ -114,32 +114,6 @@ void* be_vector_release(bvm *vm, bvector *vector)
|
||||
return vector->data;
|
||||
}
|
||||
|
||||
/* free not used */
|
||||
void* be_vector_release_32(bvm *vm, bvector *vector)
|
||||
{
|
||||
size_t size = vector->size;
|
||||
int count = be_vector_count(vector);
|
||||
if (count == 0) {
|
||||
be_free(vm, vector->data, vector->capacity * size);
|
||||
vector->capacity = 0;
|
||||
vector->data = NULL;
|
||||
vector->end = NULL;
|
||||
} else if (count < vector->capacity) {
|
||||
vector->data = be_realloc(vm,
|
||||
vector->data, vector->capacity * size, count * size); // TODO - can we skip that step?
|
||||
void* iram = berry_malloc32(count * size);
|
||||
if (iram) {
|
||||
memcpy(iram, vector->data, count * size);
|
||||
free(vector->data);
|
||||
vector->data = iram;
|
||||
}
|
||||
// vm->gc.usage = vm->gc.usage + count * size - vector->capacity * size; /* update allocated count */
|
||||
vector->end = (char*)vector->data + ((size_t)count - 1) * size;
|
||||
vector->capacity = count;
|
||||
}
|
||||
return vector->data;
|
||||
}
|
||||
|
||||
/* use binary search to find the vector capacity between 0-1024 */
|
||||
static int binary_search(int value)
|
||||
{
|
||||
|
@ -491,6 +491,7 @@ BERRY_API void be_vm_delete(bvm *vm)
|
||||
be_stack_delete(vm, &vm->tracestack);
|
||||
be_free(vm, vm->stack, (vm->stacktop - vm->stack) * sizeof(bvalue));
|
||||
be_globalvar_deinit(vm);
|
||||
be_gc_free_memory_pools(vm);
|
||||
#if BE_USE_DEBUG_HOOK
|
||||
/* free native hook */
|
||||
if (var_istype(&vm->hook, BE_COMPTR))
|
||||
@ -904,7 +905,11 @@ newframe: /* a new call frame */
|
||||
if (var_isinstance(a) && var_isstr(b)) {
|
||||
binstance *obj = var_toobj(a);
|
||||
bstring *attr = var_tostr(b);
|
||||
if (!be_instance_setmember(vm, obj, attr, c)) {
|
||||
bvalue result = *c;
|
||||
if (var_isfunction(&result)) {
|
||||
var_markstatic(&result);
|
||||
}
|
||||
if (!be_instance_setmember(vm, obj, attr, &result)) {
|
||||
reg = vm->reg;
|
||||
vm_error(vm, "attribute_error",
|
||||
"class '%s' cannot assign to attribute '%s'",
|
||||
|
@ -46,10 +46,14 @@ typedef struct {
|
||||
int status;
|
||||
} bcallframe;
|
||||
|
||||
struct gc16_t; /* memory pool for 0-16 bytes or less objects */
|
||||
struct gc32_t; /* memory pool for 17-32 bytes */
|
||||
struct bgc {
|
||||
bgcobject *list; /* the GC-object list */
|
||||
bgcobject *gray; /* the gray object list */
|
||||
bgcobject *fixed; /* the fixed objecct list */
|
||||
struct gc16_t* pool16;
|
||||
struct gc32_t* pool32;
|
||||
size_t usage; /* the count of bytes currently allocated */
|
||||
size_t threshold; /* he threshold of allocation for the next GC */
|
||||
bbyte steprate; /* the rate of increase in the distribution between two GCs (percentage) */
|
||||
@ -80,7 +84,6 @@ struct bupval {
|
||||
} u;
|
||||
int refcnt;
|
||||
};
|
||||
|
||||
struct bvm {
|
||||
bglobaldesc gbldesc; /* global description */
|
||||
bvalue *stack; /* stack space */
|
||||
|
@ -6,6 +6,363 @@
|
||||
|
||||
#if defined(USE_EMULATION) && defined(USE_EMULATION_HUE)
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: full_status
|
||||
********************************************************************/
|
||||
be_local_closure(hue_bridge_monad_full_status, /* name */
|
||||
be_nested_proto(
|
||||
11, /* nstack */
|
||||
2, /* argc */
|
||||
2, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[ 8]) { /* constants */
|
||||
/* K0 */ be_nested_str(hue_ntv),
|
||||
/* K1 */ be_nested_str(lights),
|
||||
/* K2 */ be_nested_str(contains),
|
||||
/* K3 */ be_nested_str(full_state),
|
||||
/* K4 */ be_nested_str(light),
|
||||
/* K5 */ be_nested_str(name),
|
||||
/* K6 */ be_nested_str(model),
|
||||
/* K7 */ be_nested_str(manuf),
|
||||
}),
|
||||
&be_const_str_full_status,
|
||||
&be_const_str_solidified,
|
||||
( &(const binstruction[17]) { /* code */
|
||||
0xA40A0000, // 0000 IMPORT R2 K0
|
||||
0x880C0101, // 0001 GETMBR R3 R0 K1
|
||||
0x8C0C0702, // 0002 GETMET R3 R3 K2
|
||||
0x5C140200, // 0003 MOVE R5 R1
|
||||
0x7C0C0400, // 0004 CALL R3 2
|
||||
0x780E0009, // 0005 JMPF R3 #0010
|
||||
0x880C0101, // 0006 GETMBR R3 R0 K1
|
||||
0x940C0601, // 0007 GETIDX R3 R3 R1
|
||||
0x8C100503, // 0008 GETMET R4 R2 K3
|
||||
0x5C180200, // 0009 MOVE R6 R1
|
||||
0x941C0704, // 000A GETIDX R7 R3 K4
|
||||
0x94200705, // 000B GETIDX R8 R3 K5
|
||||
0x94240706, // 000C GETIDX R9 R3 K6
|
||||
0x94280707, // 000D GETIDX R10 R3 K7
|
||||
0x7C100C00, // 000E CALL R4 6
|
||||
0x80040800, // 000F RET 1 R4
|
||||
0x80000000, // 0010 RET 0
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: hue_status
|
||||
********************************************************************/
|
||||
be_local_closure(hue_bridge_monad_hue_status, /* name */
|
||||
be_nested_proto(
|
||||
6, /* nstack */
|
||||
2, /* argc */
|
||||
2, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[ 5]) { /* constants */
|
||||
/* K0 */ be_nested_str(hue_ntv),
|
||||
/* K1 */ be_nested_str(lights),
|
||||
/* K2 */ be_nested_str(contains),
|
||||
/* K3 */ be_nested_str(light_state),
|
||||
/* K4 */ be_nested_str(light),
|
||||
}),
|
||||
&be_const_str_hue_status,
|
||||
&be_const_str_solidified,
|
||||
( &(const binstruction[13]) { /* code */
|
||||
0xA40A0000, // 0000 IMPORT R2 K0
|
||||
0x880C0101, // 0001 GETMBR R3 R0 K1
|
||||
0x8C0C0702, // 0002 GETMET R3 R3 K2
|
||||
0x5C140200, // 0003 MOVE R5 R1
|
||||
0x7C0C0400, // 0004 CALL R3 2
|
||||
0x780E0005, // 0005 JMPF R3 #000C
|
||||
0x8C0C0503, // 0006 GETMET R3 R2 K3
|
||||
0x88140101, // 0007 GETMBR R5 R0 K1
|
||||
0x94140A01, // 0008 GETIDX R5 R5 R1
|
||||
0x94140B04, // 0009 GETIDX R5 R5 K4
|
||||
0x7C0C0400, // 000A CALL R3 2
|
||||
0x80040600, // 000B RET 1 R3
|
||||
0x80000000, // 000C RET 0
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: add_light
|
||||
********************************************************************/
|
||||
be_local_closure(hue_bridge_monad_add_light, /* name */
|
||||
be_nested_proto(
|
||||
10, /* nstack */
|
||||
6, /* argc */
|
||||
2, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[14]) { /* constants */
|
||||
/* K0 */ be_nested_str(int),
|
||||
/* K1 */ be_nested_str(value_error),
|
||||
/* K2 */ be_nested_str(id_X20must_X20be_X20of_X20type_X20_X27int_X27),
|
||||
/* K3 */ be_nested_str(light_state),
|
||||
/* K4 */ be_nested_str(light_X20must_X20be_X20of_X20class_X20_X27light_state_X27),
|
||||
/* K5 */ be_const_int(0),
|
||||
/* K6 */ be_nested_str(missing_X20name),
|
||||
/* K7 */ be_nested_str(Unknown),
|
||||
/* K8 */ be_nested_str(Tasmota),
|
||||
/* K9 */ be_nested_str(lights),
|
||||
/* K10 */ be_nested_str(light),
|
||||
/* K11 */ be_nested_str(name),
|
||||
/* K12 */ be_nested_str(model),
|
||||
/* K13 */ be_nested_str(manuf),
|
||||
}),
|
||||
&be_const_str_add_light,
|
||||
&be_const_str_solidified,
|
||||
( &(const binstruction[43]) { /* code */
|
||||
0x60180004, // 0000 GETGBL R6 G4
|
||||
0x5C1C0200, // 0001 MOVE R7 R1
|
||||
0x7C180200, // 0002 CALL R6 1
|
||||
0x20180D00, // 0003 NE R6 R6 K0
|
||||
0x781A0000, // 0004 JMPF R6 #0006
|
||||
0xB0060302, // 0005 RAISE 1 K1 K2
|
||||
0x6018000F, // 0006 GETGBL R6 G15
|
||||
0x5C1C0400, // 0007 MOVE R7 R2
|
||||
0xB8220600, // 0008 GETNGBL R8 K3
|
||||
0x7C180400, // 0009 CALL R6 2
|
||||
0x741A0000, // 000A JMPT R6 #000C
|
||||
0xB0060304, // 000B RAISE 1 K1 K4
|
||||
0x60180008, // 000C GETGBL R6 G8
|
||||
0x5C1C0600, // 000D MOVE R7 R3
|
||||
0x7C180200, // 000E CALL R6 1
|
||||
0x5C0C0C00, // 000F MOVE R3 R6
|
||||
0x6018000C, // 0010 GETGBL R6 G12
|
||||
0x5C1C0600, // 0011 MOVE R7 R3
|
||||
0x7C180200, // 0012 CALL R6 1
|
||||
0x1C180D05, // 0013 EQ R6 R6 K5
|
||||
0x781A0000, // 0014 JMPF R6 #0016
|
||||
0xB0060306, // 0015 RAISE 1 K1 K6
|
||||
0x5C180800, // 0016 MOVE R6 R4
|
||||
0x741A0000, // 0017 JMPT R6 #0019
|
||||
0x58100007, // 0018 LDCONST R4 K7
|
||||
0x5C180A00, // 0019 MOVE R6 R5
|
||||
0x741A0000, // 001A JMPT R6 #001C
|
||||
0x58140008, // 001B LDCONST R5 K8
|
||||
0x88180109, // 001C GETMBR R6 R0 K9
|
||||
0x601C0013, // 001D GETGBL R7 G19
|
||||
0x7C1C0000, // 001E CALL R7 0
|
||||
0x981E1402, // 001F SETIDX R7 K10 R2
|
||||
0x981E1603, // 0020 SETIDX R7 K11 R3
|
||||
0x60200008, // 0021 GETGBL R8 G8
|
||||
0x5C240800, // 0022 MOVE R9 R4
|
||||
0x7C200200, // 0023 CALL R8 1
|
||||
0x981E1808, // 0024 SETIDX R7 K12 R8
|
||||
0x60200008, // 0025 GETGBL R8 G8
|
||||
0x5C240A00, // 0026 MOVE R9 R5
|
||||
0x7C200200, // 0027 CALL R8 1
|
||||
0x981E1A08, // 0028 SETIDX R7 K13 R8
|
||||
0x98180207, // 0029 SETIDX R6 R1 R7
|
||||
0x80000000, // 002A RET 0
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: remove_light
|
||||
********************************************************************/
|
||||
be_local_closure(hue_bridge_monad_remove_light, /* name */
|
||||
be_nested_proto(
|
||||
5, /* nstack */
|
||||
2, /* argc */
|
||||
2, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[ 2]) { /* constants */
|
||||
/* K0 */ be_nested_str(lights),
|
||||
/* K1 */ be_nested_str(remove),
|
||||
}),
|
||||
&be_const_str_remove_light,
|
||||
&be_const_str_solidified,
|
||||
( &(const binstruction[ 5]) { /* code */
|
||||
0x88080100, // 0000 GETMBR R2 R0 K0
|
||||
0x8C080501, // 0001 GETMET R2 R2 K1
|
||||
0x5C100200, // 0002 MOVE R4 R1
|
||||
0x7C080400, // 0003 CALL R2 2
|
||||
0x80000000, // 0004 RET 0
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: init
|
||||
********************************************************************/
|
||||
be_local_closure(hue_bridge_monad_init, /* name */
|
||||
be_nested_proto(
|
||||
2, /* nstack */
|
||||
1, /* argc */
|
||||
2, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[ 1]) { /* constants */
|
||||
/* K0 */ be_nested_str(lights),
|
||||
}),
|
||||
&be_const_str_init,
|
||||
&be_const_str_solidified,
|
||||
( &(const binstruction[ 4]) { /* code */
|
||||
0x60040013, // 0000 GETGBL R1 G19
|
||||
0x7C040000, // 0001 CALL R1 0
|
||||
0x90020001, // 0002 SETMBR R0 K0 R1
|
||||
0x80000000, // 0003 RET 0
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: discover
|
||||
********************************************************************/
|
||||
be_local_closure(hue_bridge_monad_discover, /* name */
|
||||
be_nested_proto(
|
||||
11, /* nstack */
|
||||
1, /* argc */
|
||||
2, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[13]) { /* constants */
|
||||
/* K0 */ be_nested_str(hue_ntv),
|
||||
/* K1 */ be_nested_str(json),
|
||||
/* K2 */ be_nested_str(string),
|
||||
/* K3 */ be_nested_str(lights),
|
||||
/* K4 */ be_nested_str(keys),
|
||||
/* K5 */ be_nested_str(full_status),
|
||||
/* K6 */ be_nested_str(_X22),
|
||||
/* K7 */ be_nested_str(_X22_X3A),
|
||||
/* K8 */ be_nested_str(push),
|
||||
/* K9 */ be_nested_str(stop_iteration),
|
||||
/* K10 */ be_const_int(0),
|
||||
/* K11 */ be_nested_str(concat),
|
||||
/* K12 */ be_nested_str(_X2C),
|
||||
}),
|
||||
&be_const_str_discover,
|
||||
&be_const_str_solidified,
|
||||
( &(const binstruction[40]) { /* code */
|
||||
0xA4060000, // 0000 IMPORT R1 K0
|
||||
0xA40A0200, // 0001 IMPORT R2 K1
|
||||
0xA40E0400, // 0002 IMPORT R3 K2
|
||||
0x60100012, // 0003 GETGBL R4 G18
|
||||
0x7C100000, // 0004 CALL R4 0
|
||||
0x60140010, // 0005 GETGBL R5 G16
|
||||
0x88180103, // 0006 GETMBR R6 R0 K3
|
||||
0x8C180D04, // 0007 GETMET R6 R6 K4
|
||||
0x7C180200, // 0008 CALL R6 1
|
||||
0x7C140200, // 0009 CALL R5 1
|
||||
0xA802000F, // 000A EXBLK 0 #001B
|
||||
0x5C180A00, // 000B MOVE R6 R5
|
||||
0x7C180000, // 000C CALL R6 0
|
||||
0x8C1C0105, // 000D GETMET R7 R0 K5
|
||||
0x5C240C00, // 000E MOVE R9 R6
|
||||
0x7C1C0400, // 000F CALL R7 2
|
||||
0x781E0008, // 0010 JMPF R7 #001A
|
||||
0x60200008, // 0011 GETGBL R8 G8
|
||||
0x5C240C00, // 0012 MOVE R9 R6
|
||||
0x7C200200, // 0013 CALL R8 1
|
||||
0x00220C08, // 0014 ADD R8 K6 R8
|
||||
0x00201107, // 0015 ADD R8 R8 K7
|
||||
0x001C1007, // 0016 ADD R7 R8 R7
|
||||
0x8C200908, // 0017 GETMET R8 R4 K8
|
||||
0x5C280E00, // 0018 MOVE R10 R7
|
||||
0x7C200400, // 0019 CALL R8 2
|
||||
0x7001FFEF, // 001A JMP #000B
|
||||
0x58140009, // 001B LDCONST R5 K9
|
||||
0xAC140200, // 001C CATCH R5 1 0
|
||||
0xB0080000, // 001D RAISE 2 R0 R0
|
||||
0x6014000C, // 001E GETGBL R5 G12
|
||||
0x5C180800, // 001F MOVE R6 R4
|
||||
0x7C140200, // 0020 CALL R5 1
|
||||
0x24140B0A, // 0021 GT R5 R5 K10
|
||||
0x78160003, // 0022 JMPF R5 #0027
|
||||
0x8C14090B, // 0023 GETMET R5 R4 K11
|
||||
0x581C000C, // 0024 LDCONST R7 K12
|
||||
0x7C140400, // 0025 CALL R5 2
|
||||
0x80040A00, // 0026 RET 1 R5
|
||||
0x80000000, // 0027 RET 0
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: light_to_id
|
||||
********************************************************************/
|
||||
be_local_closure(hue_bridge_monad_light_to_id, /* name */
|
||||
be_nested_proto(
|
||||
5, /* nstack */
|
||||
2, /* argc */
|
||||
2, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[ 4]) { /* constants */
|
||||
/* K0 */ be_nested_str(lights),
|
||||
/* K1 */ be_nested_str(keys),
|
||||
/* K2 */ be_nested_str(light),
|
||||
/* K3 */ be_nested_str(stop_iteration),
|
||||
}),
|
||||
&be_const_str_light_to_id,
|
||||
&be_const_str_solidified,
|
||||
( &(const binstruction[20]) { /* code */
|
||||
0x60080010, // 0000 GETGBL R2 G16
|
||||
0x880C0100, // 0001 GETMBR R3 R0 K0
|
||||
0x8C0C0701, // 0002 GETMET R3 R3 K1
|
||||
0x7C0C0200, // 0003 CALL R3 1
|
||||
0x7C080200, // 0004 CALL R2 1
|
||||
0xA8020009, // 0005 EXBLK 0 #0010
|
||||
0x5C0C0400, // 0006 MOVE R3 R2
|
||||
0x7C0C0000, // 0007 CALL R3 0
|
||||
0x88100100, // 0008 GETMBR R4 R0 K0
|
||||
0x94100803, // 0009 GETIDX R4 R4 R3
|
||||
0x94100902, // 000A GETIDX R4 R4 K2
|
||||
0x1C100204, // 000B EQ R4 R1 R4
|
||||
0x78120001, // 000C JMPF R4 #000F
|
||||
0xA8040001, // 000D EXBLK 1 1
|
||||
0x80040600, // 000E RET 1 R3
|
||||
0x7001FFF5, // 000F JMP #0006
|
||||
0x58080003, // 0010 LDCONST R2 K3
|
||||
0xAC080200, // 0011 CATCH R2 1 0
|
||||
0xB0080000, // 0012 RAISE 2 R0 R0
|
||||
0x80000000, // 0013 RET 0
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: cmd
|
||||
********************************************************************/
|
||||
@ -228,37 +585,6 @@ be_local_closure(hue_bridge_monad_cmd, /* name */
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: remove_light
|
||||
********************************************************************/
|
||||
be_local_closure(hue_bridge_monad_remove_light, /* name */
|
||||
be_nested_proto(
|
||||
5, /* nstack */
|
||||
2, /* argc */
|
||||
2, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[ 2]) { /* constants */
|
||||
/* K0 */ be_nested_str(lights),
|
||||
/* K1 */ be_nested_str(remove),
|
||||
}),
|
||||
&be_const_str_remove_light,
|
||||
&be_const_str_solidified,
|
||||
( &(const binstruction[ 5]) { /* code */
|
||||
0x88080100, // 0000 GETMBR R2 R0 K0
|
||||
0x8C080501, // 0001 GETMET R2 R2 K1
|
||||
0x5C100200, // 0002 MOVE R4 R1
|
||||
0x7C080400, // 0003 CALL R2 2
|
||||
0x80000000, // 0004 RET 0
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: groups
|
||||
********************************************************************/
|
||||
@ -322,301 +648,24 @@ be_local_closure(hue_bridge_monad_groups, /* name */
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: hue_status
|
||||
********************************************************************/
|
||||
be_local_closure(hue_bridge_monad_hue_status, /* name */
|
||||
be_nested_proto(
|
||||
6, /* nstack */
|
||||
2, /* argc */
|
||||
2, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[ 5]) { /* constants */
|
||||
/* K0 */ be_nested_str(hue_ntv),
|
||||
/* K1 */ be_nested_str(lights),
|
||||
/* K2 */ be_nested_str(contains),
|
||||
/* K3 */ be_nested_str(light_state),
|
||||
/* K4 */ be_nested_str(light),
|
||||
}),
|
||||
&be_const_str_hue_status,
|
||||
&be_const_str_solidified,
|
||||
( &(const binstruction[13]) { /* code */
|
||||
0xA40A0000, // 0000 IMPORT R2 K0
|
||||
0x880C0101, // 0001 GETMBR R3 R0 K1
|
||||
0x8C0C0702, // 0002 GETMET R3 R3 K2
|
||||
0x5C140200, // 0003 MOVE R5 R1
|
||||
0x7C0C0400, // 0004 CALL R3 2
|
||||
0x780E0005, // 0005 JMPF R3 #000C
|
||||
0x8C0C0503, // 0006 GETMET R3 R2 K3
|
||||
0x88140101, // 0007 GETMBR R5 R0 K1
|
||||
0x94140A01, // 0008 GETIDX R5 R5 R1
|
||||
0x94140B04, // 0009 GETIDX R5 R5 K4
|
||||
0x7C0C0400, // 000A CALL R3 2
|
||||
0x80040600, // 000B RET 1 R3
|
||||
0x80000000, // 000C RET 0
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: add_light
|
||||
********************************************************************/
|
||||
be_local_closure(hue_bridge_monad_add_light, /* name */
|
||||
be_nested_proto(
|
||||
10, /* nstack */
|
||||
6, /* argc */
|
||||
2, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[14]) { /* constants */
|
||||
/* K0 */ be_nested_str(int),
|
||||
/* K1 */ be_nested_str(value_error),
|
||||
/* K2 */ be_nested_str(id_X20must_X20be_X20of_X20type_X20_X27int_X27),
|
||||
/* K3 */ be_nested_str(light_state),
|
||||
/* K4 */ be_nested_str(light_X20must_X20be_X20of_X20class_X20_X27light_state_X27),
|
||||
/* K5 */ be_const_int(0),
|
||||
/* K6 */ be_nested_str(missing_X20name),
|
||||
/* K7 */ be_nested_str(Unknown),
|
||||
/* K8 */ be_nested_str(Tasmota),
|
||||
/* K9 */ be_nested_str(lights),
|
||||
/* K10 */ be_nested_str(light),
|
||||
/* K11 */ be_nested_str(name),
|
||||
/* K12 */ be_nested_str(model),
|
||||
/* K13 */ be_nested_str(manuf),
|
||||
}),
|
||||
&be_const_str_add_light,
|
||||
&be_const_str_solidified,
|
||||
( &(const binstruction[43]) { /* code */
|
||||
0x60180004, // 0000 GETGBL R6 G4
|
||||
0x5C1C0200, // 0001 MOVE R7 R1
|
||||
0x7C180200, // 0002 CALL R6 1
|
||||
0x20180D00, // 0003 NE R6 R6 K0
|
||||
0x781A0000, // 0004 JMPF R6 #0006
|
||||
0xB0060302, // 0005 RAISE 1 K1 K2
|
||||
0x6018000F, // 0006 GETGBL R6 G15
|
||||
0x5C1C0400, // 0007 MOVE R7 R2
|
||||
0xB8220600, // 0008 GETNGBL R8 K3
|
||||
0x7C180400, // 0009 CALL R6 2
|
||||
0x741A0000, // 000A JMPT R6 #000C
|
||||
0xB0060304, // 000B RAISE 1 K1 K4
|
||||
0x60180008, // 000C GETGBL R6 G8
|
||||
0x5C1C0600, // 000D MOVE R7 R3
|
||||
0x7C180200, // 000E CALL R6 1
|
||||
0x5C0C0C00, // 000F MOVE R3 R6
|
||||
0x6018000C, // 0010 GETGBL R6 G12
|
||||
0x5C1C0600, // 0011 MOVE R7 R3
|
||||
0x7C180200, // 0012 CALL R6 1
|
||||
0x1C180D05, // 0013 EQ R6 R6 K5
|
||||
0x781A0000, // 0014 JMPF R6 #0016
|
||||
0xB0060306, // 0015 RAISE 1 K1 K6
|
||||
0x5C180800, // 0016 MOVE R6 R4
|
||||
0x741A0000, // 0017 JMPT R6 #0019
|
||||
0x58100007, // 0018 LDCONST R4 K7
|
||||
0x5C180A00, // 0019 MOVE R6 R5
|
||||
0x741A0000, // 001A JMPT R6 #001C
|
||||
0x58140008, // 001B LDCONST R5 K8
|
||||
0x88180109, // 001C GETMBR R6 R0 K9
|
||||
0x601C0013, // 001D GETGBL R7 G19
|
||||
0x7C1C0000, // 001E CALL R7 0
|
||||
0x981E1402, // 001F SETIDX R7 K10 R2
|
||||
0x981E1603, // 0020 SETIDX R7 K11 R3
|
||||
0x60200008, // 0021 GETGBL R8 G8
|
||||
0x5C240800, // 0022 MOVE R9 R4
|
||||
0x7C200200, // 0023 CALL R8 1
|
||||
0x981E1808, // 0024 SETIDX R7 K12 R8
|
||||
0x60200008, // 0025 GETGBL R8 G8
|
||||
0x5C240A00, // 0026 MOVE R9 R5
|
||||
0x7C200200, // 0027 CALL R8 1
|
||||
0x981E1A08, // 0028 SETIDX R7 K13 R8
|
||||
0x98180207, // 0029 SETIDX R6 R1 R7
|
||||
0x80000000, // 002A RET 0
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: init
|
||||
********************************************************************/
|
||||
be_local_closure(hue_bridge_monad_init, /* name */
|
||||
be_nested_proto(
|
||||
2, /* nstack */
|
||||
1, /* argc */
|
||||
2, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[ 1]) { /* constants */
|
||||
/* K0 */ be_nested_str(lights),
|
||||
}),
|
||||
&be_const_str_init,
|
||||
&be_const_str_solidified,
|
||||
( &(const binstruction[ 4]) { /* code */
|
||||
0x60040013, // 0000 GETGBL R1 G19
|
||||
0x7C040000, // 0001 CALL R1 0
|
||||
0x90020001, // 0002 SETMBR R0 K0 R1
|
||||
0x80000000, // 0003 RET 0
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: discover
|
||||
********************************************************************/
|
||||
be_local_closure(hue_bridge_monad_discover, /* name */
|
||||
be_nested_proto(
|
||||
11, /* nstack */
|
||||
1, /* argc */
|
||||
2, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[13]) { /* constants */
|
||||
/* K0 */ be_nested_str(hue_ntv),
|
||||
/* K1 */ be_nested_str(json),
|
||||
/* K2 */ be_nested_str(string),
|
||||
/* K3 */ be_nested_str(lights),
|
||||
/* K4 */ be_nested_str(keys),
|
||||
/* K5 */ be_nested_str(full_status),
|
||||
/* K6 */ be_nested_str(_X22),
|
||||
/* K7 */ be_nested_str(_X22_X3A),
|
||||
/* K8 */ be_nested_str(push),
|
||||
/* K9 */ be_nested_str(stop_iteration),
|
||||
/* K10 */ be_const_int(0),
|
||||
/* K11 */ be_nested_str(concat),
|
||||
/* K12 */ be_nested_str(_X2C),
|
||||
}),
|
||||
&be_const_str_discover,
|
||||
&be_const_str_solidified,
|
||||
( &(const binstruction[40]) { /* code */
|
||||
0xA4060000, // 0000 IMPORT R1 K0
|
||||
0xA40A0200, // 0001 IMPORT R2 K1
|
||||
0xA40E0400, // 0002 IMPORT R3 K2
|
||||
0x60100012, // 0003 GETGBL R4 G18
|
||||
0x7C100000, // 0004 CALL R4 0
|
||||
0x60140010, // 0005 GETGBL R5 G16
|
||||
0x88180103, // 0006 GETMBR R6 R0 K3
|
||||
0x8C180D04, // 0007 GETMET R6 R6 K4
|
||||
0x7C180200, // 0008 CALL R6 1
|
||||
0x7C140200, // 0009 CALL R5 1
|
||||
0xA802000F, // 000A EXBLK 0 #001B
|
||||
0x5C180A00, // 000B MOVE R6 R5
|
||||
0x7C180000, // 000C CALL R6 0
|
||||
0x8C1C0105, // 000D GETMET R7 R0 K5
|
||||
0x5C240C00, // 000E MOVE R9 R6
|
||||
0x7C1C0400, // 000F CALL R7 2
|
||||
0x781E0008, // 0010 JMPF R7 #001A
|
||||
0x60200008, // 0011 GETGBL R8 G8
|
||||
0x5C240C00, // 0012 MOVE R9 R6
|
||||
0x7C200200, // 0013 CALL R8 1
|
||||
0x00220C08, // 0014 ADD R8 K6 R8
|
||||
0x00201107, // 0015 ADD R8 R8 K7
|
||||
0x001C1007, // 0016 ADD R7 R8 R7
|
||||
0x8C200908, // 0017 GETMET R8 R4 K8
|
||||
0x5C280E00, // 0018 MOVE R10 R7
|
||||
0x7C200400, // 0019 CALL R8 2
|
||||
0x7001FFEF, // 001A JMP #000B
|
||||
0x58140009, // 001B LDCONST R5 K9
|
||||
0xAC140200, // 001C CATCH R5 1 0
|
||||
0xB0080000, // 001D RAISE 2 R0 R0
|
||||
0x6014000C, // 001E GETGBL R5 G12
|
||||
0x5C180800, // 001F MOVE R6 R4
|
||||
0x7C140200, // 0020 CALL R5 1
|
||||
0x24140B0A, // 0021 GT R5 R5 K10
|
||||
0x78160003, // 0022 JMPF R5 #0027
|
||||
0x8C14090B, // 0023 GETMET R5 R4 K11
|
||||
0x581C000C, // 0024 LDCONST R7 K12
|
||||
0x7C140400, // 0025 CALL R5 2
|
||||
0x80040A00, // 0026 RET 1 R5
|
||||
0x80000000, // 0027 RET 0
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: full_status
|
||||
********************************************************************/
|
||||
be_local_closure(hue_bridge_monad_full_status, /* name */
|
||||
be_nested_proto(
|
||||
11, /* nstack */
|
||||
2, /* argc */
|
||||
2, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[ 8]) { /* constants */
|
||||
/* K0 */ be_nested_str(hue_ntv),
|
||||
/* K1 */ be_nested_str(lights),
|
||||
/* K2 */ be_nested_str(contains),
|
||||
/* K3 */ be_nested_str(full_state),
|
||||
/* K4 */ be_nested_str(light),
|
||||
/* K5 */ be_nested_str(name),
|
||||
/* K6 */ be_nested_str(model),
|
||||
/* K7 */ be_nested_str(manuf),
|
||||
}),
|
||||
&be_const_str_full_status,
|
||||
&be_const_str_solidified,
|
||||
( &(const binstruction[17]) { /* code */
|
||||
0xA40A0000, // 0000 IMPORT R2 K0
|
||||
0x880C0101, // 0001 GETMBR R3 R0 K1
|
||||
0x8C0C0702, // 0002 GETMET R3 R3 K2
|
||||
0x5C140200, // 0003 MOVE R5 R1
|
||||
0x7C0C0400, // 0004 CALL R3 2
|
||||
0x780E0009, // 0005 JMPF R3 #0010
|
||||
0x880C0101, // 0006 GETMBR R3 R0 K1
|
||||
0x940C0601, // 0007 GETIDX R3 R3 R1
|
||||
0x8C100503, // 0008 GETMET R4 R2 K3
|
||||
0x5C180200, // 0009 MOVE R6 R1
|
||||
0x941C0704, // 000A GETIDX R7 R3 K4
|
||||
0x94200705, // 000B GETIDX R8 R3 K5
|
||||
0x94240706, // 000C GETIDX R9 R3 K6
|
||||
0x94280707, // 000D GETIDX R10 R3 K7
|
||||
0x7C100C00, // 000E CALL R4 6
|
||||
0x80040800, // 000F RET 1 R4
|
||||
0x80000000, // 0010 RET 0
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified class: hue_bridge_monad
|
||||
********************************************************************/
|
||||
be_local_class(hue_bridge_monad,
|
||||
1,
|
||||
NULL,
|
||||
be_nested_map(9,
|
||||
be_nested_map(10,
|
||||
( (struct bmapnode*) &(const bmapnode[]) {
|
||||
{ be_const_key(lights, 1), be_const_var(0) },
|
||||
{ be_const_key(groups, -1), be_const_closure(hue_bridge_monad_groups_closure) },
|
||||
{ be_const_key(remove_light, 3), be_const_closure(hue_bridge_monad_remove_light_closure) },
|
||||
{ be_const_key(discover, -1), be_const_closure(hue_bridge_monad_discover_closure) },
|
||||
{ be_const_key(lights, -1), be_const_var(0) },
|
||||
{ be_const_key(groups, 6), be_const_closure(hue_bridge_monad_groups_closure) },
|
||||
{ be_const_key(hue_status, -1), be_const_closure(hue_bridge_monad_hue_status_closure) },
|
||||
{ be_const_key(add_light, -1), be_const_closure(hue_bridge_monad_add_light_closure) },
|
||||
{ be_const_key(cmd, 7), be_const_closure(hue_bridge_monad_cmd_closure) },
|
||||
{ be_const_key(remove_light, 8), be_const_closure(hue_bridge_monad_remove_light_closure) },
|
||||
{ be_const_key(init, -1), be_const_closure(hue_bridge_monad_init_closure) },
|
||||
{ be_const_key(full_status, -1), be_const_closure(hue_bridge_monad_full_status_closure) },
|
||||
{ be_const_key(cmd, -1), be_const_closure(hue_bridge_monad_cmd_closure) },
|
||||
{ be_const_key(light_to_id, -1), be_const_closure(hue_bridge_monad_light_to_id_closure) },
|
||||
{ be_const_key(discover, -1), be_const_closure(hue_bridge_monad_discover_closure) },
|
||||
{ be_const_key(full_status, 1), be_const_closure(hue_bridge_monad_full_status_closure) },
|
||||
})),
|
||||
be_str_literal("hue_bridge_monad")
|
||||
);
|
||||
|
21
lib/libesp32/berry_tasmota/src/be_mqtt_lib.cpp
Normal file
21
lib/libesp32/berry_tasmota/src/be_mqtt_lib.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
/********************************************************************
|
||||
* Berry module `mqtt`
|
||||
*
|
||||
*******************************************************************/
|
||||
|
||||
#include "be_constobj.h"
|
||||
#include "be_mapping.h"
|
||||
|
||||
extern int be_mqtt_publish(bvm *vm);
|
||||
|
||||
extern void be_mqtt_subscribe(const char* topic); BE_FUNC_CTYPE_DECLARE(be_mqtt_subscribe, "", "s")
|
||||
extern void be_mqtt_unsubscribe(const char* topic); BE_FUNC_CTYPE_DECLARE(be_mqtt_unsubscribe, "", "s")
|
||||
|
||||
/* @const_object_info_begin
|
||||
module mqtt (scope: global) {
|
||||
publish, func(be_mqtt_publish)
|
||||
subscribe, ctype_func(be_mqtt_subscribe)
|
||||
unsubscribe, ctype_func(be_mqtt_unsubscribe)
|
||||
}
|
||||
@const_object_info_end */
|
||||
#include "be_fixed_mqtt.h"
|
@ -487,8 +487,8 @@ be_local_closure(Tasmota_exec_tele, /* name */
|
||||
/* K6 */ be_nested_str(Tele),
|
||||
/* K7 */ be_const_int(0),
|
||||
/* K8 */ be_nested_str(try_rule),
|
||||
/* K9 */ be_nested_str(k),
|
||||
/* K10 */ be_nested_str(v),
|
||||
/* K9 */ be_nested_str(trig),
|
||||
/* K10 */ be_nested_str(f),
|
||||
/* K11 */ be_const_int(1),
|
||||
}),
|
||||
&be_const_str_exec_tele,
|
||||
@ -559,7 +559,7 @@ be_local_closure(Tasmota_run_deferred, /* name */
|
||||
/* K1 */ be_const_int(0),
|
||||
/* K2 */ be_nested_str(size),
|
||||
/* K3 */ be_nested_str(time_reached),
|
||||
/* K4 */ be_nested_str(due),
|
||||
/* K4 */ be_nested_str(trig),
|
||||
/* K5 */ be_nested_str(f),
|
||||
/* K6 */ be_nested_str(remove),
|
||||
/* K7 */ be_const_int(1),
|
||||
@ -1123,45 +1123,51 @@ be_local_closure(Tasmota_time_str, /* name */
|
||||
********************************************************************/
|
||||
be_local_closure(Tasmota_remove_rule, /* name */
|
||||
be_nested_proto(
|
||||
6, /* nstack */
|
||||
2, /* argc */
|
||||
7, /* nstack */
|
||||
3, /* argc */
|
||||
2, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[ 5]) { /* constants */
|
||||
( &(const bvalue[ 6]) { /* constants */
|
||||
/* K0 */ be_nested_str(_rules),
|
||||
/* K1 */ be_const_int(0),
|
||||
/* K2 */ be_nested_str(k),
|
||||
/* K3 */ be_nested_str(remove),
|
||||
/* K4 */ be_const_int(1),
|
||||
/* K2 */ be_nested_str(trig),
|
||||
/* K3 */ be_nested_str(id),
|
||||
/* K4 */ be_nested_str(remove),
|
||||
/* K5 */ be_const_int(1),
|
||||
}),
|
||||
&be_const_str_remove_rule,
|
||||
&be_const_str_solidified,
|
||||
( &(const binstruction[21]) { /* code */
|
||||
0x88080100, // 0000 GETMBR R2 R0 K0
|
||||
0x780A0011, // 0001 JMPF R2 #0014
|
||||
0x58080001, // 0002 LDCONST R2 K1
|
||||
0x600C000C, // 0003 GETGBL R3 G12
|
||||
0x88100100, // 0004 GETMBR R4 R0 K0
|
||||
0x7C0C0200, // 0005 CALL R3 1
|
||||
0x140C0403, // 0006 LT R3 R2 R3
|
||||
0x780E000B, // 0007 JMPF R3 #0014
|
||||
0x880C0100, // 0008 GETMBR R3 R0 K0
|
||||
0x940C0602, // 0009 GETIDX R3 R3 R2
|
||||
0x880C0702, // 000A GETMBR R3 R3 K2
|
||||
0x1C0C0601, // 000B EQ R3 R3 R1
|
||||
0x780E0004, // 000C JMPF R3 #0012
|
||||
0x880C0100, // 000D GETMBR R3 R0 K0
|
||||
0x8C0C0703, // 000E GETMET R3 R3 K3
|
||||
0x5C140400, // 000F MOVE R5 R2
|
||||
0x7C0C0400, // 0010 CALL R3 2
|
||||
0x70020000, // 0011 JMP #0013
|
||||
0x00080504, // 0012 ADD R2 R2 K4
|
||||
0x7001FFEE, // 0013 JMP #0003
|
||||
0x80000000, // 0014 RET 0
|
||||
( &(const binstruction[26]) { /* code */
|
||||
0x880C0100, // 0000 GETMBR R3 R0 K0
|
||||
0x780E0016, // 0001 JMPF R3 #0019
|
||||
0x580C0001, // 0002 LDCONST R3 K1
|
||||
0x6010000C, // 0003 GETGBL R4 G12
|
||||
0x88140100, // 0004 GETMBR R5 R0 K0
|
||||
0x7C100200, // 0005 CALL R4 1
|
||||
0x14100604, // 0006 LT R4 R3 R4
|
||||
0x78120010, // 0007 JMPF R4 #0019
|
||||
0x88100100, // 0008 GETMBR R4 R0 K0
|
||||
0x94100803, // 0009 GETIDX R4 R4 R3
|
||||
0x88100902, // 000A GETMBR R4 R4 K2
|
||||
0x1C100801, // 000B EQ R4 R4 R1
|
||||
0x78120009, // 000C JMPF R4 #0017
|
||||
0x88100100, // 000D GETMBR R4 R0 K0
|
||||
0x94100803, // 000E GETIDX R4 R4 R3
|
||||
0x88100903, // 000F GETMBR R4 R4 K3
|
||||
0x1C100802, // 0010 EQ R4 R4 R2
|
||||
0x78120004, // 0011 JMPF R4 #0017
|
||||
0x88100100, // 0012 GETMBR R4 R0 K0
|
||||
0x8C100904, // 0013 GETMET R4 R4 K4
|
||||
0x5C180600, // 0014 MOVE R6 R3
|
||||
0x7C100400, // 0015 CALL R4 2
|
||||
0x70020000, // 0016 JMP #0018
|
||||
0x000C0705, // 0017 ADD R3 R3 K5
|
||||
0x7001FFE9, // 0018 JMP #0003
|
||||
0x80000000, // 0019 RET 0
|
||||
})
|
||||
)
|
||||
);
|
||||
@ -1550,8 +1556,8 @@ be_local_closure(Tasmota_add_cmd, /* name */
|
||||
********************************************************************/
|
||||
be_local_closure(Tasmota_add_rule, /* name */
|
||||
be_nested_proto(
|
||||
9, /* nstack */
|
||||
3, /* argc */
|
||||
10, /* nstack */
|
||||
4, /* argc */
|
||||
2, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
@ -1563,36 +1569,37 @@ be_local_closure(Tasmota_add_rule, /* name */
|
||||
/* K1 */ be_nested_str(_rules),
|
||||
/* K2 */ be_nested_str(function),
|
||||
/* K3 */ be_nested_str(push),
|
||||
/* K4 */ be_nested_str(kv),
|
||||
/* K4 */ be_nested_str(Trigger),
|
||||
/* K5 */ be_nested_str(value_error),
|
||||
/* K6 */ be_nested_str(the_X20second_X20argument_X20is_X20not_X20a_X20function),
|
||||
}),
|
||||
&be_const_str_add_rule,
|
||||
&be_const_str_solidified,
|
||||
( &(const binstruction[23]) { /* code */
|
||||
0x8C0C0100, // 0000 GETMET R3 R0 K0
|
||||
0x5C140400, // 0001 MOVE R5 R2
|
||||
0x7C0C0400, // 0002 CALL R3 2
|
||||
0x880C0101, // 0003 GETMBR R3 R0 K1
|
||||
0x740E0002, // 0004 JMPT R3 #0008
|
||||
0x600C0012, // 0005 GETGBL R3 G18
|
||||
0x7C0C0000, // 0006 CALL R3 0
|
||||
0x90020203, // 0007 SETMBR R0 K1 R3
|
||||
0x600C0004, // 0008 GETGBL R3 G4
|
||||
0x5C100400, // 0009 MOVE R4 R2
|
||||
0x7C0C0200, // 000A CALL R3 1
|
||||
0x1C0C0702, // 000B EQ R3 R3 K2
|
||||
0x780E0007, // 000C JMPF R3 #0015
|
||||
0x880C0101, // 000D GETMBR R3 R0 K1
|
||||
0x8C0C0703, // 000E GETMET R3 R3 K3
|
||||
0x8C140104, // 000F GETMET R5 R0 K4
|
||||
( &(const binstruction[24]) { /* code */
|
||||
0x8C100100, // 0000 GETMET R4 R0 K0
|
||||
0x5C180400, // 0001 MOVE R6 R2
|
||||
0x7C100400, // 0002 CALL R4 2
|
||||
0x88100101, // 0003 GETMBR R4 R0 K1
|
||||
0x74120002, // 0004 JMPT R4 #0008
|
||||
0x60100012, // 0005 GETGBL R4 G18
|
||||
0x7C100000, // 0006 CALL R4 0
|
||||
0x90020204, // 0007 SETMBR R0 K1 R4
|
||||
0x60100004, // 0008 GETGBL R4 G4
|
||||
0x5C140400, // 0009 MOVE R5 R2
|
||||
0x7C100200, // 000A CALL R4 1
|
||||
0x1C100902, // 000B EQ R4 R4 K2
|
||||
0x78120008, // 000C JMPF R4 #0016
|
||||
0x88100101, // 000D GETMBR R4 R0 K1
|
||||
0x8C100903, // 000E GETMET R4 R4 K3
|
||||
0xB81A0800, // 000F GETNGBL R6 K4
|
||||
0x5C1C0200, // 0010 MOVE R7 R1
|
||||
0x5C200400, // 0011 MOVE R8 R2
|
||||
0x7C140600, // 0012 CALL R5 3
|
||||
0x7C0C0400, // 0013 CALL R3 2
|
||||
0x70020000, // 0014 JMP #0016
|
||||
0xB0060B06, // 0015 RAISE 1 K5 K6
|
||||
0x80000000, // 0016 RET 0
|
||||
0x5C240600, // 0012 MOVE R9 R3
|
||||
0x7C180600, // 0013 CALL R6 3
|
||||
0x7C100400, // 0014 CALL R4 2
|
||||
0x70020000, // 0015 JMP #0017
|
||||
0xB0060B06, // 0016 RAISE 1 K5 K6
|
||||
0x80000000, // 0017 RET 0
|
||||
})
|
||||
)
|
||||
);
|
||||
@ -1622,8 +1629,8 @@ be_local_closure(Tasmota_exec_rules, /* name */
|
||||
/* K6 */ be_const_int(3),
|
||||
/* K7 */ be_const_int(0),
|
||||
/* K8 */ be_nested_str(try_rule),
|
||||
/* K9 */ be_nested_str(k),
|
||||
/* K10 */ be_nested_str(v),
|
||||
/* K9 */ be_nested_str(trig),
|
||||
/* K10 */ be_nested_str(f),
|
||||
/* K11 */ be_const_int(1),
|
||||
}),
|
||||
&be_const_str_exec_rules,
|
||||
@ -1907,7 +1914,7 @@ be_local_closure(Tasmota_set_timer, /* name */
|
||||
/* K0 */ be_nested_str(check_not_method),
|
||||
/* K1 */ be_nested_str(_timers),
|
||||
/* K2 */ be_nested_str(push),
|
||||
/* K3 */ be_nested_str(Timer),
|
||||
/* K3 */ be_nested_str(Trigger),
|
||||
/* K4 */ be_nested_str(millis),
|
||||
}),
|
||||
&be_const_str_set_timer,
|
||||
|
@ -1,18 +1,18 @@
|
||||
/********************************************************************
|
||||
* Tasmota lib
|
||||
*
|
||||
* class Timer
|
||||
* class Trigger
|
||||
*******************************************************************/
|
||||
#include "be_constobj.h"
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: tostring
|
||||
********************************************************************/
|
||||
be_local_closure(Timer_tostring, /* name */
|
||||
be_local_closure(Trigger_tostring, /* name */
|
||||
be_nested_proto(
|
||||
10, /* nstack */
|
||||
1, /* argc */
|
||||
0, /* varg */
|
||||
2, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
@ -22,7 +22,7 @@ be_local_closure(Timer_tostring, /* name */
|
||||
/* K0 */ be_nested_str(string),
|
||||
/* K1 */ be_nested_str(format),
|
||||
/* K2 */ be_nested_str(_X3Cinstance_X3A_X20_X25s_X28_X25s_X2C_X20_X25s_X2C_X20_X25s_X29),
|
||||
/* K3 */ be_nested_str(due),
|
||||
/* K3 */ be_nested_str(trig),
|
||||
/* K4 */ be_nested_str(f),
|
||||
/* K5 */ be_nested_str(id),
|
||||
}),
|
||||
@ -57,18 +57,18 @@ be_local_closure(Timer_tostring, /* name */
|
||||
/********************************************************************
|
||||
** Solidified function: init
|
||||
********************************************************************/
|
||||
be_local_closure(Timer_init, /* name */
|
||||
be_local_closure(Trigger_init, /* name */
|
||||
be_nested_proto(
|
||||
4, /* nstack */
|
||||
4, /* argc */
|
||||
0, /* varg */
|
||||
2, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[ 3]) { /* constants */
|
||||
/* K0 */ be_nested_str(due),
|
||||
/* K0 */ be_nested_str(trig),
|
||||
/* K1 */ be_nested_str(f),
|
||||
/* K2 */ be_nested_str(id),
|
||||
}),
|
||||
@ -86,25 +86,25 @@ be_local_closure(Timer_init, /* name */
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified class: Timer
|
||||
** Solidified class: Trigger
|
||||
********************************************************************/
|
||||
be_local_class(Timer,
|
||||
be_local_class(Trigger,
|
||||
3,
|
||||
NULL,
|
||||
be_nested_map(5,
|
||||
( (struct bmapnode*) &(const bmapnode[]) {
|
||||
{ be_const_key(tostring, 4), be_const_closure(Timer_tostring_closure) },
|
||||
{ be_const_key(tostring, 3), be_const_closure(Trigger_tostring_closure) },
|
||||
{ be_const_key(id, 2), be_const_var(2) },
|
||||
{ be_const_key(f, -1), be_const_var(1) },
|
||||
{ be_const_key(due, -1), be_const_var(0) },
|
||||
{ be_const_key(init, -1), be_const_closure(Timer_init_closure) },
|
||||
{ be_const_key(init, -1), be_const_closure(Trigger_init_closure) },
|
||||
{ be_const_key(trig, -1), be_const_var(0) },
|
||||
})),
|
||||
be_str_literal("Timer")
|
||||
be_str_literal("Trigger")
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
void be_load_Timer_class(bvm *vm) {
|
||||
be_pushntvclass(vm, &be_class_Timer);
|
||||
be_setglobal(vm, "Timer");
|
||||
void be_load_Trigger_class(bvm *vm) {
|
||||
be_pushntvclass(vm, &be_class_Trigger);
|
||||
be_setglobal(vm, "Trigger");
|
||||
be_pop(vm, 1);
|
||||
}
|
@ -1,17 +1,17 @@
|
||||
#- Native code used for testing and code solidification -#
|
||||
#- Do not use it -#
|
||||
|
||||
class Timer
|
||||
var due, f, id
|
||||
def init(due, f, id)
|
||||
self.due = due
|
||||
class Trigger
|
||||
var trig, f, id
|
||||
def init(trig, f, id)
|
||||
self.trig = trig
|
||||
self.f = f
|
||||
self.id = id
|
||||
end
|
||||
def tostring()
|
||||
import string
|
||||
return string.format("<instance: %s(%s, %s, %s)", str(classof(self)),
|
||||
str(self.due), str(self.f), str(self.id))
|
||||
str(self.trig), str(self.f), str(self.id))
|
||||
end
|
||||
end
|
||||
|
||||
@ -58,20 +58,6 @@ class Tasmota
|
||||
end
|
||||
end
|
||||
|
||||
# create a specific sub-class for rules: pattern(string) -> closure
|
||||
# Classs KV has two members k and v
|
||||
def kv(k, v)
|
||||
class KV
|
||||
var k, v
|
||||
def init(k,v)
|
||||
self.k = k
|
||||
self.v = v
|
||||
end
|
||||
end
|
||||
|
||||
return KV(k, v)
|
||||
end
|
||||
|
||||
# add `chars_in_string(s:string,c:string) -> int``
|
||||
# looks for any char in c, and return the position of the first char
|
||||
# or -1 if not found
|
||||
@ -130,23 +116,23 @@ class Tasmota
|
||||
end
|
||||
|
||||
# Rules
|
||||
def add_rule(pat,f)
|
||||
def add_rule(pat, f, id)
|
||||
self.check_not_method(f)
|
||||
if !self._rules
|
||||
self._rules=[]
|
||||
end
|
||||
if type(f) == 'function'
|
||||
self._rules.push(self.kv(pat, f))
|
||||
self._rules.push(Trigger(pat, f, id))
|
||||
else
|
||||
raise 'value_error', 'the second argument is not a function'
|
||||
end
|
||||
end
|
||||
|
||||
def remove_rule(pat)
|
||||
def remove_rule(pat, id)
|
||||
if self._rules
|
||||
var i = 0
|
||||
while i < size(self._rules)
|
||||
if self._rules[i].k == pat
|
||||
if self._rules[i].trig == pat && self._rules[i].id == id
|
||||
self._rules.remove(i) #- don't increment i since we removed the object -#
|
||||
else
|
||||
i += 1
|
||||
@ -214,8 +200,8 @@ class Tasmota
|
||||
if self._rules
|
||||
var i = 0
|
||||
while i < size(self._rules)
|
||||
var kv = self._rules[i]
|
||||
ret = self.try_rule(ev,kv.k,kv.v) || ret #- call should be first to avoid evaluation shortcut if ret is already true -#
|
||||
var tr = self._rules[i]
|
||||
ret = self.try_rule(ev,tr.trig,tr.f) || ret #- call should be first to avoid evaluation shortcut if ret is already true -#
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
@ -239,8 +225,8 @@ class Tasmota
|
||||
|
||||
var i = 0
|
||||
while i < size(self._rules)
|
||||
var kv = self._rules[i]
|
||||
ret = self.try_rule(ev,kv.k,kv.v) || ret #- call should be first to avoid evaluation shortcut -#
|
||||
var tr = self._rules[i]
|
||||
ret = self.try_rule(ev,tr.trig,tr.f) || ret #- call should be first to avoid evaluation shortcut -#
|
||||
i += 1
|
||||
end
|
||||
return ret
|
||||
@ -251,7 +237,7 @@ class Tasmota
|
||||
def set_timer(delay,f,id)
|
||||
self.check_not_method(f)
|
||||
if !self._timers self._timers=[] end
|
||||
self._timers.push(Timer(self.millis(delay),f,id))
|
||||
self._timers.push(Trigger(self.millis(delay),f,id))
|
||||
end
|
||||
|
||||
# run every 50ms tick
|
||||
@ -259,7 +245,7 @@ class Tasmota
|
||||
if self._timers
|
||||
var i=0
|
||||
while i<self._timers.size()
|
||||
if self.time_reached(self._timers[i].due)
|
||||
if self.time_reached(self._timers[i].trig)
|
||||
var f=self._timers[i].f
|
||||
self._timers.remove(i)
|
||||
f()
|
||||
|
@ -28,6 +28,15 @@ hue_bridge.init = def (m)
|
||||
self.lights.remove(id)
|
||||
end
|
||||
|
||||
# get id from light object
|
||||
def light_to_id(l)
|
||||
for id: self.lights.keys()
|
||||
if l == self.lights[id]['light']
|
||||
return id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# return the status of a single light by id
|
||||
def hue_status(id)
|
||||
import hue_ntv
|
||||
|
@ -89,8 +89,9 @@ lib_extra_dirs = ${library.lib_extra_dirs}
|
||||
|
||||
|
||||
[env:tasmota32_base]
|
||||
; *** Uncomment next line ";" to enable development Tasmota Arduino version ESP32
|
||||
;platform = https://github.com/Jason2866/platform-espressif32/releases/download/v2.0.2.1/platform-espressif32-2.0.2.1.zip
|
||||
; *** Uncomment next lines ";" to enable development Tasmota Arduino version ESP32
|
||||
;platform = https://github.com/Jason2866/platform-espressif32.git#IDF44/ESP32-S3
|
||||
;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/664/framework-arduinoespressif32-v4.4_dev-73c0f44528.tar.gz
|
||||
build_unflags = ${esp32_defaults.build_unflags}
|
||||
build_flags = ${esp32_defaults.build_flags}
|
||||
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Herzschlag"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 - RX"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 - TX"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Battito cardiaco"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 - SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 - RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "Kierunek wiatru"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -847,6 +847,8 @@
|
||||
#define D_SENSOR_HRG15_RX "HRG15 Rx"
|
||||
#define D_SENSOR_HRG15_TX "HRG15 Tx"
|
||||
#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING"
|
||||
#define D_SENSOR_BL6523_TX "BL6523 Tx"
|
||||
#define D_SENSOR_BL6523_RX "BL6523 Rx"
|
||||
#define D_SENSOR_HEARTBEAT "Heartbeat"
|
||||
#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK"
|
||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||
|
@ -1097,7 +1097,7 @@ void CmndSetoptionBase(bool indexed) {
|
||||
SettingsSave(2);
|
||||
}
|
||||
#ifdef USE_HOME_ASSISTANT
|
||||
if ((19 == pindex) || (30 == pindex)) {
|
||||
if ((19 == pindex) || (30 == pindex) || (114 == pindex)) {
|
||||
HAssDiscover(); // Delayed execution to provide enough resources during hass_discovery or hass_light
|
||||
}
|
||||
#endif // USE_HOME_ASSISTANT
|
||||
|
@ -509,13 +509,7 @@ void *special_calloc(size_t num, size_t size) {
|
||||
|
||||
// Variants for IRAM heap, which need all accesses to be 32 bits aligned
|
||||
void *special_malloc32(uint32_t size) {
|
||||
return heap_caps_malloc(size, UsePSRAM() ? MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT : MALLOC_CAP_32BIT);
|
||||
}
|
||||
void *special_realloc32(void *ptr, size_t size) {
|
||||
return heap_caps_realloc(ptr, size, UsePSRAM() ? MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT : MALLOC_CAP_32BIT);
|
||||
}
|
||||
void *special_calloc32(size_t num, size_t size) {
|
||||
return heap_caps_calloc(num, size, UsePSRAM() ? MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT : MALLOC_CAP_32BIT);
|
||||
return heap_caps_malloc(size, MALLOC_CAP_32BIT);
|
||||
}
|
||||
|
||||
float CpuTemperature(void) {
|
||||
|
@ -789,9 +789,11 @@ void ResponseAppendFeatures(void)
|
||||
feature8 |= 0x00100000; // xnrg_21_sdm230.ino
|
||||
#endif
|
||||
#ifdef USE_CM110x
|
||||
feature8 |= 0x00200000; // xsns_95_cm110x.ino
|
||||
feature8 |= 0x00200000; // xsns_95_cm110x.ino
|
||||
#endif
|
||||
#if defined(USE_ENERGY_SENSOR) && defined(USE_BL6523)
|
||||
feature8 |= 0x00400000; // xnrg_22_bl6523.ino
|
||||
#endif
|
||||
// feature8 |= 0x00400000;
|
||||
// feature8 |= 0x00800000;
|
||||
|
||||
// feature8 |= 0x01000000;
|
||||
|
@ -182,6 +182,7 @@ enum UserSelectablePins {
|
||||
GPIO_SDM230_TX, GPIO_SDM230_RX, // SDM230 Serial interface
|
||||
GPIO_ADC_MQ, // Analog MQ Sensor
|
||||
GPIO_CM11_TXD, GPIO_CM11_RXD, // CM11 Serial interface
|
||||
GPIO_BL6523_TX, GPIO_BL6523_RX, // BL6523 based Watt meter Serial interface
|
||||
GPIO_SENSOR_END };
|
||||
|
||||
enum ProgramSelectablePins {
|
||||
@ -403,6 +404,7 @@ const char kSensorNames[] PROGMEM =
|
||||
D_SENSOR_SDM230_TX "|" D_SENSOR_SDM230_RX "|"
|
||||
D_SENSOR_ADC_MQ "|"
|
||||
D_SENSOR_CM11_TX "|" D_SENSOR_CM11_RX "|"
|
||||
D_SENSOR_BL6523_TX "|" D_SENSOR_BL6523_RX "|"
|
||||
;
|
||||
|
||||
const char kSensorNamesFixed[] PROGMEM =
|
||||
@ -770,6 +772,10 @@ const uint16_t kGpioNiceList[] PROGMEM = {
|
||||
AGPIO(GPIO_SDM230_TX), // SDM230 Serial interface
|
||||
AGPIO(GPIO_SDM230_RX), // SDM230 Serial interface
|
||||
#endif
|
||||
#ifdef USE_BL6523
|
||||
AGPIO(GPIO_BL6523_TX), // BL6523 based Watt meter Serial interface
|
||||
AGPIO(GPIO_BL6523_RX), // BL6523 based Watt meter Serial interface
|
||||
#endif
|
||||
#endif // USE_ENERGY_SENSOR
|
||||
|
||||
/*-------------------------------------------------------------------------------------------*\
|
||||
|
@ -373,6 +373,17 @@ struct GVARS {
|
||||
int16_t strind;
|
||||
};
|
||||
|
||||
#ifdef USE_SCRIPT_SPI
|
||||
struct SCRIPT_SPI {
|
||||
int8_t sclk;
|
||||
int8_t mosi;
|
||||
int8_t miso;
|
||||
int8_t cs[4];
|
||||
SPIClass *spip;
|
||||
SPISettings settings;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#define NUM_RES 0xfe
|
||||
#define STR_RES 0xfd
|
||||
@ -454,6 +465,10 @@ struct SCRIPT_MEM {
|
||||
#endif
|
||||
float retval;
|
||||
char *retstr;
|
||||
#ifdef USE_SCRIPT_SPI
|
||||
struct SCRIPT_SPI spi;
|
||||
#endif
|
||||
|
||||
} glob_script_mem;
|
||||
|
||||
|
||||
@ -4005,6 +4020,96 @@ extern char *SML_GetSVal(uint32_t index);
|
||||
goto exit;
|
||||
}
|
||||
#endif //USE_SCRIPT_SERIAL
|
||||
|
||||
|
||||
#ifdef USE_SCRIPT_SPI
|
||||
if (!strncmp(lp, "spi(", 4)) {
|
||||
lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, 0);
|
||||
uint8_t sel = fvar;
|
||||
uint8_t index;
|
||||
switch (sel) {
|
||||
case 0:
|
||||
// set bus pins
|
||||
lp = GetNumericArgument(lp , OPER_EQU, &fvar, 0);
|
||||
glob_script_mem.spi.sclk = fvar;
|
||||
|
||||
if (glob_script_mem.spi.sclk < 0) {
|
||||
// attach to existing Tasmota SPI
|
||||
lp = GetNumericArgument(lp , OPER_EQU, &fvar, 0);
|
||||
fvar *= 1000000;
|
||||
glob_script_mem.spi.settings = SPISettings(fvar, MSBFIRST, SPI_MODE0);
|
||||
|
||||
if (TasmotaGlobal.spi_enabled) {
|
||||
#ifdef EPS8266
|
||||
SPI.begin();
|
||||
glob_script_mem.spi.spip = &SPI;
|
||||
#endif // EPS8266
|
||||
|
||||
#ifdef ESP32
|
||||
if (glob_script_mem.spi.sclk == -1) {
|
||||
SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1);
|
||||
glob_script_mem.spi.spip = &SPI;
|
||||
} else {
|
||||
glob_script_mem.spi.spip = new SPIClass(HSPI);
|
||||
glob_script_mem.spi.spip->begin(Pin(GPIO_SPI_CLK, 1), Pin(GPIO_SPI_MISO, 1), Pin(GPIO_SPI_MOSI, 1), -1);
|
||||
}
|
||||
|
||||
#endif // ESP32
|
||||
} else {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("error: spi pins not defined"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
pinMode(glob_script_mem.spi.sclk , OUTPUT);
|
||||
digitalWrite(glob_script_mem.spi.sclk , 0);
|
||||
|
||||
lp = GetNumericArgument(lp , OPER_EQU, &fvar, 0);
|
||||
glob_script_mem.spi.mosi = fvar;
|
||||
if (glob_script_mem.spi.mosi >= 0) {
|
||||
pinMode(glob_script_mem.spi.mosi , OUTPUT);
|
||||
digitalWrite(glob_script_mem.spi.mosi , 0);
|
||||
}
|
||||
|
||||
lp = GetNumericArgument(lp , OPER_EQU, &fvar, 0);
|
||||
glob_script_mem.spi.miso = fvar;
|
||||
if (glob_script_mem.spi.miso >= 0) {
|
||||
pinMode(glob_script_mem.spi.miso , INPUT_PULLUP);
|
||||
}
|
||||
|
||||
if (Is_gpio_used(glob_script_mem.spi.mosi) || Is_gpio_used(glob_script_mem.spi.miso)
|
||||
|| Is_gpio_used(glob_script_mem.spi.sclk) ) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("warning: pins already used"));
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// set cs
|
||||
lp = GetNumericArgument(lp , OPER_EQU, &fvar, 0);
|
||||
index = fvar;
|
||||
index &= 3;
|
||||
lp = GetNumericArgument(lp , OPER_EQU, &fvar, 0);
|
||||
glob_script_mem.spi.cs[index] = fvar;
|
||||
pinMode(glob_script_mem.spi.cs[index] , OUTPUT);
|
||||
digitalWrite(glob_script_mem.spi.cs[index] , 1);
|
||||
if (Is_gpio_used(glob_script_mem.spi.cs[index])) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("warning: pins already used"));
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// transfer bytes
|
||||
lp = GetNumericArgument(lp , OPER_EQU, &fvar, 0);
|
||||
uint8_t index = fvar;
|
||||
lp = GetNumericArgument(lp , OPER_EQU, &fvar, 0);
|
||||
uint32_t val = fvar;
|
||||
lp = GetNumericArgument(lp , OPER_EQU, &fvar, 0);
|
||||
script_sspi_trans(index & 3, val, fvar);
|
||||
break;
|
||||
}
|
||||
len = 0;
|
||||
goto exit;
|
||||
}
|
||||
#endif // USE_SCRIPT_SPI
|
||||
break;
|
||||
|
||||
case 't':
|
||||
@ -5402,7 +5507,7 @@ int16_t Run_script_sub(const char *type, int8_t tlen, struct GVARS *gv) {
|
||||
} else {
|
||||
glob_script_mem.retstr = 0;
|
||||
}
|
||||
section = 0;
|
||||
section = 99;
|
||||
goto next_line;
|
||||
} else if (!strncmp(lp, "break", 5)) {
|
||||
lp += 5;
|
||||
@ -5413,7 +5518,8 @@ int16_t Run_script_sub(const char *type, int8_t tlen, struct GVARS *gv) {
|
||||
}
|
||||
floop = 0;
|
||||
} else {
|
||||
section = 0;
|
||||
section = 99;
|
||||
// leave immediately
|
||||
}
|
||||
goto next_line;
|
||||
} else if (!strncmp(lp, "dp", 2) && isdigit(*(lp + 2))) {
|
||||
@ -5973,6 +6079,7 @@ int16_t Run_script_sub(const char *type, int8_t tlen, struct GVARS *gv) {
|
||||
}
|
||||
// next line
|
||||
next_line:
|
||||
if (section == 99) return 0;
|
||||
if (*lp==SCRIPT_EOL) {
|
||||
lp++;
|
||||
} else {
|
||||
@ -5990,6 +6097,55 @@ int16_t Run_script_sub(const char *type, int8_t tlen, struct GVARS *gv) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_SCRIPT_SPI
|
||||
// transfer 1-3 bytes
|
||||
uint32_t script_sspi_trans(uint32_t cs_index, uint32_t val, uint32_t size) {
|
||||
uint32_t out = 0;
|
||||
|
||||
digitalWrite(glob_script_mem.spi.cs[cs_index], 0);
|
||||
|
||||
if (glob_script_mem.spi.sclk < 0) {
|
||||
// use existing hardware spi
|
||||
glob_script_mem.spi.spip->beginTransaction(glob_script_mem.spi.settings);
|
||||
if (size == 1) {
|
||||
out = glob_script_mem.spi.spip->transfer(val);
|
||||
}
|
||||
if (size == 2) {
|
||||
out = glob_script_mem.spi.spip->transfer16(val);
|
||||
}
|
||||
if (size == 3) {
|
||||
out = glob_script_mem.spi.spip->transfer(val >> 16);
|
||||
out <<= 16;
|
||||
out |= glob_script_mem.spi.spip->transfer16(val);
|
||||
}
|
||||
//SPI.transferBytes();
|
||||
glob_script_mem.spi.spip->endTransaction();
|
||||
digitalWrite(glob_script_mem.spi.cs[cs_index], 1);
|
||||
return out;
|
||||
}
|
||||
|
||||
if (size < 1 || size > 3) size = 1;
|
||||
uint32_t bit = 1 << ((size * 8) - 1);
|
||||
while (bit) {
|
||||
digitalWrite(glob_script_mem.spi.sclk, 0);
|
||||
if (glob_script_mem.spi.mosi >= 0) {
|
||||
if (val & bit) digitalWrite(glob_script_mem.spi.mosi, 1);
|
||||
else digitalWrite(glob_script_mem.spi.mosi, 0);
|
||||
}
|
||||
digitalWrite(glob_script_mem.spi.sclk, 1);
|
||||
if (glob_script_mem.spi.miso >= 0) {
|
||||
if (digitalRead(glob_script_mem.spi.miso)) {
|
||||
out |= bit;
|
||||
}
|
||||
}
|
||||
bit >>= 1;
|
||||
}
|
||||
digitalWrite(glob_script_mem.spi.cs[cs_index], 1);
|
||||
return out;
|
||||
}
|
||||
#endif // USE_SCRIPT_SPI
|
||||
|
||||
#ifdef USE_SCRIPT_SERIAL
|
||||
bool Script_Close_Serial() {
|
||||
if (glob_script_mem.sp) {
|
||||
@ -6004,7 +6160,7 @@ bool Script_Close_Serial() {
|
||||
#endif //USE_SCRIPT_SERIAL
|
||||
|
||||
bool Is_gpio_used(uint8_t gpiopin) {
|
||||
if ((gpiopin < nitems(TasmotaGlobal.gpio_pin)) && (TasmotaGlobal.gpio_pin[gpiopin] > 0)) {
|
||||
if (gpiopin >= 0 && (gpiopin < nitems(TasmotaGlobal.gpio_pin)) && (TasmotaGlobal.gpio_pin[gpiopin] > 0)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -52,7 +52,8 @@ enum ZnpSubsystem {
|
||||
Z_SAPI = 0x06,
|
||||
Z_UTIL = 0x07,
|
||||
Z_DEBUG = 0x08,
|
||||
Z_APP = 0x09
|
||||
Z_APP = 0x09,
|
||||
Z_APP_CNF = 0x0F, // new in ZStacK 3
|
||||
};
|
||||
#endif // USE_ZIGBEE_ZNP
|
||||
|
||||
@ -1103,6 +1104,14 @@ enum Z_Util {
|
||||
Z_UTIL_ZCL_KEY_ESTABLISH_IND = 0xE1
|
||||
};
|
||||
|
||||
enum Z_App_Cnf {
|
||||
Z_APP_CNF_BDB_START_COMMISSIONING = 0x05,
|
||||
Z_APP_CNF_BDB_SET_CHANNEL = 0x08,
|
||||
Z_APP_CNF_BDB_SET_TC_REQUIRE_KEY_EXCHANGE = 0x09,
|
||||
Z_APP_CNF_BDB_COMMISSIONING_NOTIFICATION = 0x80,
|
||||
Z_APP_CNF_BDB_SET_NWK_FRAME_COUNTER = 0xFF,
|
||||
};
|
||||
|
||||
enum ZCL_Global_Commands {
|
||||
ZCL_READ_ATTRIBUTES = 0x00,
|
||||
ZCL_READ_ATTRIBUTES_RESPONSE = 0x01,
|
||||
|
@ -80,6 +80,7 @@ const uint8_t ZIGBEE_LABEL_INIT_DEVICE = 14; // Init ZNP as end-device
|
||||
const uint8_t ZIGBEE_LABEL_START_DEVICE = 15; // Start ZNP as end-device
|
||||
const uint8_t ZIGBEE_LABEL_START_ROUTER_DEVICE = 16; // Start common to router and device
|
||||
const uint8_t ZIGBEE_LABEL_ZB3_INIT = 17; // check parameters for ZB3
|
||||
const uint8_t ZIGBEE_LABEL_COORD_STARTED = 18; // Coordinator has started
|
||||
const uint8_t ZIGBEE_LABEL_FACT_RESET_ROUTER_DEVICE_POST = 19; // common post configuration for router and device
|
||||
const uint8_t ZIGBEE_LABEL_READY = 20; // goto label 20 for main loop
|
||||
const uint8_t ZIGBEE_LABEL_MAIN_LOOP = 21; // main loop
|
||||
|
@ -223,6 +223,16 @@ const uint32_t ZB_ALL_CHANNELS = 0x07FFF800;
|
||||
ZBR(ZBS_W_ALL_CHANN, Z_SREQ | Z_SYS, SYS_OSAL_NV_WRITE, CONF_CHANLIST,0x00, 0x00, 0x04 /* len */,
|
||||
Z_B0(ZB_ALL_CHANNELS), Z_B1(ZB_ALL_CHANNELS), Z_B2(ZB_ALL_CHANNELS), Z_B3(ZB_ALL_CHANNELS),
|
||||
/*0x00, 0x08, 0x00, 0x00*/ ) // 21098400000400F8FF7F
|
||||
|
||||
// Configure BDB Channels
|
||||
ZBR(ZBS_W_BDB_CHANN, Z_SREQ | Z_APP_CNF, Z_APP_CNF_BDB_SET_CHANNEL, 0x01 /*primary*/,
|
||||
Z_B0(USE_ZIGBEE_CHANNEL_MASK), Z_B1(USE_ZIGBEE_CHANNEL_MASK), Z_B2(USE_ZIGBEE_CHANNEL_MASK), Z_B3(USE_ZIGBEE_CHANNEL_MASK),
|
||||
/*0x00, 0x08, 0x00, 0x00*/ ) // 2F0801xxxxxxxx
|
||||
// Configure BDB Channels secondary channel to zeroes
|
||||
ZBM(ZBS_W_BDB_CHANN2, Z_SREQ | Z_APP_CNF, Z_APP_CNF_BDB_SET_CHANNEL, 0x00 /*secondary*/,
|
||||
0x00, 0x08, 0x00, 0x00 ) // 2F080000000000
|
||||
ZBM(ZBR_W_BDB_CHANN_OK, Z_SRSP | Z_APP_CNF, Z_APP_CNF_BDB_SET_CHANNEL, Z_SUCCESS ) // 6F0800
|
||||
|
||||
// Write Logical Type = 00 = coordinator
|
||||
ZBM(ZBS_W_LOGTYP_COORD, Z_SREQ | Z_SYS, SYS_OSAL_NV_WRITE, CONF_LOGICAL_TYPE,0x00, 0x00, 0x01 /* len */, 0x00 ) // 21098700000100
|
||||
// Write Logical Type = 01 = router
|
||||
@ -263,6 +273,10 @@ ZBM(AREQ_STARTUPFROMAPP, Z_AREQ | Z_ZDO, ZDO_STATE_CHANGE_IND ) // 45C00xx -
|
||||
ZBM(AREQ_STARTUPFROMAPP_COORD, Z_AREQ | Z_ZDO, ZDO_STATE_CHANGE_IND, ZDO_DEV_ZB_COORD ) // 45C009 + 08 = starting, 09 = started
|
||||
ZBM(AREQ_STARTUPFROMAPP_ROUTER, Z_AREQ | Z_ZDO, ZDO_STATE_CHANGE_IND, ZDO_DEV_ROUTER ) // 45C009 + 02 = looking PanID, 07 = started
|
||||
ZBM(AREQ_STARTUPFROMAPP_DEVICE, Z_AREQ | Z_ZDO, ZDO_STATE_CHANGE_IND, ZDO_DEV_END_DEVICE ) // 45C009 + 02 = looking PanID, 06 = started
|
||||
// BDB START Commissioning
|
||||
ZBM(ZBS_BDB_START_COMMIS, Z_SREQ | Z_APP_CNF, Z_APP_CNF_BDB_START_COMMISSIONING, 0x04 /*mode*/) // 2F0504
|
||||
ZBM(ZBR_BDB_START_COMMIS, Z_SRSP | Z_APP_CNF, Z_APP_CNF_BDB_START_COMMISSIONING, Z_SUCCESS) // 6F0500
|
||||
|
||||
// GetDeviceInfo
|
||||
ZBM(ZBS_GETDEVICEINFO, Z_SREQ | Z_UTIL, Z_UTIL_GET_DEVICE_INFO ) // 2700
|
||||
ZBM(ZBR_GETDEVICEINFO, Z_SRSP | Z_UTIL, Z_UTIL_GET_DEVICE_INFO, Z_SUCCESS ) // Ex= 6700.00.6263151D004B1200.0000.07.09.00
|
||||
@ -296,8 +310,10 @@ ZBM(AREQ_ZDO_NODEDESCRSP, Z_AREQ | Z_ZDO, ZDO_NODE_DESC_RSP) // 4582
|
||||
// Z_ZDO:activeEpReq
|
||||
ZBM(ZBS_ZDO_ACTIVEEPREQ, Z_SREQ | Z_ZDO, ZDO_ACTIVE_EP_REQ, 0x00, 0x00, 0x00, 0x00) // 250500000000
|
||||
ZBM(ZBR_ZDO_ACTIVEEPREQ, Z_SRSP | Z_ZDO, ZDO_ACTIVE_EP_REQ, Z_SUCCESS) // 65050000
|
||||
ZBM(ZBR_ZDO_ACTIVEEPRSP_NONE, Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP, 0x00, 0x00 /* srcAddr */, Z_SUCCESS,
|
||||
0x00, 0x00 /* nwkaddr */, 0x00 /* activeepcount */) // 45050000 - no Ep running
|
||||
// ZBM(ZBR_ZDO_ACTIVEEPRSP_NONE, Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP, 0x00, 0x00 /* srcAddr */, Z_SUCCESS,
|
||||
// 0x00, 0x00 /* nwkaddr */, 0x00 /* activeepcount */) // 45050000 - no Ep running
|
||||
// Change #14819 - we now allow some EP to be alreaady declared
|
||||
ZBM(ZBR_ZDO_ACTIVEEPRSP_SUCESS, Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP, 0x00, 0x00 /* srcAddr */, Z_SUCCESS) // 45050000xxxx - no Ep running
|
||||
ZBM(ZBR_ZDO_ACTIVEEPRSP_OK, Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP, 0x00, 0x00 /* srcAddr */, Z_SUCCESS,
|
||||
0x00, 0x00 /* nwkaddr */, 0x02 /* activeepcount */, 0x0B, 0x01 /* the actual endpoints */) // 25050000 - no Ep running
|
||||
|
||||
@ -371,6 +387,10 @@ void ZNP_UpdateConfig(uint8_t zb_channel, uint16_t zb_pan_id, uint64_t zb_ext_pa
|
||||
ZBW(ZBS_W_CHANN, Z_SREQ | Z_SYS, SYS_OSAL_NV_WRITE, CONF_CHANLIST,0x00, 0x00, 0x04 /* len */,
|
||||
Z_B0(zb_channel_mask), Z_B1(zb_channel_mask), Z_B2(zb_channel_mask), Z_B3(zb_channel_mask),
|
||||
/*0x00, 0x08, 0x00, 0x00*/ ) // 210984000004xxxxxxxx
|
||||
// Write BDB Channel ID - ZStack3 specific
|
||||
ZBW(ZBS_W_BDB_CHANN, Z_SREQ | Z_APP_CNF, Z_APP_CNF_BDB_SET_CHANNEL, 0x01 /*primary*/,
|
||||
Z_B0(zb_channel_mask), Z_B1(zb_channel_mask), Z_B2(zb_channel_mask), Z_B3(zb_channel_mask),
|
||||
/*0x00, 0x08, 0x00, 0x00*/ ) // 2F0801xxxxxxxx
|
||||
// Write precfgkey
|
||||
ZBW(ZBS_W_PFGK, Z_SREQ | Z_SYS, SYS_OSAL_NV_WRITE, CONF_PRECFGKEY,0x00, 0x00,
|
||||
0x10 /* len */,
|
||||
@ -401,7 +421,7 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
|
||||
ZI_WAIT(15500) // wait for 15 seconds for Tasmota to stabilize
|
||||
|
||||
//ZI_MQTT_STATE(ZIGBEE_STATUS_BOOT, "Booting")
|
||||
ZI_LOG(LOG_LEVEL_INFO, D_LOG_ZIGBEE "rebooting CC2530 device")
|
||||
ZI_LOG(LOG_LEVEL_INFO, D_LOG_ZIGBEE "rebooting ZNP device")
|
||||
|
||||
ZI_CALL(&ZNP_Reset_Device, 0) // LOW = reset
|
||||
ZI_WAIT(100) // wait for .1 second
|
||||
@ -434,34 +454,54 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
|
||||
ZI_SEND(ZBS_PFGKEN) // check PFGKEN
|
||||
ZI_WAIT_RECV(1000, ZBR_PFGKEN)
|
||||
|
||||
ZI_LABEL(ZIGBEE_LABEL_START_COORD)
|
||||
// Check if the MCU is running ZStack3, it so goto ZIGBEE_LABEL_ZB3_INIT, or continue
|
||||
ZI_CALL(&Z_GotoZB3, ZIGBEE_LABEL_ZB3_INIT)
|
||||
// ======================================================================
|
||||
// Start procedure for ZStack 1.2
|
||||
// ======================================================================
|
||||
ZI_SEND(ZBS_PFGK) // check PFGK on ZB1.2
|
||||
ZI_WAIT_RECV(1000, ZBR_PFGK)
|
||||
ZI_GOTO(ZIGBEE_LABEL_START_COORD)
|
||||
|
||||
ZI_LABEL(ZIGBEE_LABEL_ZB3_INIT)
|
||||
ZI_SEND(ZBS_PFGK3) // check PFGK on ZB3
|
||||
ZI_WAIT_RECV(1000, ZBR_PFGK3)
|
||||
//ZI_LOG(LOG_LEVEL_INFO, D_LOG_ZIGBEE "zigbee configuration ok")
|
||||
// all is good, we can start
|
||||
|
||||
ZI_LABEL(ZIGBEE_LABEL_START_COORD) // START ZNP App
|
||||
ZI_MQTT_STATE(ZIGBEE_STATUS_STARTING, kConfiguredCoord)
|
||||
ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_ABORT)
|
||||
// Z_ZDO:startupFromApp
|
||||
//ZI_LOG(LOG_LEVEL_INFO, D_LOG_ZIGBEE "starting zigbee coordinator")
|
||||
ZI_SEND(ZBS_STARTUPFROMAPP) // start coordinator
|
||||
ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_ABORT) // set any failure to ABORT
|
||||
ZI_SEND(ZBS_STARTUPFROMAPP) // start coordinator
|
||||
ZI_WAIT_RECV(5000, ZBR_STARTUPFROMAPP) // wait for sync ack of command
|
||||
ZI_WAIT_UNTIL_FUNC(20000, AREQ_STARTUPFROMAPP, &ZNP_ReceiveStateChange) // wait for async message that coordinator started, max 20s
|
||||
ZI_GOTO(ZIGBEE_LABEL_COORD_STARTED)
|
||||
|
||||
// ======================================================================
|
||||
// Start procedure for ZStack 3
|
||||
// ======================================================================
|
||||
ZI_LABEL(ZIGBEE_LABEL_ZB3_INIT)
|
||||
ZI_SEND(ZBS_PFGK3) // check PFGK on ZB3
|
||||
ZI_WAIT_RECV(1000, ZBR_PFGK3)
|
||||
|
||||
ZI_MQTT_STATE(ZIGBEE_STATUS_STARTING, kConfiguredCoord)
|
||||
ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_ABORT) // set any failure to ABORT
|
||||
// Set channel mask for primary and secondary, using BDB_SET_CHANNEL
|
||||
ZI_SEND(ZBS_W_BDB_CHANN) // set channel for primary network
|
||||
ZI_WAIT_RECV(2000, ZBR_W_BDB_CHANN_OK)
|
||||
ZI_SEND(ZBS_W_BDB_CHANN2) // no channel for secondary network
|
||||
ZI_WAIT_RECV(2000, ZBR_W_BDB_CHANN_OK)
|
||||
// all is good, we can start
|
||||
ZI_SEND(ZBS_BDB_START_COMMIS) // start coordinator
|
||||
ZI_WAIT_RECV(5000, ZBR_BDB_START_COMMIS) // wait for sync ack of command
|
||||
ZI_WAIT_UNTIL_FUNC(20000, AREQ_STARTUPFROMAPP, &ZNP_ReceiveStateChange) // wait for async message that coordinator started, max 20s
|
||||
|
||||
// ======================================================================
|
||||
// Coordinator has started, to post-configuration
|
||||
// ======================================================================
|
||||
ZI_LABEL(ZIGBEE_LABEL_COORD_STARTED) // Coordinator has started
|
||||
ZI_SEND(ZBS_GETDEVICEINFO) // GetDeviceInfo
|
||||
ZI_WAIT_RECV_FUNC(2000, ZBR_GETDEVICEINFO, &ZNP_ReceiveDeviceInfo)
|
||||
//ZI_WAIT_RECV(2000, ZBR_GETDEVICEINFO) // memorize info
|
||||
ZI_SEND(ZBS_ZDO_NODEDESCREQ) // Z_ZDO:nodeDescReq
|
||||
ZI_WAIT_RECV(1000, ZBR_ZDO_NODEDESCREQ)
|
||||
ZI_WAIT_UNTIL(5000, AREQ_ZDO_NODEDESCRSP)
|
||||
ZI_SEND(ZBS_ZDO_ACTIVEEPREQ) // Z_ZDO:activeEpReq
|
||||
ZI_WAIT_RECV(1000, ZBR_ZDO_ACTIVEEPREQ)
|
||||
ZI_WAIT_UNTIL(1000, ZBR_ZDO_ACTIVEEPRSP_NONE)
|
||||
ZI_WAIT_UNTIL(1000, ZBR_ZDO_ACTIVEEPRSP_SUCESS)
|
||||
ZI_SEND(ZBS_AF_REGISTER01) // Z_AF register for endpoint 01, profile 0x0104 Home Automation
|
||||
ZI_WAIT_RECV(1000, ZBR_AF_REGISTER)
|
||||
ZI_SEND(ZBS_AF_REGISTER0B) // Z_AF register for endpoint 0B, profile 0x0104 Home Automation
|
||||
@ -495,6 +535,9 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
|
||||
ZI_WAIT_FOREVER()
|
||||
ZI_GOTO(ZIGBEE_LABEL_READY)
|
||||
|
||||
// ======================================================================
|
||||
// Wrong configuration, do a factory reset and push configuration
|
||||
// ======================================================================
|
||||
ZI_LABEL(ZIGBEE_LABEL_FACT_RESET_COORD) // reformat device
|
||||
ZI_MQTT_STATE(ZIGBEE_STATUS_RESET_CONF, kResetting)
|
||||
//ZI_LOG(LOG_LEVEL_INFO, D_LOG_ZIGBEE "zigbee bad configuration of device, doing a factory reset")
|
||||
|
@ -51,7 +51,7 @@ void EZ_RSTACK(uint8_t reset_code) {
|
||||
default: reason_str = PSTR("Unknown"); break;
|
||||
}
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{"
|
||||
"\"Status\":%d,\"Message\":\"EFR32 booted\",\"RestartReason\":\"%s\""
|
||||
"\"Status\":%d,\"Message\":\"EFR32 EZSP booted\",\"RestartReason\":\"%s\""
|
||||
",\"Code\":%d}}"),
|
||||
ZIGBEE_STATUS_BOOT, reason_str, reset_code);
|
||||
|
||||
@ -418,7 +418,7 @@ int32_t ZNP_Reboot(int32_t res, SBuffer &buf) {
|
||||
}
|
||||
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{"
|
||||
"\"Status\":%d,\"Message\":\"CCxxxx booted\",\"RestartReason\":\"%s\""
|
||||
"\"Status\":%d,\"Message\":\"CCxxxx ZNP booted\",\"RestartReason\":\"%s\""
|
||||
",\"MajorRel\":%d,\"MinorRel\":%d}}"),
|
||||
ZIGBEE_STATUS_BOOT, reason_str,
|
||||
major_rel, minor_rel);
|
||||
|
@ -178,7 +178,7 @@ bool Xdrv29(uint8_t function)
|
||||
DeepSleepEverySecond();
|
||||
break;
|
||||
case FUNC_AFTER_TELEPERIOD:
|
||||
if (DeepSleepEnabled() && !deepsleep_flag) {
|
||||
if (DeepSleepEnabled() && !deepsleep_flag && (Settings->tele_period == 10 || Settings->tele_period == 300 || millis() > 20000 )) {
|
||||
deepsleep_flag = DEEPSLEEP_START_COUNTDOWN; // Start deepsleep in 4 seconds
|
||||
}
|
||||
break;
|
||||
|
@ -41,11 +41,11 @@ IPAddress ip_filter;
|
||||
TasmotaSerial *TCPSerial = nullptr;
|
||||
|
||||
const char kTCPCommands[] PROGMEM = "TCP" "|" // prefix
|
||||
"Start" "|" "Baudrate" "|" "Config"
|
||||
"Start" "|" "Baudrate" "|" "Config" "|" "Connect"
|
||||
;
|
||||
|
||||
void (* const TCPCommand[])(void) PROGMEM = {
|
||||
&CmndTCPStart, &CmndTCPBaudrate, &CmndTCPConfig
|
||||
&CmndTCPStart, &CmndTCPBaudrate, &CmndTCPConfig, &CmndTCPConnect
|
||||
};
|
||||
|
||||
//
|
||||
@ -216,6 +216,45 @@ void CmndTCPConfig(void) {
|
||||
ResponseCmndChar_P(GetSerialConfig(0x7F & Settings->tcp_config).c_str());
|
||||
}
|
||||
|
||||
//
|
||||
// Command `Connect`
|
||||
// Params: port,<IPv4>
|
||||
//
|
||||
void CmndTCPConnect(void) {
|
||||
int32_t tcp_port = XdrvMailbox.payload;
|
||||
|
||||
if (ArgC() == 2) {
|
||||
char sub_string[XdrvMailbox.data_len];
|
||||
WiFiClient new_client;
|
||||
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_TCP "Connecting to %s on port %d"), ArgV(sub_string, 2),tcp_port);
|
||||
if (new_client.connect(ArgV(sub_string, 2),tcp_port)) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_TCP "connected!"));
|
||||
} else {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_TCP "error connecting!"));
|
||||
}
|
||||
|
||||
// find an empty slot
|
||||
uint32_t i;
|
||||
for (i=0; i<nitems(client_tcp); i++) {
|
||||
WiFiClient &client = client_tcp[i];
|
||||
if (!client) {
|
||||
client = new_client;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= nitems(client_tcp)) {
|
||||
i = client_next++ % nitems(client_tcp);
|
||||
WiFiClient &client = client_tcp[i];
|
||||
client.stop();
|
||||
client = new_client;
|
||||
}
|
||||
} else {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_TCP "Usage: port,ip_address"));
|
||||
}
|
||||
|
||||
ResponseCmndDone();
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
89
tasmota/xdrv_52_3_berry_mqtt.ino
Normal file
89
tasmota/xdrv_52_3_berry_mqtt.ino
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
xdrv_52_3_berry_mqtt.ino - Berry scripting language, native fucnctions
|
||||
|
||||
Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Mappgin from internal light and a generic `light_state` Berry class
|
||||
|
||||
#ifdef USE_BERRY
|
||||
|
||||
#include "berry.h"
|
||||
|
||||
// Berry: `tasmota.publish(topic, payload [, retain:bool, start:int, len:int]) -> nil``
|
||||
// is_method is true if called from Tasmota class, false if called from mqtt module
|
||||
int32_t be_mqtt_publish(struct bvm *vm, bool is_method) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top >= 2+is_method && be_isstring(vm, 1+is_method) && (be_isstring(vm, 2+is_method) || be_isbytes(vm, 2+is_method))) { // 2 mandatory string arguments
|
||||
bool retain = false;
|
||||
int32_t payload_start = 0;
|
||||
int32_t len = -1; // send all of it
|
||||
if (top >= 3+is_method) { retain = be_tobool(vm, 3+is_method); }
|
||||
if (top >= 4+is_method) {
|
||||
payload_start = be_toint(vm, 4+is_method);
|
||||
if (payload_start < 0) payload_start = 0;
|
||||
}
|
||||
if (top >= 5+is_method) { len = be_toint(vm, 5+is_method); }
|
||||
const char * topic = be_tostring(vm, 1+is_method);
|
||||
const char * payload = nullptr;
|
||||
size_t payload_len = 0;
|
||||
|
||||
if (be_isstring(vm, 2+is_method)) {
|
||||
payload = be_tostring(vm, 2+is_method);
|
||||
payload_len = strlen(payload);
|
||||
} else {
|
||||
payload = (const char *) be_tobytes(vm, 2+is_method, &payload_len);
|
||||
}
|
||||
if (!payload) { be_raise(vm, "value_error", "Empty payload"); }
|
||||
|
||||
// adjust start and len
|
||||
if (payload_start >= payload_len) { len = 0; } // send empty packet
|
||||
else if (len < 0) { len = payload_len - payload_start; } // send all packet, adjust len
|
||||
else if (payload_start + len > payload_len) { len = payload_len - payload_start; } // len is too long, adjust
|
||||
// adjust start
|
||||
payload = payload + payload_start;
|
||||
|
||||
be_pop(vm, be_top(vm)); // clear stack to avoid any indirect warning message in subsequent calls to Berry
|
||||
|
||||
MqttPublishPayload(topic, payload, len, retain);
|
||||
|
||||
be_return_nil(vm); // Return
|
||||
}
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
int32_t l_publish(struct bvm *vm);
|
||||
int32_t l_publish(struct bvm *vm) {
|
||||
return be_mqtt_publish(vm, true);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t be_mqtt_publish(struct bvm *vm) {
|
||||
return be_mqtt_publish(vm, false);
|
||||
}
|
||||
|
||||
void be_mqtt_subscribe(const char* topic) {
|
||||
if (!topic) { return; }
|
||||
MqttSubscribe(topic);
|
||||
}
|
||||
|
||||
void be_mqtt_unsubscribe(const char* topic) {
|
||||
if (!topic) { return; }
|
||||
MqttUnsubscribe(topic);
|
||||
}
|
||||
|
||||
#endif // USE_BERRY
|
@ -68,49 +68,6 @@ const uint32_t BERRY_MAX_REPL_LOGS = 1024; // max number of print output recor
|
||||
*
|
||||
\*********************************************************************************************/
|
||||
extern "C" {
|
||||
// Berry: `tasmota.publish(topic, payload [, retain:bool, start:int, len:int]) -> nil``
|
||||
//
|
||||
int32_t l_publish(struct bvm *vm);
|
||||
int32_t l_publish(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top >= 3 && be_isstring(vm, 2) && (be_isstring(vm, 3) || be_isbytes(vm, 3))) { // 2 mandatory string arguments
|
||||
bool retain = false;
|
||||
int32_t payload_start = 0;
|
||||
int32_t len = -1; // send all of it
|
||||
if (top >= 4) { retain = be_tobool(vm, 4); }
|
||||
if (top >= 5) {
|
||||
payload_start = be_toint(vm, 5);
|
||||
if (payload_start < 0) payload_start = 0;
|
||||
}
|
||||
if (top >= 6) { len = be_toint(vm, 6); }
|
||||
const char * topic = be_tostring(vm, 2);
|
||||
const char * payload = nullptr;
|
||||
size_t payload_len = 0;
|
||||
|
||||
if (be_isstring(vm, 3)) {
|
||||
payload = be_tostring(vm, 3);
|
||||
payload_len = strlen(payload);
|
||||
} else {
|
||||
payload = (const char *) be_tobytes(vm, 3, &payload_len);
|
||||
}
|
||||
if (!payload) { be_raise(vm, "value_error", "Empty payload"); }
|
||||
|
||||
// adjust start and len
|
||||
if (payload_start >= payload_len) { len = 0; } // send empty packet
|
||||
else if (len < 0) { len = payload_len - payload_start; } // send all packet, adjust len
|
||||
else if (payload_start + len > payload_len) { len = payload_len - payload_start; } // len is too long, adjust
|
||||
// adjust start
|
||||
payload = payload + payload_start;
|
||||
|
||||
be_pop(vm, be_top(vm)); // clear stack to avoid any indirect warning message in subsequent calls to Berry
|
||||
|
||||
MqttPublishPayload(topic, payload, len, retain);
|
||||
|
||||
be_return_nil(vm); // Return
|
||||
}
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
// Berry: `tasmota.publish_result(payload:string, subtopic:string) -> nil``
|
||||
//
|
||||
int32_t l_publish_result(struct bvm *vm);
|
||||
@ -220,11 +177,10 @@ extern "C" {
|
||||
if (UsePSRAM()) {
|
||||
be_map_insert_int(vm, "psram", ESP.getPsramSize() / 1024);
|
||||
be_map_insert_int(vm, "psram_free", ESP.getFreePsram() / 1024);
|
||||
} else {
|
||||
// IRAM information
|
||||
int32_t iram_free = (int32_t)heap_caps_get_free_size(MALLOC_CAP_32BIT) - (int32_t)heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
be_map_insert_int(vm, "iram_free", iram_free / 1024);
|
||||
}
|
||||
// IRAM information
|
||||
int32_t iram_free = (int32_t)heap_caps_get_free_size(MALLOC_CAP_32BIT) - (int32_t)heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
be_map_insert_int(vm, "iram_free", iram_free / 1024);
|
||||
be_pop(vm, 1);
|
||||
be_return(vm);
|
||||
}
|
||||
|
@ -89,21 +89,7 @@ extern "C" {
|
||||
#ifdef USE_BERRY_IRAM
|
||||
return special_malloc32(size);
|
||||
#else
|
||||
return special_malloc(size);
|
||||
#endif
|
||||
}
|
||||
void *berry_realloc32(void *ptr, size_t size) {
|
||||
#ifdef USE_BERRY_IRAM
|
||||
return special_realloc32(ptr, size);
|
||||
#else
|
||||
return special_realloc(ptr, size);
|
||||
#endif
|
||||
}
|
||||
void *berry_calloc32(size_t num, size_t size) {
|
||||
#ifdef USE_BERRY_IRAM
|
||||
return special_calloc32(num, size);
|
||||
#else
|
||||
return special_calloc(num, size);
|
||||
return NULL; /* return NULL to indicate that IRAM is not enabled */
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -234,8 +220,14 @@ void BerryObservability(bvm *vm, int event...) {
|
||||
uint32_t gc_elapsed = millis() - gc_time;
|
||||
uint32_t vm_scanned = va_arg(param, uint32_t);
|
||||
uint32_t vm_freed = va_arg(param, uint32_t);
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, D_LOG_BERRY "GC from %i to %i bytes, objects freed %i/%i (in %d ms)",
|
||||
vm_usage, vm_usage2, vm_freed, vm_scanned, gc_elapsed);
|
||||
size_t slots_used_before_gc = va_arg(param, size_t);
|
||||
size_t slots_allocated_before_gc = va_arg(param, size_t);
|
||||
size_t slots_used_after_gc = va_arg(param, size_t);
|
||||
size_t slots_allocated_after_gc = va_arg(param, size_t);
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, D_LOG_BERRY "GC from %i to %i bytes, objects freed %i/%i (in %d ms) - slots from %i/%i to %i/%i",
|
||||
vm_usage, vm_usage2, vm_freed, vm_scanned, gc_elapsed,
|
||||
slots_used_before_gc, slots_allocated_before_gc,
|
||||
slots_used_after_gc, slots_allocated_after_gc);
|
||||
// make new threshold tighter when we reach high memory usage
|
||||
if (!UsePSRAM() && vm->gc.threshold > 20*1024) {
|
||||
vm->gc.threshold = vm->gc.usage + 10*1024; // increase by only 10 KB
|
||||
|
@ -32,7 +32,7 @@
|
||||
* Green led is controlled by ARM processor indicating SD-Card access.
|
||||
* ESP32 is used as interface between eWelink and ARM processor in SPM-Main unit communicating over proprietary serial protocol.
|
||||
* Power on sequence for two SPM-4Relay modules is 00-00-15-10-(0F)-(13)-(13)-(19)-0C-09-04-09-04-0B-0B
|
||||
* Up to six months of daily energy are stored onthe SD-Card. Previous data is lost.
|
||||
* Up to 180 days of daily energy are stored on the SD-Card. Previous data is lost.
|
||||
* Tasmota support is based on Sonoff SPM v1.0.0 ARM firmware.
|
||||
* Energy history cannot be guaranteed using either SD-Card or internal flash. As a solution Tasmota stores the total energy and yesterday energy just after midnight.
|
||||
*
|
||||
@ -55,6 +55,7 @@
|
||||
* SspmHistory<relay> - Retrieve daily energy of last six month (as defined by ARM firmware)
|
||||
* SspmIAmHere<relay> - Blink ERROR in SPM-4Relay where relay resides
|
||||
* SspmLog<relay> [x] - Retrieve relay power state change and cause logging
|
||||
* SspmMap 0 - Start a scan to fill default mapping
|
||||
* SspmMap 2,3,1,.. - Map scanned module number to physical module number using positional numbering
|
||||
* SspmOverload<relay> 0 - Set default overload detection parameters as read from module during initial scan
|
||||
* SspmOverload<relay> <delay>,<min_power>,<max_power>,<min_voltage>,<max_voltage,<max_current>
|
||||
@ -1409,11 +1410,21 @@ void SSPMHandleReceivedData(void) {
|
||||
Sspm->min_voltage = SSPMGetValue(&SspmBuffer[46]); // x.xxV
|
||||
}
|
||||
uint32_t module_id = SspmBuffer[19] << 8 | SspmBuffer[20];
|
||||
if (0 == Sspm->Settings.module_map[Sspm->module_max]) {
|
||||
Sspm->Settings.module_map[Sspm->module_max] = module_id;
|
||||
}
|
||||
// if (0 == Sspm->Settings.module_map[Sspm->module_max]) {
|
||||
// Sspm->Settings.module_map[Sspm->module_max] = module_id;
|
||||
// }
|
||||
int mapped = SSPMGetModuleNumberFromMapIfFound(module_id);
|
||||
if (-1 == mapped) { Sspm->map_change = true; }
|
||||
if (-1 == mapped) {
|
||||
// Scanned module not in mapped list. Append if possible
|
||||
for (uint32_t module = Sspm->module_max; module < SSPM_MAX_MODULES; module++) {
|
||||
if (0 == Sspm->Settings.module_map[module]) {
|
||||
Sspm->Settings.module_map[module] = module_id;
|
||||
mapped = module;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Sspm->map_change = true;
|
||||
}
|
||||
mapped++;
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("SPM: 4Relay %d (mapped to %d) type %d version %d.%d.%d found with id %12_H"),
|
||||
Sspm->module_max +1, mapped, SspmBuffer[35], SspmBuffer[36], SspmBuffer[37], SspmBuffer[38], Sspm->module[Sspm->module_max]);
|
||||
@ -2212,9 +2223,16 @@ void CmndSSPMReset(void) {
|
||||
|
||||
void CmndSSPMMap(void) {
|
||||
// Map scanned module number to physical module number using positional numbering
|
||||
// SspmMap 1,3,4,2
|
||||
// SspmMap 0 - start a scan to fill default mapping
|
||||
// SspmMap 1,3,4,2 - map modules
|
||||
// TODO: Might need input checks on count and valid different numbers
|
||||
if (Sspm->module_max) { // Valid after initial scan
|
||||
if (0 == XdrvMailbox.payload) {
|
||||
for (uint32_t module = 0; module < SSPM_MAX_MODULES; module++) {
|
||||
Sspm->Settings.module_map[module] = 0; // Clear mapping slots
|
||||
}
|
||||
CmndSSPMScan(); // Start scan to fill default mapping
|
||||
}
|
||||
else if (Sspm->module_max) { // Valid after initial scan
|
||||
char *p;
|
||||
uint32_t i = 0;
|
||||
for (char* str = strtok_r(XdrvMailbox.data, ",", &p); str && i < Sspm->module_max; str = strtok_r(nullptr, ",", &p)) {
|
||||
|
357
tasmota/xnrg_22_bl6523.ino
Normal file
357
tasmota/xnrg_22_bl6523.ino
Normal file
@ -0,0 +1,357 @@
|
||||
/*
|
||||
xnrg_22_bl6523.ino - BL6523 based Watt hour meter support for Tasmota
|
||||
|
||||
Copyright (C) 2022 Jeevas Vasudevan
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_ENERGY_SENSOR
|
||||
#ifdef USE_BL6523
|
||||
/*********************************************************************************************\
|
||||
* Chinese BL6523 based Watt hour meter
|
||||
*
|
||||
* This meter provides accurate Voltage, Frequency, Ampere, Wattage, Power Factor, KWh
|
||||
* To use Tasmota the user needs to add an ESP8266 or ESP32
|
||||
* Three lines need to be connected via 1KOhh resistors to ESP from the main board(RX,TX GND)
|
||||
*
|
||||
* Connection Eg (ESP8266) - Non - Isolated:
|
||||
* BL6523 RX ->1KOhm-> ESP IO4(D2) (Should be Input Capable)
|
||||
* BL6523 TX ->1KOhm-> ESP IO5(D1) (Should be Input Capable)
|
||||
* BL6523 GND -> ESP GND
|
||||
*
|
||||
* Connection Eg (ESP32) - Non - Isolated:
|
||||
* BL6523 RX ->1KOhm-> ESP IO4 (Should be Input Capable)
|
||||
* BL6523 TX ->1KOhm-> ESP IO5 (Should be Input Capable)
|
||||
* BL6523 GND -> ESP GND
|
||||
*
|
||||
* To build add the below to user_config_override.h
|
||||
* #define USE_ENERGY_SENSOR // Enable Energy sensor framework
|
||||
* #define USE_BL6523 // Add support for Chinese BL6523 based Watt hour meter (+1k code)¸
|
||||
*
|
||||
* After Installation use the below template sample:
|
||||
* {"NAME":"BL6523 Smart Meter","GPIO":[0,0,0,0,7488,7520,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XNRG_22 22
|
||||
|
||||
#include <TasmotaSerial.h>
|
||||
|
||||
#define BL6523_RX_DATASET_SIZE 2
|
||||
#define BL6523_TX_DATASET_SIZE 4
|
||||
|
||||
#define BL6523_BAUD 4800
|
||||
#define BL6523_REG_AMPS 0x05
|
||||
#define BL6523_REG_VOLTS 0x07
|
||||
#define BL6523_REG_FREQ 0x09
|
||||
#define BL6523_REG_WATTS 0x0A
|
||||
#define BL6523_REG_POWF 0x08
|
||||
#define BL6523_REG_WATTHR 0x0C
|
||||
|
||||
#define SINGLE_PHASE 0
|
||||
#define RX_WAIT 100
|
||||
|
||||
#define BL6523_IREF 297899
|
||||
#define BL6523_UREF 13304
|
||||
#define BL6523_FREF 3907
|
||||
#define BL6523_PREF 707
|
||||
#define BL6523_PWHRREF_D 33 // Substract this from BL6523_PREF to get WattHr Div.
|
||||
|
||||
TasmotaSerial *Bl6523RxSerial;
|
||||
TasmotaSerial *Bl6523TxSerial;
|
||||
|
||||
struct BL6523
|
||||
{
|
||||
uint8_t type = 1;
|
||||
uint8_t valid = 0;
|
||||
uint8_t got_data_stone = 0;
|
||||
bool discovery_triggered = false;
|
||||
} Bl6523;
|
||||
|
||||
bool Bl6523ReadData(void)
|
||||
{
|
||||
uint32_t powf_word = 0, powf_buf = 0, i = 0;
|
||||
float powf = 0.0f;
|
||||
|
||||
if (!Bl6523RxSerial->available())
|
||||
{
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("BL6:No Rx Data available" ));
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((Bl6523RxSerial->peek() != 0x35) && Bl6523RxSerial->available())
|
||||
{
|
||||
Bl6523RxSerial->read();
|
||||
}
|
||||
|
||||
if (Bl6523RxSerial->available() < BL6523_RX_DATASET_SIZE)
|
||||
{
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("BL6:Rx less than expected" ));
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t rx_buffer[BL6523_RX_DATASET_SIZE];
|
||||
Bl6523RxSerial->readBytes(rx_buffer, BL6523_RX_DATASET_SIZE);
|
||||
Bl6523RxSerial->flush(); // Make room for another burst
|
||||
|
||||
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, rx_buffer, BL6523_RX_DATASET_SIZE);
|
||||
|
||||
i=0;
|
||||
while (Bl6523TxSerial->available() < BL6523_TX_DATASET_SIZE)
|
||||
{
|
||||
// sleep till TX buffer is full
|
||||
delay(10);
|
||||
if ( i++ > RX_WAIT ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t tx_buffer[BL6523_TX_DATASET_SIZE];
|
||||
Bl6523TxSerial->readBytes(tx_buffer, BL6523_TX_DATASET_SIZE);
|
||||
Bl6523TxSerial->flush(); // Make room for another burst
|
||||
|
||||
|
||||
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, tx_buffer, BL6523_TX_DATASET_SIZE);
|
||||
|
||||
/* Checksum: (Addr+Data_L+Data_M+Data_H) & 0xFF, then byte invert */
|
||||
uint8_t crc = rx_buffer[1]; //Addr
|
||||
for (uint32_t i = 0; i < (BL6523_TX_DATASET_SIZE - 1); i++)
|
||||
{
|
||||
crc += tx_buffer[i]; //Add Data_L,Data_M and Data_H to Addr
|
||||
}
|
||||
crc &= 0xff; // Bitwise AND 0xFF
|
||||
crc = ~crc; // Invert the byte
|
||||
if (crc != tx_buffer[BL6523_TX_DATASET_SIZE - 1])
|
||||
{
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL6:" D_CHECKSUM_FAILURE));
|
||||
Bl6523TxSerial->flush();
|
||||
Bl6523RxSerial->flush();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* WRITE DATA (format: command(write->0xCA) address data_low data_mid data_high checksum )
|
||||
WRITE Sample(RX):
|
||||
RX: CA 3E 55 00 00 6C (WRPROT - allow)
|
||||
RX: CA 14 00 00 10 DB (MODE)
|
||||
RX: CA 15 04 00 00 E6 (GAIN - IB 16x gain )
|
||||
RX: CA 19 08 00 00 DE (WA_CFDIV )
|
||||
RX: CA 3E AA 00 00 17 (WRPROT - disable)
|
||||
*/
|
||||
|
||||
/* READ DATA (format: command(read->0x35) address data_low data_mid data_high checksum )
|
||||
READ Sample(RX-TX) Data:
|
||||
RX: 35 05 TX: E4 00 00 16 (IA rms )
|
||||
RX: 35 07 TX: D5 A3 2E 52 (V rms )
|
||||
RX: 35 09 TX: F0 FB 02 09 (FREQ)
|
||||
RX: 35 0A TX: 00 00 00 F5 (WATT)
|
||||
RX: 35 08 TX: 00 00 00 F7 (PF)
|
||||
RX: 35 0C TX: 00 00 00 F3 (WATT_HR)
|
||||
*/
|
||||
|
||||
switch(rx_buffer[1]) {
|
||||
case BL6523_REG_AMPS :
|
||||
Energy.current[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_current_calibration; // 1.260 A
|
||||
break;
|
||||
case BL6523_REG_VOLTS :
|
||||
Energy.voltage[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_voltage_calibration; // 230.2 V
|
||||
break;
|
||||
case BL6523_REG_FREQ :
|
||||
Energy.frequency[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_frequency_calibration; // 50.0 Hz
|
||||
break;
|
||||
case BL6523_REG_WATTS :
|
||||
Energy.active_power[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_power_calibration; // -196.3 W
|
||||
break;
|
||||
case BL6523_REG_POWF :
|
||||
/* Power factor =(sign bit)*((PF[22]×2^-1)+(PF[21]×2^-2)+。。。)
|
||||
Eg., reg value 0x7FFFFF(HEX) -> PF 1, 0x800000(HEX) -> -1, 0x400000(HEX) -> 0.5
|
||||
*/
|
||||
powf = 0.0f;
|
||||
powf_buf = ((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]);
|
||||
powf_word = (powf_buf >> 23) ? ~(powf_buf & 0x7fffff) : powf_buf & 0x7fffff; //Extract the 23 bits and invert if sign bit(24) is set
|
||||
for (int i = 0; i < 23; i++){ // Accumulate powf from 23 bits
|
||||
powf += ((powf_word >> (22-i)) * pow(2,(0-(i+1))));
|
||||
powf_word = powf_word & (0x7fffff >> (1+i));
|
||||
}
|
||||
powf = (powf_buf >> 23) ? (0.0f - (powf)) : powf; // Negate if sign bit(24) is set
|
||||
Energy.power_factor[SINGLE_PHASE] = powf;
|
||||
break;
|
||||
case BL6523_REG_WATTHR :
|
||||
Energy.import_active[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / ( Settings->energy_power_calibration - BL6523_PWHRREF_D ); // 6.216 kWh => used in EnergyUpdateTotal()
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
Energy.data_valid[SINGLE_PHASE] = 0;
|
||||
EnergyUpdateTotal();
|
||||
if (!Bl6523.discovery_triggered)
|
||||
{
|
||||
TasmotaGlobal.discovery_counter = 1; // force TasDiscovery()
|
||||
Bl6523.discovery_triggered = true;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void Bl6523Update(void)
|
||||
{ // Every 250 millisecond
|
||||
if (Bl6523ReadData())
|
||||
{
|
||||
Bl6523.valid = 60;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Bl6523.valid) {
|
||||
Bl6523.valid--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void Bl6523Init(void)
|
||||
{
|
||||
|
||||
Bl6523.type = 0;
|
||||
Bl6523RxSerial = new TasmotaSerial(Pin(GPIO_BL6523_RX), -1, 1);
|
||||
Bl6523TxSerial = new TasmotaSerial(Pin(GPIO_BL6523_TX), -1, 1);
|
||||
if ((Bl6523RxSerial->begin(BL6523_BAUD)) && (Bl6523TxSerial->begin(BL6523_BAUD)))
|
||||
{
|
||||
if (Bl6523RxSerial->hardwareSerial())
|
||||
{
|
||||
ClaimSerial();
|
||||
}
|
||||
if (Bl6523TxSerial->hardwareSerial())
|
||||
{
|
||||
ClaimSerial();
|
||||
}
|
||||
Bl6523.type = 1;
|
||||
Energy.phase_count = 1;
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("BL6:Init Success" ));
|
||||
}
|
||||
else
|
||||
{
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("BL6:Init Failure!" ));
|
||||
TasmotaGlobal.energy_driver = ENERGY_NONE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool Bl6523Command(void) {
|
||||
bool serviced = true;
|
||||
|
||||
int32_t value = (int32_t)(CharToFloat(XdrvMailbox.data) * 1000); // 1.234 = 1234, -1.234 = -1234
|
||||
uint32_t abs_value = abs(value) / 10; // 1.23 = 123, -1.23 = 123
|
||||
|
||||
if ((CMND_POWERCAL == Energy.command_code) || (CMND_VOLTAGECAL == Energy.command_code) || (CMND_CURRENTCAL == Energy.command_code)) {
|
||||
// Service in xdrv_03_energy.ino
|
||||
}
|
||||
else if (CMND_POWERSET == Energy.command_code) {
|
||||
if (XdrvMailbox.data_len) {
|
||||
if ((abs_value > 100) && (abs_value < 200000)) { // Between 1.00 and 2000.00 W
|
||||
Settings->energy_power_calibration = abs_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (CMND_VOLTAGESET == Energy.command_code) {
|
||||
if (XdrvMailbox.data_len) {
|
||||
if ((abs_value > 10000) && (abs_value < 26000)) { // Between 100.00 and 260.00 V
|
||||
Settings->energy_voltage_calibration = abs_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (CMND_CURRENTSET == Energy.command_code) {
|
||||
if (XdrvMailbox.data_len) {
|
||||
if ((abs_value > 1000) && (abs_value < 1000000)) { // Between 10.00 mA and 10.00000 A
|
||||
Settings->energy_current_calibration = abs_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (CMND_FREQUENCYSET == Energy.command_code) {
|
||||
if (XdrvMailbox.data_len) {
|
||||
if ((abs_value > 4500) && (abs_value < 6500)) { // Between 45.00 and 65.00 Hz
|
||||
Settings->energy_frequency_calibration = abs_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (CMND_ENERGYCONFIG == Energy.command_code) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Config index %d, payload %d, value %d, data '%s'"),
|
||||
XdrvMailbox.index, XdrvMailbox.payload, value, XdrvMailbox.data ? XdrvMailbox.data : "null" );
|
||||
|
||||
// EnergyConfig1 to 3 = Set Energy.current[channel] in A like 0.417 for 417mA
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index < 4)) {
|
||||
//Bl6523.current[XdrvMailbox.index -1] = value;
|
||||
}
|
||||
// EnergyConfig4 to 6 = Set Energy.active_power[channel] in W like 100 for 100W
|
||||
if ((XdrvMailbox.index > 3) && (XdrvMailbox.index < 7)) {
|
||||
//Bl6523.power[XdrvMailbox.index -4] = value;
|
||||
}
|
||||
}
|
||||
else serviced = false; // Unknown command
|
||||
|
||||
return serviced;
|
||||
}
|
||||
|
||||
void Bl6523DrvInit(void)
|
||||
{
|
||||
if (PinUsed(GPIO_BL6523_RX) && PinUsed(GPIO_BL6523_TX)) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("BL6:PreInit Success" ));
|
||||
TasmotaGlobal.energy_driver = XNRG_22;
|
||||
if (HLW_PREF_PULSE == Settings->energy_power_calibration) {
|
||||
Settings->energy_frequency_calibration = BL6523_FREF;
|
||||
Settings->energy_voltage_calibration = BL6523_UREF;
|
||||
Settings->energy_current_calibration = BL6523_IREF;
|
||||
Settings->energy_power_calibration = BL6523_PREF;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("BL6:PreInit Failure!" ));
|
||||
TasmotaGlobal.energy_driver = ENERGY_NONE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool Xnrg22(uint8_t function)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case FUNC_EVERY_250_MSECOND:
|
||||
Bl6523Update();
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
result = Bl6523Command();
|
||||
break;
|
||||
case FUNC_INIT:
|
||||
Bl6523Init();
|
||||
break;
|
||||
case FUNC_PRE_INIT:
|
||||
Bl6523DrvInit();
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_BL6523
|
||||
#endif // USE_ENERGY_SENSOR
|
@ -37,7 +37,13 @@
|
||||
* Rule:
|
||||
* on wiegand#uid=4302741608 do publish cmnd/ailight/power 2 endon
|
||||
*
|
||||
* contains:
|
||||
* 20220215
|
||||
* - fix 34-bit size parity chk
|
||||
* - fix 64-bit representation after removal of %llu support (Tasmota does not support 64-bit decimal output specifier (%llu) saving 60k code)
|
||||
* - change internal rfid size from uint64_t to uint32_t
|
||||
* - limited max amount of kaypad presses to a 32-bit number (at least 999999999)
|
||||
* ---
|
||||
* 20201101
|
||||
* - fix for #11047 Wiegand 26/34 missed some key press if they are press at normal speed
|
||||
* - removed testing code for tests without attached hardware
|
||||
* - added SetOption123 0-Wiegand UID decimal (default) 1-Wiegand UID hexadecimal
|
||||
@ -102,23 +108,21 @@ class Wiegand {
|
||||
#if (DEV_WIEGAND_TEST_MODE!=1)
|
||||
private:
|
||||
#endif //(DEV_WIEGAND_TEST_MODE==1)
|
||||
uint64_t CheckAndConvertRfid(uint64_t,uint16_t);
|
||||
uint32_t CheckAndConvertRfid(uint64_t,uint16_t);
|
||||
uint8_t CalculateParities(uint64_t, int);
|
||||
bool WiegandConversion (uint64_t , uint16_t );
|
||||
void setOutputFormat(void); // fix output HEX format
|
||||
void HandleKeyPad(void); //handle one tag for multi key strokes
|
||||
|
||||
|
||||
static void handleD0Interrupt(void);
|
||||
static void handleD1Interrupt(void);
|
||||
static void handleDxInterrupt(int in); // fix #11047
|
||||
static void ClearRFIDBuffer(int);
|
||||
|
||||
uint64_t rfid;
|
||||
uint32_t rfid;
|
||||
uint32_t tagSize;
|
||||
const char* outFormat;
|
||||
uint64_t mqttRFIDKeypadBuffer;
|
||||
uint64_t webRFIDKeypadBuffer;
|
||||
uint32_t mqttRFIDKeypadBuffer;
|
||||
uint32_t webRFIDKeypadBuffer;
|
||||
|
||||
static volatile uint64_t rfidBuffer;
|
||||
static volatile uint16_t bitCount;
|
||||
@ -145,15 +149,14 @@ volatile bool Wiegand::CodeComplete;
|
||||
volatile RFID_store Wiegand::rfid_found[WIEGAND_RFID_ARRAY_SIZE];
|
||||
volatile int Wiegand::currentFoundRFIDcount;
|
||||
|
||||
|
||||
|
||||
void IRAM_ATTR Wiegand::ClearRFIDBuffer(int endIndex = WIEGAND_RFID_ARRAY_SIZE) {
|
||||
currentFoundRFIDcount=WIEGAND_RFID_ARRAY_SIZE-endIndex; // clear all buffers
|
||||
for (int i= 0; i < endIndex; i++) {
|
||||
rfid_found[i].RFID=0;
|
||||
rfid_found[i].bitCount=0;
|
||||
}
|
||||
currentFoundRFIDcount = WIEGAND_RFID_ARRAY_SIZE - endIndex; // clear all buffers
|
||||
for (uint32_t i = 0; i < endIndex; i++) {
|
||||
rfid_found[i].RFID=0;
|
||||
rfid_found[i].bitCount=0;
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR Wiegand::handleD1Interrupt() { // Receive a 1 bit. (D0=high & D1=low)
|
||||
handleDxInterrupt(1);
|
||||
}
|
||||
@ -163,9 +166,9 @@ void IRAM_ATTR Wiegand::handleD0Interrupt() { // Receive a 0 bit. (D0=low & D1=
|
||||
}
|
||||
|
||||
void IRAM_ATTR Wiegand::handleDxInterrupt(int in) {
|
||||
unsigned long curTime = micros(); // to be sure I will use micros() instead of millis() overflow is handle by using the minus operator to compare
|
||||
unsigned long diffTime= curTime - lastFoundTime;
|
||||
if ( (diffTime > CodeGapTime) && (bitCount > 0)) {
|
||||
uint32_t curTime = micros(); // to be sure I will use micros() instead of millis() overflow is handle by using the minus operator to compare
|
||||
uint32_t diffTime = curTime - lastFoundTime;
|
||||
if ((diffTime > CodeGapTime) && (bitCount > 0)) {
|
||||
// previous RFID tag (key pad numer)is complete. Will be detected by the code ending gap
|
||||
// one bit will take the time of impulse_time + impulse_gap_time. it (bitTime) will be recalculated each time an impulse is detected
|
||||
// the devices will add some inter_code_gap_time to separate codes this will be much longer than the bit_time. (WIEGAND_CODE_GAP_FACTOR)
|
||||
@ -188,7 +191,7 @@ void IRAM_ATTR Wiegand::handleDxInterrupt(int in) {
|
||||
FirstBitTimeStamp = (curTime != 0) ? curTime : 1; // accept 1µs differenct to avoid a miss the first timestamp if curTime is 0.
|
||||
}
|
||||
else if (bitCount == 2) { // only calculate once per RFID tag, but restrict to values, which are in within a plausible range
|
||||
bitTime = ((diffTime > (WIEGAND_BIT_TIME_DEFAULT/4)) && (diffTime < (4*WIEGAND_BIT_TIME_DEFAULT))) ? diffTime : WIEGAND_BIT_TIME_DEFAULT;
|
||||
bitTime = ((diffTime > (WIEGAND_BIT_TIME_DEFAULT / 4)) && (diffTime < (4 * WIEGAND_BIT_TIME_DEFAULT))) ? diffTime : WIEGAND_BIT_TIME_DEFAULT;
|
||||
CodeGapTime = WIEGAND_CODE_GAP_FACTOR * bitTime;
|
||||
}
|
||||
//save current rfid in array otherwise we will never see the last found tag
|
||||
@ -243,7 +246,7 @@ void Wiegand::Init() {
|
||||
#endif // DEV_WIEGAND_TEST_MODE>0
|
||||
}
|
||||
|
||||
uint64_t Wiegand::CheckAndConvertRfid(uint64_t rfidIn, uint16_t bitCount) {
|
||||
uint32_t Wiegand::CheckAndConvertRfid(uint64_t rfidIn, uint16_t bitCount) {
|
||||
uint8_t evenParityBit = 0;
|
||||
uint8_t oddParityBit = (uint8_t) (rfidIn & 0x1); // Last bit = odd parity
|
||||
uint8_t calcParity = 0;
|
||||
@ -264,8 +267,8 @@ uint64_t Wiegand::CheckAndConvertRfid(uint64_t rfidIn, uint16_t bitCount) {
|
||||
break;
|
||||
|
||||
case 34:
|
||||
evenParityBit = (rfidIn & 0x400000000) ? 0x80 : 0;
|
||||
rfidIn = (rfidIn & 0x3FFFFFFFE) >>1;
|
||||
evenParityBit = (rfidIn & 0x200000000) ? 0x80 : 0;
|
||||
rfidIn = (rfidIn & 0x1FFFFFFFE) >>1;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -273,8 +276,8 @@ uint64_t Wiegand::CheckAndConvertRfid(uint64_t rfidIn, uint16_t bitCount) {
|
||||
}
|
||||
calcParity = CalculateParities(rfidIn, bitCount); // Check result on http://www.ccdesignworks.com/wiegand_calc.htm with raw tag as input
|
||||
if (calcParity != (evenParityBit | oddParityBit)) { // Parity bit is wrong
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("WIE: %_X parity error"), &rfidIn); // Print up to uint64_t
|
||||
rfidIn=0;
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("WIE: %llu parity error"), rfidIn);
|
||||
}
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: even (left) parity: %u "), (evenParityBit>>7));
|
||||
@ -282,10 +285,10 @@ uint64_t Wiegand::CheckAndConvertRfid(uint64_t rfidIn, uint16_t bitCount) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: odd (right) parity: %u "), oddParityBit);
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: odd (calc) parity: %u "), (calcParity & 0x01));
|
||||
#endif // DEV_WIEGAND_TEST_MODE>0
|
||||
return rfidIn;
|
||||
return (uint32_t)rfidIn;
|
||||
}
|
||||
|
||||
uint8_t Wiegand::CalculateParities(uint64_t tagWithoutParities, int tag_size=26) {
|
||||
uint8_t Wiegand::CalculateParities(uint64_t tagWithoutParities, int tag_size = 26) {
|
||||
// tag_size is the size of the final tag including the 2 parity bits
|
||||
// So length if the tagWithoutParities should be (tag_size-2) !! That will be not profed and
|
||||
// lead to wrong results if the input value is larger!
|
||||
@ -295,7 +298,7 @@ uint8_t Wiegand::CalculateParities(uint64_t tagWithoutParities, int tag_size=26)
|
||||
tag_size -= 2;
|
||||
if (tag_size <= 0) { return retValue; } // Prohibit div zero exception and other wrong inputs
|
||||
uint8_t parity = 1; // Check for odd parity on LSB
|
||||
for (uint8_t i = 0; i < (tag_size / 2); i++) {
|
||||
for (uint32_t i = 0; i < (tag_size / 2); i++) {
|
||||
parity ^= (tagWithoutParities & 1);
|
||||
tagWithoutParities >>= 1;
|
||||
}
|
||||
@ -314,53 +317,47 @@ uint8_t Wiegand::CalculateParities(uint64_t tagWithoutParities, int tag_size=26)
|
||||
bool Wiegand::WiegandConversion (uint64_t rfidBuffer, uint16_t bitCount) {
|
||||
bool bRet = false;
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Raw tag %llu, Bit count %u"), rfidBuffer, bitCount);
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Raw tag %_X, Bit count %u"), &rfidBuffer, bitCount); // Print up to uint64_t
|
||||
#endif // DEV_WIEGAND_TEST_MODE>0
|
||||
if ((24 == bitCount) || (26 == bitCount) || (32 == bitCount) || (34 == bitCount)) {
|
||||
// 24, 26, 32, 34-bit Wiegand codes
|
||||
rfid = CheckAndConvertRfid(rfidBuffer, bitCount);
|
||||
tagSize = bitCount;
|
||||
if ((24 == bitCount) || (26 == bitCount) || (32 == bitCount) || (34 == bitCount)) {
|
||||
// 24, 26, 32, 34-bit Wiegand codes
|
||||
rfid = CheckAndConvertRfid(rfidBuffer, bitCount);
|
||||
tagSize = bitCount;
|
||||
bRet = true;
|
||||
}
|
||||
else if (4 == bitCount) {
|
||||
// 4-bit Wiegand codes for keypads
|
||||
rfid = (uint32_t)(rfidBuffer & 0x0000000F);
|
||||
tagSize = bitCount;
|
||||
bRet = true;
|
||||
}
|
||||
else if (8 == bitCount) {
|
||||
// 8-bit Wiegand codes for keypads with integrity
|
||||
// 8-bit Wiegand keyboard data, high nibble is the "NOT" of low nibble
|
||||
// eg if key 1 pressed, data=E1 in binary 11100001 , high nibble=1110 , low nibble = 0001
|
||||
char highNibble = (rfidBuffer & 0xf0) >>4;
|
||||
char lowNibble = (rfidBuffer & 0x0f);
|
||||
if (lowNibble == (~highNibble & 0x0f)) { // Check if low nibble matches the "NOT" of high nibble.
|
||||
rfid = (uint32_t)(lowNibble);
|
||||
bRet = true;
|
||||
}
|
||||
else if (4 == bitCount) {
|
||||
// 4-bit Wiegand codes for keypads
|
||||
rfid = (int)(rfidBuffer & 0x0000000F);
|
||||
tagSize = bitCount;
|
||||
bRet = true;
|
||||
}
|
||||
else if (8 == bitCount) {
|
||||
// 8-bit Wiegand codes for keypads with integrity
|
||||
// 8-bit Wiegand keyboard data, high nibble is the "NOT" of low nibble
|
||||
// eg if key 1 pressed, data=E1 in binary 11100001 , high nibble=1110 , low nibble = 0001
|
||||
char highNibble = (rfidBuffer & 0xf0) >>4;
|
||||
char lowNibble = (rfidBuffer & 0x0f);
|
||||
if (lowNibble == (~highNibble & 0x0f)) { // Check if low nibble matches the "NOT" of high nibble.
|
||||
rfid = (int)(lowNibble);
|
||||
bRet = true;
|
||||
} else {
|
||||
bRet = false;
|
||||
}
|
||||
tagSize = bitCount;
|
||||
} else {
|
||||
// Time reached but unknown bitCount, clear and start again
|
||||
tagSize = 0;
|
||||
bRet = false;
|
||||
}
|
||||
tagSize = bitCount;
|
||||
} else {
|
||||
// Time reached but unknown bitCount, clear and start again
|
||||
tagSize = 0;
|
||||
bRet = false;
|
||||
}
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Tag out %llu, tag size %u "), rfid, tagSize);
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Tag out %u, tag size %u "), rfid, tagSize);
|
||||
#endif // DEV_WIEGAND_TEST_MODE>0
|
||||
return bRet;
|
||||
}
|
||||
|
||||
void Wiegand::setOutputFormat(void)
|
||||
{
|
||||
if (GetOption(WIEGAND_OPTION_HEX) == 0) { outFormat = "u"; }
|
||||
else { outFormat = "X" WIEGAND_OPTION_HEX_POSTFIX ; }
|
||||
}
|
||||
|
||||
void Wiegand::HandleKeyPad(void) { // will be called if a valid key pad input was recognized
|
||||
if (GetOption(WIEGAND_OPTION_KEYPAD_TO_TAG) == 0) { // handle all key pad inputs as ONE Tag until # is recognized
|
||||
if ( (tagSize == 4) || (tagSize == 8) ) {
|
||||
if (GetOption(WIEGAND_OPTION_KEYPAD_TO_TAG) == 0) { // handle all key pad inputs as ONE Tag until # is recognized
|
||||
if ((tagSize == 4) || (tagSize == 8)) {
|
||||
//only handle Keypad strokes if it is requested
|
||||
if (rfid >= 0x0a) { // # * as end of input detected -> all key values which are larger than 9
|
||||
rfid = mqttRFIDKeypadBuffer; // original tagsize of 4 or 8 will be kept.
|
||||
@ -368,7 +365,7 @@ void Wiegand::HandleKeyPad(void) { // will be called if a valid key pad input wa
|
||||
mqttRFIDKeypadBuffer = 0;
|
||||
}
|
||||
else {
|
||||
mqttRFIDKeypadBuffer = (mqttRFIDKeypadBuffer*10)+rfid; //left shift + new key
|
||||
mqttRFIDKeypadBuffer = (mqttRFIDKeypadBuffer * 10) + rfid; //left shift + new key
|
||||
webRFIDKeypadBuffer = mqttRFIDKeypadBuffer; // visualising the current typed keys
|
||||
rfid = 0;
|
||||
tagSize = 0;
|
||||
@ -382,38 +379,33 @@ void Wiegand::HandleKeyPad(void) { // will be called if a valid key pad input wa
|
||||
}
|
||||
|
||||
void Wiegand::ScanForTag() {
|
||||
unsigned long startTime = micros();
|
||||
uint32_t startTime = micros();
|
||||
handleDxInterrupt(3);
|
||||
if (currentFoundRFIDcount > 0) {
|
||||
unsigned int lastFoundRFIDcount = currentFoundRFIDcount;
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag(). bitTime: %0lu lastFoundTime: %0lu RFIDS in buffer: %lu"), bitTime, lastFoundTime, currentFoundRFIDcount);
|
||||
#endif
|
||||
// format MQTT output
|
||||
// setOutputFormat();
|
||||
// char sFormat[50];
|
||||
// snprintf( sFormat, 50, PSTR(",\"Wiegand\":{\"UID\":%%0ll%s,\"" D_JSON_SIZE "\":%%%s}}"), outFormat, outFormat);
|
||||
for (int i= 0; i < WIEGAND_RFID_ARRAY_SIZE; i++)
|
||||
{
|
||||
if (rfid_found[i].RFID != 0 || (rfid_found[i].RFID == 0 && i == 0)) {
|
||||
uint64_t oldTag = rfid;
|
||||
if (currentFoundRFIDcount > 0) {
|
||||
uint32_t lastFoundRFIDcount = currentFoundRFIDcount;
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag(). bitTime: %u lastFoundTime: %u RFIDS in buffer: %u"), bitTime, lastFoundTime, currentFoundRFIDcount);
|
||||
#endif
|
||||
for (uint32_t i = 0; i < WIEGAND_RFID_ARRAY_SIZE; i++) {
|
||||
if (rfid_found[i].RFID != 0 || (rfid_found[i].RFID == 0 && i == 0)) {
|
||||
uint32_t oldTag = rfid;
|
||||
bool validKey = WiegandConversion(rfid_found[i].RFID, rfid_found[i].bitCount);
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ValidKey: %d Previous tag %llu"), validKey, oldTag);
|
||||
#endif // DEV_WIEGAND_TEST_MODE>0
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ValidKey %d, Previous tag %u"), validKey, oldTag);
|
||||
#endif // DEV_WIEGAND_TEST_MODE>0
|
||||
if (validKey) { // Only in case of valid key do action. Issue#10585
|
||||
HandleKeyPad(); //support one tag for multi key input
|
||||
if (tagSize>0) { //do output only for rfids which are complete
|
||||
if (tagSize > 0) { //do output only for rfids which are complete
|
||||
if (oldTag == rfid) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("WIE: Old tag"));
|
||||
}
|
||||
// ResponseTime_P(sFormat, rfid, tagSize);
|
||||
// Tasmota does not support 64-bit decimal output specifier (%llu) saving 60k code
|
||||
ResponseTime_P(PSTR(",\"Wiegand\":{\"UID\":"));
|
||||
if (GetOption(WIEGAND_OPTION_HEX) == 0) {
|
||||
ResponseTime_P(PSTR(",\"Wiegand\":{\"UID\":%lu,\"" D_JSON_SIZE "\":%d}}"), (uint32_t)rfid, tagSize);
|
||||
ResponseAppend_P(PSTR("%u"), rfid);
|
||||
} else {
|
||||
ResponseTime_P(PSTR(",\"Wiegand\":{\"UID\":\"%2_X" WIEGAND_OPTION_HEX_POSTFIX "\",\"" D_JSON_SIZE "\":\"%X" WIEGAND_OPTION_HEX_POSTFIX "\"}}"), &rfid, tagSize);
|
||||
ResponseAppend_P(PSTR("\"%X" WIEGAND_OPTION_HEX_POSTFIX "\""), rfid);
|
||||
}
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_SIZE "\":%d}}"), tagSize);
|
||||
MqttPublishTeleSensor();
|
||||
}
|
||||
}
|
||||
@ -422,33 +414,29 @@ void Wiegand::ScanForTag() {
|
||||
if (currentFoundRFIDcount > lastFoundRFIDcount) {
|
||||
// if that happens: we need to move the id found during the loop to top of the array
|
||||
// and correct the currentFoundRFIDcount
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag() %lu tags added while working on buffer"), (currentFoundRFIDcount-lastFoundRFIDcount));
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag() %u tags added while working on buffer"), (currentFoundRFIDcount - lastFoundRFIDcount));
|
||||
}
|
||||
ClearRFIDBuffer(); //reset array
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag() time elapsed %lu"), (micros() - startTime));
|
||||
#endif
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag() time elapsed %u"), (micros() - startTime));
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
void Wiegand::Show(void) {
|
||||
// setOutputFormat();
|
||||
// char sFormat [30];
|
||||
// snprintf( sFormat, 30,PSTR("{s}Wiegand UID{m}%%ll%s {e}"), outFormat);
|
||||
// if (tagSize>0) { WSContentSend_PD(sFormat, rfid); }
|
||||
// else { WSContentSend_PD(sFormat, webRFIDKeypadBuffer); }
|
||||
// Tasmota does not support 64-bit decimal output specifier (%llu) saving 60k code
|
||||
if (GetOption(WIEGAND_OPTION_HEX) == 0) {
|
||||
WSContentSend_P(PSTR("{s}Wiegand UID{m}%lu{e}"), (tagSize>0) ? (uint32_t)rfid : (uint32_t)webRFIDKeypadBuffer);
|
||||
} else {
|
||||
WSContentSend_P(PSTR("{s}Wiegand UID{m}%2_X" WIEGAND_OPTION_HEX_POSTFIX "{e}"), (tagSize>0) ? &rfid : &webRFIDKeypadBuffer);
|
||||
}
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Tag %llu, Bits %u"), rfid, bitCount);
|
||||
#endif // DEV_WIEGAND_TEST_MODE>0
|
||||
WSContentSend_P(PSTR("{s}Wiegand UID{m}"));
|
||||
if (GetOption(WIEGAND_OPTION_HEX) == 0) {
|
||||
WSContentSend_P(PSTR("%u"), (tagSize > 0) ? rfid : webRFIDKeypadBuffer);
|
||||
} else {
|
||||
WSContentSend_P(PSTR("%X" WIEGAND_OPTION_HEX_POSTFIX), (tagSize > 0) ? rfid : webRFIDKeypadBuffer);
|
||||
}
|
||||
WSContentSend_P(PSTR("{e}"));
|
||||
|
||||
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Tag %u, Bits %u"), rfid, bitCount);
|
||||
#endif // DEV_WIEGAND_TEST_MODE>0
|
||||
}
|
||||
#endif // USE_WEBSERVER
|
||||
|
||||
|
@ -262,7 +262,7 @@ a_features = [[
|
||||
"USE_MCP2515","USE_TASMESH","USE_WIFI_RANGE_EXTENDER","USE_INFLUXDB",
|
||||
"USE_HRG15","USE_VINDRIKTNING","USE_SCD40","USE_HM330X",
|
||||
"USE_HDC2010","USE_LSC_MCSL","USE_SONOFF_SPM","USE_SHIFT595",
|
||||
"USE_SDM230","USE_CM110x","","",
|
||||
"USE_SDM230","USE_CM110x","USE_BL6523","",
|
||||
"","","","",
|
||||
"","","",""
|
||||
]]
|
||||
@ -292,7 +292,7 @@ else:
|
||||
obj = json.load(fp)
|
||||
|
||||
def StartDecode():
|
||||
print ("\n*** decode-status.py v20220115 by Theo Arends and Jacek Ziolkowski ***")
|
||||
print ("\n*** decode-status.py v11.0.0.1 by Theo Arends and Jacek Ziolkowski ***")
|
||||
|
||||
# print("Decoding\n{}".format(obj))
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user