Merge branch 'arendst:development' into S3_Homekit

This commit is contained in:
Jason2866 2022-02-16 18:10:46 +01:00 committed by GitHub
commit 574be6b7f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 2896 additions and 1796 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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'",

View File

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

View File

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

View 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"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
/*-------------------------------------------------------------------------------------------*\

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
\*********************************************************************************************/

View 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

View File

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

View File

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

View File

@ -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
View 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^1PF[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

View File

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

View File

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