Removed max number of 30 backlog entries

This commit is contained in:
Theo Arends 2024-01-18 16:32:28 +01:00
parent db70d9c8cb
commit c9d0106007
10 changed files with 438 additions and 127 deletions

View File

@ -13,8 +13,8 @@ All notable changes to this project will be documented in this file.
- ESP32 MI BLE support for Xiaomi LYWSD02MMC (#20381)
- LVGL option to add `lv.keyboard` extra widget (#20496)
- GUI sensor separators (#20495)
- Command ``TimedPower<index> <milliseconds>[,ON|OFF|TOGGLE|BLINK]`` executes ``Power<index> [ON|OFF|TOGGLE|BLINK] `` and after <millisecond> executes ``Power<index> [OFF|ON|TOGGLE|OFF]``
- Berry add solidification of strings longer than 255 bytes
- Command ``TimedPower<index> <milliseconds>[,ON|OFF|TOGGLE|BLINK]`` executes ``Power<index> [ON|OFF|TOGGLE|BLINK] `` and after <millisecond> executes ``Power<index> [OFF|ON|TOGGLE|BLINK_OFF]``
- Berry solidification of strings longer than 255 bytes (#20529)
### Breaking Changed
@ -30,9 +30,10 @@ All notable changes to this project will be documented in this file.
- Zigbee ramdom crash in main page (#20481)
- Web file upload response on upload error (#20340)
- ESP32 shutter exception 6 (divide by zero) on ``ShutterMode 4`` (#20524)
- GPIOViewer exception 3
### Removed
- Max number of 30 backlog entries
## [13.3.0.2] 20240111
### Added

View File

@ -146,6 +146,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
- Berry provide lightweight options for `tasmota.wifi/eth/memory/rtc` [#20448](https://github.com/arendst/Tasmota/issues/20448)
- Berry `tasmota.webcolor` [#20454](https://github.com/arendst/Tasmota/issues/20454)
- Berry `debug.caller` [#20470](https://github.com/arendst/Tasmota/issues/20470)
- Berry solidification of strings longer than 255 bytes [#20529](https://github.com/arendst/Tasmota/issues/20529)
- LVGL `lv.str_arr` [#20480](https://github.com/arendst/Tasmota/issues/20480)
- LVGL option to add `lv.keyboard` extra widget [#20496](https://github.com/arendst/Tasmota/issues/20496)
- HASPmota `haspmota.page_show()` to change page [#20333](https://github.com/arendst/Tasmota/issues/20333)
@ -179,4 +180,5 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
- Berry claiming UART0 if needed [#20324](https://github.com/arendst/Tasmota/issues/20324)
- Matter Contact sensor was not triggering any update [#20232](https://github.com/arendst/Tasmota/issues/20232)
### Removed
### Removed
- Max number of 30 backlog entries

View File

@ -7,6 +7,8 @@
Created by Ivan Seidel Gomes, March, 2013.
Released into the public domain.
20240118 - Removed sort functions not used by Tasmota (@arendst)
*/
@ -39,8 +41,6 @@ protected:
ListNode<T>* getNode(int index);
ListNode<T>* findEndOfSortedString(ListNode<T> *p, int (*cmp)(T &, T &));
public:
LinkedList();
LinkedList(int sizeIndex, T _t); //initiate list size and default value
@ -96,11 +96,6 @@ public:
*/
virtual void clear();
/*
Sort the list, given a comparison function
*/
virtual void sort(int (*cmp)(T &, T &));
// add support to array brakets [] operator
inline T& operator[](int index);
inline T& operator[](size_t& i) { return this->get(i); }
@ -347,73 +342,4 @@ void LinkedList<T>::clear(){
shift();
}
template<typename T>
void LinkedList<T>::sort(int (*cmp)(T &, T &)){
if(_size < 2) return; // trivial case;
for(;;) {
ListNode<T> **joinPoint = &root;
while(*joinPoint) {
ListNode<T> *a = *joinPoint;
ListNode<T> *a_end = findEndOfSortedString(a, cmp);
if(!a_end->next ) {
if(joinPoint == &root) {
last = a_end;
isCached = false;
return;
}
else {
break;
}
}
ListNode<T> *b = a_end->next;
ListNode<T> *b_end = findEndOfSortedString(b, cmp);
ListNode<T> *tail = b_end->next;
a_end->next = NULL;
b_end->next = NULL;
while(a && b) {
if(cmp(a->data, b->data) <= 0) {
*joinPoint = a;
joinPoint = &a->next;
a = a->next;
}
else {
*joinPoint = b;
joinPoint = &b->next;
b = b->next;
}
}
if(a) {
*joinPoint = a;
while(a->next) a = a->next;
a->next = tail;
joinPoint = &a->next;
}
else {
*joinPoint = b;
while(b->next) b = b->next;
b->next = tail;
joinPoint = &b->next;
}
}
}
}
template<typename T>
ListNode<T>* LinkedList<T>::findEndOfSortedString(ListNode<T> *p, int (*cmp)(T &, T &)) {
while(p->next && cmp(p->data, p->next->data) <= 0) {
p = p->next;
}
return p;
}
#endif

View File

@ -0,0 +1,419 @@
/*
LinkedList.h - V1.1 - Generic LinkedList implementation
Works better with FIFO, because LIFO will need to
search the entire List to find the last one;
For instructions, go to https://github.com/ivanseidel/LinkedList
Created by Ivan Seidel Gomes, March, 2013.
Released into the public domain.
*/
#ifndef LinkedList_h
#define LinkedList_h
#include <stddef.h>
template<class T>
struct ListNode
{
T data;
ListNode<T> *next;
};
template <typename T>
class LinkedList{
protected:
int _size;
ListNode<T> *root;
ListNode<T> *last;
// Helps "get" method, by saving last position
ListNode<T> *lastNodeGot;
int lastIndexGot;
// isCached should be set to FALSE
// everytime the list suffer changes
bool isCached;
ListNode<T>* getNode(int index);
ListNode<T>* findEndOfSortedString(ListNode<T> *p, int (*cmp)(T &, T &));
public:
LinkedList();
LinkedList(int sizeIndex, T _t); //initiate list size and default value
~LinkedList();
/*
Returns current size of LinkedList
*/
virtual int size();
/*
Adds a T object in the specified index;
Unlink and link the LinkedList correcly;
Increment _size
*/
virtual bool add(int index, T);
/*
Adds a T object in the end of the LinkedList;
Increment _size;
*/
virtual bool add(T);
/*
Adds a T object in the start of the LinkedList;
Increment _size;
*/
virtual bool unshift(T);
/*
Set the object at index, with T;
*/
virtual bool set(int index, T);
/*
Remove object at index;
If index is not reachable, returns false;
else, decrement _size
*/
virtual T remove(int index);
/*
Remove last object;
*/
virtual T pop();
/*
Remove first object;
*/
virtual T shift();
/*
Get the index'th element on the list;
Return Element if accessible,
else, return false;
*/
virtual T get(int index);
/*
Clear the entire array
*/
virtual void clear();
/*
Sort the list, given a comparison function
*/
virtual void sort(int (*cmp)(T &, T &));
// add support to array brakets [] operator
inline T& operator[](int index);
inline T& operator[](size_t& i) { return this->get(i); }
inline const T& operator[](const size_t& i) const { return this->get(i); }
};
// Initialize LinkedList with false values
template<typename T>
LinkedList<T>::LinkedList()
{
root=NULL;
last=NULL;
_size=0;
lastNodeGot = root;
lastIndexGot = 0;
isCached = false;
}
// Clear Nodes and free Memory
template<typename T>
LinkedList<T>::~LinkedList()
{
ListNode<T>* tmp;
while(root!=NULL)
{
tmp=root;
root=root->next;
delete tmp;
}
last = NULL;
_size=0;
isCached = false;
}
/*
Actualy "logic" coding
*/
template<typename T>
ListNode<T>* LinkedList<T>::getNode(int index){
int _pos = 0;
ListNode<T>* current = root;
// Check if the node trying to get is
// immediatly AFTER the previous got one
if(isCached && lastIndexGot <= index){
_pos = lastIndexGot;
current = lastNodeGot;
}
while(_pos < index && current){
current = current->next;
_pos++;
}
// Check if the object index got is the same as the required
if(_pos == index){
isCached = true;
lastIndexGot = index;
lastNodeGot = current;
return current;
}
return NULL;
}
template<typename T>
int LinkedList<T>::size(){
return _size;
}
template<typename T>
LinkedList<T>::LinkedList(int sizeIndex, T _t){
for (int i = 0; i < sizeIndex; i++){
add(_t);
}
}
template<typename T>
bool LinkedList<T>::add(int index, T _t){
if(index >= _size)
return add(_t);
if(index == 0)
return unshift(_t);
ListNode<T> *tmp = new ListNode<T>(),
*_prev = getNode(index-1);
tmp->data = _t;
tmp->next = _prev->next;
_prev->next = tmp;
_size++;
isCached = false;
return true;
}
template<typename T>
bool LinkedList<T>::add(T _t){
ListNode<T> *tmp = new ListNode<T>();
tmp->data = _t;
tmp->next = NULL;
if(root){
// Already have elements inserted
last->next = tmp;
last = tmp;
}else{
// First element being inserted
root = tmp;
last = tmp;
}
_size++;
isCached = false;
return true;
}
template<typename T>
bool LinkedList<T>::unshift(T _t){
if(_size == 0)
return add(_t);
ListNode<T> *tmp = new ListNode<T>();
tmp->next = root;
tmp->data = _t;
root = tmp;
_size++;
isCached = false;
return true;
}
template<typename T>
T& LinkedList<T>::operator[](int index) {
return getNode(index)->data;
}
template<typename T>
bool LinkedList<T>::set(int index, T _t){
// Check if index position is in bounds
if(index < 0 || index >= _size)
return false;
getNode(index)->data = _t;
return true;
}
template<typename T>
T LinkedList<T>::pop(){
if(_size <= 0)
return T();
isCached = false;
if(_size >= 2){
ListNode<T> *tmp = getNode(_size - 2);
T ret = tmp->next->data;
delete(tmp->next);
tmp->next = NULL;
last = tmp;
_size--;
return ret;
}else{
// Only one element left on the list
T ret = root->data;
delete(root);
root = NULL;
last = NULL;
_size = 0;
return ret;
}
}
template<typename T>
T LinkedList<T>::shift(){
if(_size <= 0)
return T();
if(_size > 1){
ListNode<T> *_next = root->next;
T ret = root->data;
delete(root);
root = _next;
_size --;
isCached = false;
return ret;
}else{
// Only one left, then pop()
return pop();
}
}
template<typename T>
T LinkedList<T>::remove(int index){
if (index < 0 || index >= _size)
{
return T();
}
if(index == 0)
return shift();
if (index == _size-1)
{
return pop();
}
ListNode<T> *tmp = getNode(index - 1);
ListNode<T> *toDelete = tmp->next;
T ret = toDelete->data;
tmp->next = tmp->next->next;
delete(toDelete);
_size--;
isCached = false;
return ret;
}
template<typename T>
T LinkedList<T>::get(int index){
ListNode<T> *tmp = getNode(index);
return (tmp ? tmp->data : T());
}
template<typename T>
void LinkedList<T>::clear(){
while(size() > 0)
shift();
}
template<typename T>
void LinkedList<T>::sort(int (*cmp)(T &, T &)){
if(_size < 2) return; // trivial case;
for(;;) {
ListNode<T> **joinPoint = &root;
while(*joinPoint) {
ListNode<T> *a = *joinPoint;
ListNode<T> *a_end = findEndOfSortedString(a, cmp);
if(!a_end->next ) {
if(joinPoint == &root) {
last = a_end;
isCached = false;
return;
}
else {
break;
}
}
ListNode<T> *b = a_end->next;
ListNode<T> *b_end = findEndOfSortedString(b, cmp);
ListNode<T> *tail = b_end->next;
a_end->next = NULL;
b_end->next = NULL;
while(a && b) {
if(cmp(a->data, b->data) <= 0) {
*joinPoint = a;
joinPoint = &a->next;
a = a->next;
}
else {
*joinPoint = b;
joinPoint = &b->next;
b = b->next;
}
}
if(a) {
*joinPoint = a;
while(a->next) a = a->next;
a->next = tail;
joinPoint = &a->next;
}
else {
*joinPoint = b;
while(b->next) b = b->next;
b->next = tail;
joinPoint = &b->next;
}
}
}
}
template<typename T>
ListNode<T>* LinkedList<T>::findEndOfSortedString(ListNode<T> *p, int (*cmp)(T &, T &)) {
while(p->next && cmp(p->data, p->next->data) <= 0) {
p = p->next;
}
return p;
}
#endif

View File

@ -220,7 +220,6 @@ const uint16_t MAX_LOGSZ = 700; // Max number of characters in log l
const uint8_t SENSOR_MAX_MISS = 5; // Max number of missed sensor reads before deciding it's offline
const uint8_t MAX_BACKLOG = 30; // Max number of commands in backlog
const uint32_t MIN_BACKLOG_DELAY = 200; // Minimal backlog delay in mSeconds
const uint8_t MAX_TIMED_CMND = 16; // Max number of timed commands

View File

@ -497,6 +497,7 @@
// -- Rules or Script ----------------------------
// Select none or only one of the below defines USE_RULES or USE_SCRIPT
#define USE_RULES // Add support for rules (+8k code)
// #define SUPPORT_MQTT_EVENT // Support trigger event with MQTT subscriptions (+3k5 code)
// #define USE_EXPRESSION // Add support for expression evaluation in rules (+3k2 code, +64 bytes mem)
// #define SUPPORT_IF_STATEMENT // Add support for IF statement in rules (+4k2 code, -332 bytes mem)
// #define USER_RULE1 "<Any rule1 data>" // Add rule1 data saved at initial firmware load or when command reset is executed

View File

@ -411,11 +411,6 @@ struct TasmotaGlobal_t {
uint8_t pwm_dimmer_led_bri; // Adjusted brightness LED level
#endif // USE_PWM_DIMMER
#ifndef SUPPORT_IF_STATEMENT
uint8_t backlog_index; // Command backlog index
uint8_t backlog_pointer; // Command backlog pointer
String backlog[MAX_BACKLOG]; // Command backlog buffer
#endif
tTimedCmnd timed_cmnd[MAX_TIMED_CMND]; // Timed command buffer
#ifdef MQTT_DATA_STRING
@ -438,19 +433,15 @@ struct TasmotaGlobal_t {
#endif // PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED
#ifdef USE_BERRY
bool berry_fast_loop_enabled = false; // is Berry fast loop enabled, i.e. control is passed at each loop iteration
bool berry_fast_loop_enabled = false; // is Berry fast loop enabled, i.e. control is passed at each loop iteration
#endif // USE_BERRY
} TasmotaGlobal;
TSettings* Settings = nullptr;
#ifdef SUPPORT_IF_STATEMENT
#include <LinkedList.h>
LinkedList<String> backlog; // Command backlog implemented with LinkedList
#define BACKLOG_EMPTY (backlog.size() == 0)
#else
#define BACKLOG_EMPTY (TasmotaGlobal.backlog_pointer == TasmotaGlobal.backlog_index)
#endif
#include <LinkedList.h>
LinkedList<String> backlog; // Command backlog implemented with LinkedList
#define BACKLOG_EMPTY (backlog.size() == 0)
/*********************************************************************************************\
* Main
@ -794,14 +785,7 @@ void BacklogLoop(void) {
bool nodelay_detected = false;
String cmd;
do {
#ifdef SUPPORT_IF_STATEMENT
cmd = backlog.shift();
#else
cmd = TasmotaGlobal.backlog[TasmotaGlobal.backlog_pointer];
TasmotaGlobal.backlog[TasmotaGlobal.backlog_pointer] = (const char*) nullptr; // Force deallocation of the String internal memory
TasmotaGlobal.backlog_pointer++;
if (TasmotaGlobal.backlog_pointer >= MAX_BACKLOG) { TasmotaGlobal.backlog_pointer = 0; }
#endif
nodelay_detected = !strncasecmp_P(cmd.c_str(), PSTR(D_CMND_NODELAY), strlen(D_CMND_NODELAY));
if (nodelay_detected) { nodelay = true; }
} while (!BACKLOG_EMPTY && nodelay_detected);

View File

@ -580,14 +580,7 @@ void CmndBacklog(void) {
}
char *blcommand = strtok(XdrvMailbox.data, ";");
#ifdef SUPPORT_IF_STATEMENT
while ((blcommand != nullptr) && (backlog.size() < MAX_BACKLOG))
#else
uint32_t bl_pointer = (!TasmotaGlobal.backlog_pointer) ? MAX_BACKLOG -1 : TasmotaGlobal.backlog_pointer;
bl_pointer--;
while ((blcommand != nullptr) && (TasmotaGlobal.backlog_index != bl_pointer))
#endif
{
while (blcommand != nullptr) {
// Ignore semicolon (; = end of single command) between brackets {}
char *next = strchr(blcommand, '\0') +1; // Prepare for next ;
while ((next != nullptr) && (ChrCount(blcommand, "{") != ChrCount(blcommand, "}"))) { // Check for valid {} pair
@ -606,17 +599,7 @@ void CmndBacklog(void) {
}
// Do not allow command Reset in backlog
if ((*blcommand != '\0') && (strncasecmp_P(blcommand, PSTR(D_CMND_RESET), strlen(D_CMND_RESET)) != 0)) {
#ifdef SUPPORT_IF_STATEMENT
if (backlog.size() < MAX_BACKLOG) {
backlog.add(blcommand);
}
#else
TasmotaGlobal.backlog[TasmotaGlobal.backlog_index] = blcommand;
TasmotaGlobal.backlog_index++;
if (TasmotaGlobal.backlog_index >= MAX_BACKLOG) {
TasmotaGlobal.backlog_index = 0;
}
#endif
backlog.add(blcommand);
}
blcommand = strtok(nullptr, ";");
}
@ -625,11 +608,7 @@ void CmndBacklog(void) {
TasmotaGlobal.backlog_timer = millis();
} else {
bool blflag = BACKLOG_EMPTY;
#ifdef SUPPORT_IF_STATEMENT
backlog.clear();
#else
TasmotaGlobal.backlog_pointer = TasmotaGlobal.backlog_index;
#endif
ResponseCmndChar(blflag ? PSTR(D_JSON_EMPTY) : PSTR(D_JSON_ABORTED));
}
}

View File

@ -657,7 +657,7 @@ void DomoticzSaveSettings(void) {
snprintf_P(arg_idx, sizeof(arg_idx), PSTR("l%d"), i -1);
cmnd += AddWebCommand(cmnd2, arg_idx, PSTR("0"));
}
ExecuteWebCommand((char*)cmnd.c_str()); // Note: beware of max number of commands in backlog currently 30 (MAX_BACKLOG)
ExecuteWebCommand((char*)cmnd.c_str());
}
#endif // USE_WEBSERVER

View File

@ -2066,7 +2066,7 @@ void ExecuteCommandBlock(const char * commands, int len)
sCurrentCommand.trim();
/*
if (sCurrentCommand.length() > 0
&& backlog.size() < MAX_BACKLOG && !TasmotaGlobal.backlog_mutex)
&& !TasmotaGlobal.backlog_mutex)
{
//Insert into backlog
TasmotaGlobal.backlog_mutex = true;
@ -2075,7 +2075,7 @@ void ExecuteCommandBlock(const char * commands, int len)
insertPosition++;
}
*/
if ((sCurrentCommand.length() > 0) && (backlog.size() < MAX_BACKLOG)) {
if (sCurrentCommand.length() > 0) {
//Insert into backlog
backlog.add(insertPosition, sCurrentCommand);
insertPosition++;