mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-24 19:26:37 +00:00
Introduce Expression in Rules
Support use an expression as paramter in some rule commands, include Var<x>, Mem<x> and Ruletimer<x>. Expression is constructed by constants (float number), variables (var<x>, mem<x>, Time, Uptime, Sunrise, Sunset), operators and round brackets. Currently support 6 operators, order by priority from high to low: ^ (power) % (modulo) *, / +, - Commands examples: Var1 3.14 * (MEM1 * (10 + VAR2 ^2) - 100) % 10 + uptime / (2 + MEM2) Ruletimer4 Time - Sunrise + MEM2/2
This commit is contained in:
parent
e779c7bdca
commit
4b4b3709ad
21
lib/LinkedList-1.2.3/LICENSE.txt
Normal file
21
lib/LinkedList-1.2.3/LICENSE.txt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Ivan Seidel
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
325
lib/LinkedList-1.2.3/LinkedList.h
Normal file
325
lib/LinkedList-1.2.3/LinkedList.h
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
/*
|
||||||
|
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);
|
||||||
|
|
||||||
|
public:
|
||||||
|
LinkedList();
|
||||||
|
~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;
|
||||||
|
Increment _size;
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
int LinkedList<T>::size(){
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
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>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
171
lib/LinkedList-1.2.3/README.md
Normal file
171
lib/LinkedList-1.2.3/README.md
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
# LinkedList
|
||||||
|
|
||||||
|
This library was developed targeting **`Arduino`** applications. However, works just great with any C++.
|
||||||
|
|
||||||
|
Implementing a buffer for objects takes time. If we are not in the mood, we just create an `array[1000]` with enough size.
|
||||||
|
|
||||||
|
The objective of this library is to create a pattern for projects.
|
||||||
|
If you need to use a List of: `int`, `float`, `objects`, `Lists` or `Wales`. **This is what you are looking for.**
|
||||||
|
|
||||||
|
With a simple but powerful caching algorithm, you can get subsequent objects much faster than usual. Tested without any problems with Lists bigger than 2000 members.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. [Download](https://github.com/ivanseidel/LinkedList/archive/master.zip) the Latest release from gitHub.
|
||||||
|
2. Unzip and modify the Folder name to "LinkedList" (Remove the '-version')
|
||||||
|
3. Paste the modified folder on your Library folder (On your `Libraries` folder inside Sketchbooks or Arduino software).
|
||||||
|
4. Reopen the Arduino software.
|
||||||
|
|
||||||
|
**If you are here, because another Library requires this class, just don't waste time reading bellow. Install and ready.**
|
||||||
|
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
### The `LinkedList` class
|
||||||
|
|
||||||
|
In case you don't know what a LinkedList is and what it's used for, take a quick look at [Wikipedia::LinkedList](https://en.wikipedia.org/wiki/Linked_list) before continuing.
|
||||||
|
|
||||||
|
#### To declare a LinkedList object
|
||||||
|
```c++
|
||||||
|
// Instantiate a LinkedList that will hold 'integer'
|
||||||
|
LinkedList<int> myLinkedList = LinkedList<int>();
|
||||||
|
|
||||||
|
// Or just this
|
||||||
|
LinkedList<int> myLinkedList;
|
||||||
|
|
||||||
|
// But if you are instantiating a pointer LinkedList...
|
||||||
|
LinkedList<int> *myLinkedList = new LinkedList<int>();
|
||||||
|
|
||||||
|
// If you want a LinkedList with any other type such as 'MyClass'
|
||||||
|
// Make sure you call delete(MyClass) when you remove!
|
||||||
|
LinkedList<MyClass> *myLinkedList = new LinkedList<MyClass>();
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Getting the size of the linked list
|
||||||
|
```c++
|
||||||
|
// To get the size of a linked list, make use of the size() method
|
||||||
|
int theSize = myList.size();
|
||||||
|
|
||||||
|
// Notice that if it's pointer to the linked list, you should use -> instead
|
||||||
|
int theSize = myList->size();
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Adding elements
|
||||||
|
|
||||||
|
```c++
|
||||||
|
// add(obj) method will insert at the END of the list
|
||||||
|
myList.add(myObject);
|
||||||
|
|
||||||
|
// add(index, obj) method will try to insert the object at the specified index
|
||||||
|
myList.add(0, myObject); // Add at the beginning
|
||||||
|
myList.add(3, myObject); // Add at index 3
|
||||||
|
|
||||||
|
// unshift(obj) method will insert the object at the beginning
|
||||||
|
myList.unshift(myObject);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Getting elements
|
||||||
|
|
||||||
|
```c++
|
||||||
|
// get(index) will return the element at index
|
||||||
|
// (notice that the start element is 0, not 1)
|
||||||
|
|
||||||
|
// Get the FIRST element
|
||||||
|
myObject = myList.get(0);
|
||||||
|
|
||||||
|
// Get the third element
|
||||||
|
myObject = myList.get(2);
|
||||||
|
|
||||||
|
// Get the LAST element
|
||||||
|
myObject = myList.get(myList.size() - 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Changing elements
|
||||||
|
```c++
|
||||||
|
// set(index, obj) method will change the object at index to obj
|
||||||
|
|
||||||
|
// Change the first element to myObject
|
||||||
|
myList.set(0, myObject);
|
||||||
|
|
||||||
|
// Change the third element to myObject
|
||||||
|
myList.set(2, myObject);
|
||||||
|
|
||||||
|
// Change the LAST element of the list
|
||||||
|
myList.set(myList.size() - 1, myObject);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Removing elements
|
||||||
|
```c++
|
||||||
|
// remove(index) will remove and return the element at index
|
||||||
|
|
||||||
|
// Remove the first object
|
||||||
|
myList.remove(0);
|
||||||
|
|
||||||
|
// Get and Delete the third element
|
||||||
|
myDeletedObject = myList.remove(2);
|
||||||
|
|
||||||
|
// pop() will remove and return the LAST element
|
||||||
|
myDeletedObject = myList.pop();
|
||||||
|
|
||||||
|
// shift() will remove and return the FIRST element
|
||||||
|
myDeletedObject = myList.shift();
|
||||||
|
|
||||||
|
// clear() will erase the entire list, leaving it with 0 elements
|
||||||
|
// NOTE: Clear wont DELETE/FREE memory from Pointers, if you
|
||||||
|
// are using Classes/Poiners, manualy delete and free those.
|
||||||
|
myList.clear();
|
||||||
|
```
|
||||||
|
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
## Library Reference
|
||||||
|
|
||||||
|
### `ListNode` struct
|
||||||
|
|
||||||
|
- `T` `ListNode::data` - The object data
|
||||||
|
|
||||||
|
- `ListNode<T>` `*next` - Pointer to the next Node
|
||||||
|
|
||||||
|
### `LinkedList` class
|
||||||
|
|
||||||
|
**`boolean` methods returns if succeeded**
|
||||||
|
|
||||||
|
- `LinkedList<T>::LinkedList()` - Constructor.
|
||||||
|
|
||||||
|
- `LinkedList<T>::~LinkedList()` - Destructor. Clear Nodes to minimize memory. Does not free pointer memory.
|
||||||
|
|
||||||
|
- `int` `LinkedList<T>::size()` - Returns the current size of the list.
|
||||||
|
|
||||||
|
- `bool` `LinkedList<T>::add(T)` - Add element T at the END of the list.
|
||||||
|
|
||||||
|
- `bool` `LinkedList<T>::add(int index, T)` - Add element T at `index` of the list.
|
||||||
|
|
||||||
|
- `bool` `LinkedList<T>::unshift(T)` - Add element T at the BEGINNING of the list.
|
||||||
|
|
||||||
|
- `bool` `LinkedList<T>::set(int index, T)` - Set the element at `index` to T.
|
||||||
|
|
||||||
|
- `T` `LinkedList<T>::remove(int index)` - Remove element at `index`. Return the removed element. Does not free pointer memory
|
||||||
|
|
||||||
|
- `T` `LinkedList<T>::pop()` - Remove the LAST element. Return the removed element.
|
||||||
|
|
||||||
|
- `T` `LinkedList<T>::shift()` - Remove the FIRST element. Return the removed element.
|
||||||
|
|
||||||
|
- `T` `LinkedList<T>::get(int index)` - Return the element at `index`.
|
||||||
|
|
||||||
|
- `void` `LinkedList<T>::clear()` - Removes all elements. Does not free pointer memory.
|
||||||
|
|
||||||
|
- **protected** `int` `LinkedList<T>::_size` - Holds the cached size of the list.
|
||||||
|
|
||||||
|
- **protected** `ListNode<T>` `LinkedList<T>::*root` - Holds the root node of the list.
|
||||||
|
|
||||||
|
- **protected** `ListNode<T>` `LinkedList<T>::*last` - Holds the last node of the list.
|
||||||
|
|
||||||
|
- **protected** `ListNode<T>*` `LinkedList<T>::getNode(int index)` - Returns the `index` node of the list.
|
||||||
|
|
||||||
|
### Version History
|
||||||
|
|
||||||
|
* `1.1 (2013-07-20)`: Cache implemented. Getting subsequent objects is now O(N). Before, O(N^2).
|
||||||
|
* `1.0 (2013-07-20)`: Original release
|
||||||
|
|
||||||
|

|
81
lib/LinkedList-1.2.3/examples/ClassList/ClassList.pde
Normal file
81
lib/LinkedList-1.2.3/examples/ClassList/ClassList.pde
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
LinkedList Example
|
||||||
|
Link: http://github.com/ivanseidel/LinkedList
|
||||||
|
|
||||||
|
Example Created by
|
||||||
|
Tom Stewart, github.com/tastewar
|
||||||
|
|
||||||
|
Edited by:
|
||||||
|
Ivan Seidel, github.com/ivanseidel
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LinkedList.h>
|
||||||
|
|
||||||
|
// Let's define a new class
|
||||||
|
class Animal {
|
||||||
|
public:
|
||||||
|
char *name;
|
||||||
|
bool isMammal;
|
||||||
|
};
|
||||||
|
|
||||||
|
char catname[]="kitty";
|
||||||
|
char dogname[]="doggie";
|
||||||
|
char emuname[]="emu";
|
||||||
|
|
||||||
|
LinkedList<Animal*> myAnimalList = LinkedList<Animal*>();
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
|
||||||
|
Serial.begin(9600);
|
||||||
|
Serial.println("Hello!" );
|
||||||
|
|
||||||
|
// Create a Cat
|
||||||
|
Animal *cat = new Animal();
|
||||||
|
cat->name = catname;
|
||||||
|
cat->isMammal = true;
|
||||||
|
|
||||||
|
// Create a dog
|
||||||
|
Animal *dog = new Animal();
|
||||||
|
dog->name = dogname;
|
||||||
|
dog->isMammal = true;
|
||||||
|
|
||||||
|
// Create a emu
|
||||||
|
Animal *emu = new Animal();
|
||||||
|
emu->name = emuname;
|
||||||
|
emu->isMammal = false; // just an example; no offense to pig lovers
|
||||||
|
|
||||||
|
// Add animals to list
|
||||||
|
myAnimalList.add(cat);
|
||||||
|
myAnimalList.add(emu);
|
||||||
|
myAnimalList.add(dog);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
Serial.print("There are ");
|
||||||
|
Serial.print(myAnimalList.size());
|
||||||
|
Serial.print(" animals in the list. The mammals are: ");
|
||||||
|
|
||||||
|
int current = 0;
|
||||||
|
Animal *animal;
|
||||||
|
for(int i = 0; i < myAnimalList.size(); i++){
|
||||||
|
|
||||||
|
// Get animal from list
|
||||||
|
animal = myAnimalList.get(i);
|
||||||
|
|
||||||
|
// If its a mammal, then print it's name
|
||||||
|
if(animal->isMammal){
|
||||||
|
|
||||||
|
// Avoid printing spacer on the first element
|
||||||
|
if(current++)
|
||||||
|
Serial.print(", ");
|
||||||
|
|
||||||
|
// Print animal name
|
||||||
|
Serial.print(animal->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.println(".");
|
||||||
|
|
||||||
|
while (true); // nothing else to do, loop forever
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
LinkedList Example
|
||||||
|
Link: http://github.com/ivanseidel/LinkedList
|
||||||
|
|
||||||
|
Example Created by
|
||||||
|
Tom Stewart, github.com/tastewar
|
||||||
|
|
||||||
|
Edited by:
|
||||||
|
Ivan Seidel, github.com/ivanseidel
|
||||||
|
*/
|
||||||
|
#include <LinkedList.h>
|
||||||
|
|
||||||
|
LinkedList<int> myList = LinkedList<int>();
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
|
||||||
|
Serial.begin(9600);
|
||||||
|
Serial.println("Hello!");
|
||||||
|
|
||||||
|
// Add some stuff to the list
|
||||||
|
int k = -240,
|
||||||
|
l = 123,
|
||||||
|
m = -2,
|
||||||
|
n = 222;
|
||||||
|
myList.add(n);
|
||||||
|
myList.add(0);
|
||||||
|
myList.add(l);
|
||||||
|
myList.add(17);
|
||||||
|
myList.add(k);
|
||||||
|
myList.add(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
int listSize = myList.size();
|
||||||
|
|
||||||
|
Serial.print("There are ");
|
||||||
|
Serial.print(listSize);
|
||||||
|
Serial.print(" integers in the list. The negative ones are: ");
|
||||||
|
|
||||||
|
// Print Negative numbers
|
||||||
|
for (int h = 0; h < listSize; h++) {
|
||||||
|
|
||||||
|
// Get value from list
|
||||||
|
int val = myList.get(h);
|
||||||
|
|
||||||
|
// If the value is negative, print it
|
||||||
|
if (val < 0) {
|
||||||
|
Serial.print(" ");
|
||||||
|
Serial.print(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true); // nothing else to do, loop forever
|
||||||
|
}
|
||||||
|
|
||||||
|
|
28
lib/LinkedList-1.2.3/keywords.txt
Normal file
28
lib/LinkedList-1.2.3/keywords.txt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#######################################
|
||||||
|
# Syntax Coloring
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Datatypes (KEYWORD1)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
LinkedList KEYWORD1
|
||||||
|
ListNode KEYWORD1
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Methods and Functions (KEYWORD2)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
size KEYWORD2
|
||||||
|
add KEYWORD2
|
||||||
|
unshift KEYWORD2
|
||||||
|
set KEYWORD2
|
||||||
|
remove KEYWORD2
|
||||||
|
pop KEYWORD2
|
||||||
|
shift KEYWORD2
|
||||||
|
get KEYWORD2
|
||||||
|
clear KEYWORD2
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Constants (LITERAL1)
|
||||||
|
#######################################
|
12
lib/LinkedList-1.2.3/library.json
Normal file
12
lib/LinkedList-1.2.3/library.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "LinkedList",
|
||||||
|
"keywords": "pattern",
|
||||||
|
"description": "A fully implemented LinkedList (int, float, objects, Lists or Wales) made to work with Arduino projects",
|
||||||
|
"repository":
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/ivanseidel/LinkedList.git"
|
||||||
|
},
|
||||||
|
"frameworks": "arduino",
|
||||||
|
"platforms": "*"
|
||||||
|
}
|
9
lib/LinkedList-1.2.3/library.properties
Normal file
9
lib/LinkedList-1.2.3/library.properties
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
name=LinkedList
|
||||||
|
version=1.2.3
|
||||||
|
author=Ivan Seidel <ivanseidel@gmail.com>
|
||||||
|
maintainer=Ivan Seidel <ivanseidel@gmail.com>
|
||||||
|
sentence=A fully implemented LinkedList made to work with Arduino projects
|
||||||
|
paragraph=The objective of this library is to create a pattern for projects. If you need to use a List of: int, float, objects, Lists or Wales. This is what you are looking for.
|
||||||
|
category=Data Processing
|
||||||
|
url=https://github.com/ivanseidel/LinkedList
|
||||||
|
architectures=*
|
@ -278,6 +278,9 @@
|
|||||||
|
|
||||||
// -- Rules ---------------------------------------
|
// -- Rules ---------------------------------------
|
||||||
#define USE_RULES // Add support for rules (+4k4 code)
|
#define USE_RULES // Add support for rules (+4k4 code)
|
||||||
|
#ifdef USE_RULES
|
||||||
|
#define USE_EXPRESSION // Add support for expression evaluation in rules (+3k1 code, +28 bytes mem)
|
||||||
|
#endif
|
||||||
|
|
||||||
// -- Internal Analog input -----------------------
|
// -- Internal Analog input -----------------------
|
||||||
#define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices
|
#define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices
|
||||||
|
@ -64,7 +64,9 @@
|
|||||||
#ifdef USE_SPI
|
#ifdef USE_SPI
|
||||||
#include <SPI.h> // SPI support, TFT
|
#include <SPI.h> // SPI support, TFT
|
||||||
#endif // USE_SPI
|
#endif // USE_SPI
|
||||||
|
#ifdef USE_EXPRESSION
|
||||||
|
#include <LinkedList.h> // Import LinkedList library
|
||||||
|
#endif
|
||||||
// Structs
|
// Structs
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|
||||||
|
@ -154,7 +154,7 @@ char* subStr(char* dest, char* str, const char *delim, int index)
|
|||||||
return sub;
|
return sub;
|
||||||
}
|
}
|
||||||
|
|
||||||
double CharToDouble(char *str)
|
double CharToDouble(const char *str)
|
||||||
{
|
{
|
||||||
// simple ascii to double, because atof or strtod are too large
|
// simple ascii to double, because atof or strtod are too large
|
||||||
char strbuf[24];
|
char strbuf[24];
|
||||||
|
@ -90,6 +90,19 @@
|
|||||||
#define MAXIMUM_COMPARE_OPERATOR COMPARE_OPERATOR_SMALLER_EQUAL
|
#define MAXIMUM_COMPARE_OPERATOR COMPARE_OPERATOR_SMALLER_EQUAL
|
||||||
const char kCompareOperators[] PROGMEM = "=\0>\0<\0|\0==!=>=<=";
|
const char kCompareOperators[] PROGMEM = "=\0>\0<\0|\0==!=>=<=";
|
||||||
|
|
||||||
|
#ifdef USE_EXPRESSION
|
||||||
|
const char kExpressionOperators[] PROGMEM = "+-*/%^";
|
||||||
|
#define EXPRESSION_OPERATOR_ADD 0
|
||||||
|
#define EXPRESSION_OPERATOR_SUBTRACT 1
|
||||||
|
#define EXPRESSION_OPERATOR_MULTIPLY 2
|
||||||
|
#define EXPRESSION_OPERATOR_DIVIDEDBY 3
|
||||||
|
#define EXPRESSION_OPERATOR_MODULO 4
|
||||||
|
#define EXPRESSION_OPERATOR_POWER 5
|
||||||
|
|
||||||
|
const uint8_t kExpressionOperatorsPriorities[] PROGMEM = {1, 1, 2, 2, 3, 4};
|
||||||
|
#define MAX_EXPRESSION_OPERATOR_PRIORITY 4
|
||||||
|
#endif //USE_EXPRESSION
|
||||||
|
|
||||||
enum RulesCommands { CMND_RULE, CMND_RULETIMER, CMND_EVENT, CMND_VAR, CMND_MEM, CMND_ADD, CMND_SUB, CMND_MULT, CMND_SCALE, CMND_CALC_RESOLUTION };
|
enum RulesCommands { CMND_RULE, CMND_RULETIMER, CMND_EVENT, CMND_VAR, CMND_MEM, CMND_ADD, CMND_SUB, CMND_MULT, CMND_SCALE, CMND_CALC_RESOLUTION };
|
||||||
const char kRulesCommands[] PROGMEM = D_CMND_RULE "|" D_CMND_RULETIMER "|" D_CMND_EVENT "|" D_CMND_VAR "|" D_CMND_MEM "|" D_CMND_ADD "|" D_CMND_SUB "|" D_CMND_MULT "|" D_CMND_SCALE "|" D_CMND_CALC_RESOLUTION ;
|
const char kRulesCommands[] PROGMEM = D_CMND_RULE "|" D_CMND_RULETIMER "|" D_CMND_EVENT "|" D_CMND_VAR "|" D_CMND_MEM "|" D_CMND_ADD "|" D_CMND_SUB "|" D_CMND_MULT "|" D_CMND_SCALE "|" D_CMND_CALC_RESOLUTION ;
|
||||||
|
|
||||||
@ -562,6 +575,310 @@ void RulesTeleperiod(void)
|
|||||||
rules_teleperiod = 0;
|
rules_teleperiod = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_EXPRESSION
|
||||||
|
/********************************************************************************************/
|
||||||
|
/*
|
||||||
|
* Parse a number value
|
||||||
|
* Input:
|
||||||
|
* pNumber - A char pointer point to a digit started string (guaranteed)
|
||||||
|
* value - Reference a double variable used to accept the result
|
||||||
|
* Output:
|
||||||
|
* pNumber - Pointer forward to next character after the number
|
||||||
|
* value - double type, the result value
|
||||||
|
* Return:
|
||||||
|
* true - succeed
|
||||||
|
* false - failed
|
||||||
|
*/
|
||||||
|
bool findNextNumber(char * &pNumber, double &value)
|
||||||
|
{
|
||||||
|
bool bSucceed = false;
|
||||||
|
String sNumber = "";
|
||||||
|
while (*pNumber) {
|
||||||
|
if (isdigit(*pNumber) || (*pNumber == '.')) {
|
||||||
|
sNumber += *pNumber;
|
||||||
|
pNumber++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sNumber.length() > 0) {
|
||||||
|
value = CharToDouble(sNumber.c_str());
|
||||||
|
bSucceed = true;
|
||||||
|
}
|
||||||
|
return bSucceed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************/
|
||||||
|
/*
|
||||||
|
* Parse a variable (like VAR1, MEM3) and get its value (double type)
|
||||||
|
* Input:
|
||||||
|
* pVarname - A char pointer point to a variable name string
|
||||||
|
* value - Reference a double variable used to accept the result
|
||||||
|
* Output:
|
||||||
|
* pVarname - Pointer forward to next character after the variable
|
||||||
|
* value - double type, the result value
|
||||||
|
* Return:
|
||||||
|
* true - succeed
|
||||||
|
* false - failed
|
||||||
|
*/
|
||||||
|
bool findNextVariableValue(char * &pVarname, double &value)
|
||||||
|
{
|
||||||
|
bool succeed = false;
|
||||||
|
value = 0;
|
||||||
|
String sVarName = "";
|
||||||
|
while (*pVarname) {
|
||||||
|
if (isalpha(*pVarname) || isdigit(*pVarname)) {
|
||||||
|
sVarName.concat(*pVarname);
|
||||||
|
pVarname++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sVarName.toUpperCase();
|
||||||
|
if (sVarName.startsWith("VAR")) {
|
||||||
|
int index = sVarName.substring(3).toInt();
|
||||||
|
if (index > 0 && index <= MAX_RULE_VARS) {
|
||||||
|
value = CharToDouble(vars[index -1]);
|
||||||
|
succeed = true;
|
||||||
|
}
|
||||||
|
} else if (sVarName.startsWith("MEM")) {
|
||||||
|
int index = sVarName.substring(3).toInt();
|
||||||
|
if (index > 0 && index <= MAX_RULE_MEMS) {
|
||||||
|
value = CharToDouble(Settings.mems[index -1]);
|
||||||
|
succeed = true;
|
||||||
|
}
|
||||||
|
} else if (sVarName.equals("TIME")) {
|
||||||
|
value = GetMinutesPastMidnight();
|
||||||
|
succeed = true;
|
||||||
|
} else if (sVarName.equals("UPTIME")) {
|
||||||
|
value = GetMinutesUptime();
|
||||||
|
succeed = true;
|
||||||
|
#if defined(USE_TIMERS) && defined(USE_SUNRISE)
|
||||||
|
} else if (sVarName.equals("SUNRISE")) {
|
||||||
|
value = GetSunMinutes(0);
|
||||||
|
succeed = true;
|
||||||
|
} else if (sVarName.equals("SUNSET")) {
|
||||||
|
value = GetSunMinutes(1);
|
||||||
|
succeed = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return succeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************/
|
||||||
|
/*
|
||||||
|
* Find next object in expression and evaluate it
|
||||||
|
* An object could be:
|
||||||
|
* - A float number start with a digit, like 0.787
|
||||||
|
* - A variable name, like VAR1, MEM3
|
||||||
|
* - An expression enclosed with a pair of round brackets, (.....)
|
||||||
|
* Input:
|
||||||
|
* pointer - A char pointer point to a place of the expression string
|
||||||
|
* value - Reference a double variable used to accept the result
|
||||||
|
* Output:
|
||||||
|
* pointer - Pointer forward to next character after next object
|
||||||
|
* value - double type, the result value
|
||||||
|
* Return:
|
||||||
|
* true - succeed
|
||||||
|
* false - failed
|
||||||
|
*/
|
||||||
|
bool findNextObjectValue(char * &pointer, double &value)
|
||||||
|
{
|
||||||
|
bool bSucceed = false;
|
||||||
|
while (*pointer)
|
||||||
|
{
|
||||||
|
if (isspace(*pointer)) { //Skip leading spaces
|
||||||
|
pointer++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isdigit(*pointer)) { //This object is a number
|
||||||
|
bSucceed = findNextNumber(pointer, value);
|
||||||
|
break;
|
||||||
|
} else if (isalpha(*pointer)) { //Should be a variable like VAR12, MEM1
|
||||||
|
bSucceed = findNextVariableValue(pointer, value);
|
||||||
|
break;
|
||||||
|
} else if (*pointer == '(') { //It is a sub expression bracketed with ()
|
||||||
|
pointer++;
|
||||||
|
char * sub_exp_start = pointer; //Find out the sub expression between a pair of parenthesis. "()"
|
||||||
|
unsigned int sub_exp_len = 0;
|
||||||
|
//Look for the matched closure parenthesis.")"
|
||||||
|
bool bFindClosures = false;
|
||||||
|
uint8_t matchClosures = 1;
|
||||||
|
while (*pointer)
|
||||||
|
{
|
||||||
|
if (*pointer == ')') {
|
||||||
|
matchClosures--;
|
||||||
|
if (matchClosures == 0) {
|
||||||
|
sub_exp_len = pointer - sub_exp_start;
|
||||||
|
bFindClosures = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (*pointer == '(') {
|
||||||
|
matchClosures++;
|
||||||
|
}
|
||||||
|
pointer++;
|
||||||
|
}
|
||||||
|
if (bFindClosures) {
|
||||||
|
value = evaluateExpression(sub_exp_start, sub_exp_len);
|
||||||
|
bSucceed = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else { //No number, no variable, no expression, then invalid object.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bSucceed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************/
|
||||||
|
/*
|
||||||
|
* Find next operator in expression
|
||||||
|
* An operator could be: +, - , * , / , %, ^
|
||||||
|
* Input:
|
||||||
|
* pointer - A char pointer point to a place of the expression string
|
||||||
|
* op - Reference to a variable used to accept the result
|
||||||
|
* Output:
|
||||||
|
* pointer - Pointer forward to next character after next operator
|
||||||
|
* op - The operator. 0, 1, 2, 3, 4, 5
|
||||||
|
* Return:
|
||||||
|
* true - succeed
|
||||||
|
* false - failed
|
||||||
|
*/
|
||||||
|
bool findNextOperator(char * &pointer, int8_t &op)
|
||||||
|
{
|
||||||
|
bool bSucceed = false;
|
||||||
|
while (*pointer)
|
||||||
|
{
|
||||||
|
if (isspace(*pointer)) { //Skip leading spaces
|
||||||
|
pointer++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (char *pch = strchr(kExpressionOperators, *pointer)) { //If it is an operator
|
||||||
|
op = (int8_t)(pch - kExpressionOperators);
|
||||||
|
pointer++;
|
||||||
|
bSucceed = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return bSucceed;
|
||||||
|
}
|
||||||
|
/********************************************************************************************/
|
||||||
|
/*
|
||||||
|
* Calculate a simple expression composed by 2 value and 1 operator, like 2 * 3
|
||||||
|
* Input:
|
||||||
|
* pointer - A char pointer point to a place of the expression string
|
||||||
|
* value - Reference a double variable used to accept the result
|
||||||
|
* Output:
|
||||||
|
* pointer - Pointer forward to next character after next object
|
||||||
|
* value - double type, the result value
|
||||||
|
* Return:
|
||||||
|
* true - succeed
|
||||||
|
* false - failed
|
||||||
|
*/
|
||||||
|
double calculateTwoValues(double v1, double v2, uint8_t op)
|
||||||
|
{
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case EXPRESSION_OPERATOR_ADD:
|
||||||
|
return v1 + v2;
|
||||||
|
case EXPRESSION_OPERATOR_SUBTRACT:
|
||||||
|
return v1 - v2;
|
||||||
|
case EXPRESSION_OPERATOR_MULTIPLY:
|
||||||
|
return v1 * v2;
|
||||||
|
case EXPRESSION_OPERATOR_DIVIDEDBY:
|
||||||
|
return (0 == v2) ? 0 : (v1 / v2);
|
||||||
|
case EXPRESSION_OPERATOR_MODULO:
|
||||||
|
return (0 == v2) ? 0 : (int(v1) % int(v2));
|
||||||
|
case EXPRESSION_OPERATOR_POWER:
|
||||||
|
return FastPrecisePow(v1, v2);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************/
|
||||||
|
/*
|
||||||
|
* Parse and evaluate an expression.
|
||||||
|
* For example: "10 * ( MEM2 + 1) / 2"
|
||||||
|
* Right now, only support operators listed here: (order by priority)
|
||||||
|
* Priority 4: ^ (power)
|
||||||
|
* Priority 3: % (modulo, always get integer result)
|
||||||
|
* Priority 2: *, /
|
||||||
|
* Priority 1: +, -
|
||||||
|
* Input:
|
||||||
|
* expression - The expression to be evaluated
|
||||||
|
* len - Length of the expression
|
||||||
|
* Return:
|
||||||
|
* double - result.
|
||||||
|
* 0 - if the expression is invalid
|
||||||
|
* An example:
|
||||||
|
* MEM1 = 3, MEM2 = 6, VAR2 = 15, VAR10 = 80
|
||||||
|
* At beginning, the expression might be complicated like: 3.14 * (MEM1 * (10 + VAR2 ^2) - 100) % 10 + VAR10 / (2 + MEM2)
|
||||||
|
* We are going to scan the whole expression, evaluate each object.
|
||||||
|
* Finally we will have a value list:.
|
||||||
|
* Order Object Value
|
||||||
|
* 0 3.14 3.14
|
||||||
|
* 1 (MEM1 * (10 + VAR2 ^2) - 100) 605
|
||||||
|
* 2 10 10
|
||||||
|
* 3 VAR10 80
|
||||||
|
* 4 (2 + MEM2) 8
|
||||||
|
* And an operator list:
|
||||||
|
* Order Operator Priority
|
||||||
|
* 0 * 2
|
||||||
|
* 1 % 3
|
||||||
|
* 2 + 1
|
||||||
|
* 3 / 2
|
||||||
|
*/
|
||||||
|
double evaluateExpression(const char * expression, unsigned int len)
|
||||||
|
{
|
||||||
|
char expbuf[len + 1];
|
||||||
|
memcpy(expbuf, expression, len);
|
||||||
|
expbuf[len] = '\0';
|
||||||
|
char * scan_pointer = expbuf;
|
||||||
|
|
||||||
|
LinkedList<double> object_values;
|
||||||
|
LinkedList<int8_t> operators;
|
||||||
|
int8_t op;
|
||||||
|
double va;
|
||||||
|
//Find and add the value of first object
|
||||||
|
if (findNextObjectValue(scan_pointer, va)) {
|
||||||
|
object_values.add(va);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
while (*scan_pointer)
|
||||||
|
{
|
||||||
|
if (findNextOperator(scan_pointer, op)
|
||||||
|
&& *scan_pointer
|
||||||
|
&& findNextObjectValue(scan_pointer, va))
|
||||||
|
{
|
||||||
|
operators.add(op);
|
||||||
|
object_values.add(va);
|
||||||
|
} else {
|
||||||
|
//No operator followed or no more object after this operator, we done.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Going to evaluate the whole expression
|
||||||
|
//Calculate by order of operator priorities. Looking for all operators with specified priority (from High to Low)
|
||||||
|
for (int8_t priority = MAX_EXPRESSION_OPERATOR_PRIORITY; priority>0; priority--) {
|
||||||
|
int index = 0;
|
||||||
|
while (index < operators.size()) {
|
||||||
|
if (priority == kExpressionOperatorsPriorities[(operators.get(index))]) { //need to calculate the operator first
|
||||||
|
//get current object value and remove the next object with current operator
|
||||||
|
va = calculateTwoValues(object_values.get(index), object_values.remove(index + 1), operators.remove(index));
|
||||||
|
//Replace the current value with the result
|
||||||
|
object_values.set(index, va);
|
||||||
|
} else {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return object_values.get(0);
|
||||||
|
}
|
||||||
|
#endif //USE_EXPRESSION
|
||||||
|
|
||||||
bool RulesCommand(void)
|
bool RulesCommand(void)
|
||||||
{
|
{
|
||||||
char command[CMDSZ];
|
char command[CMDSZ];
|
||||||
@ -620,7 +937,12 @@ bool RulesCommand(void)
|
|||||||
}
|
}
|
||||||
else if ((CMND_RULETIMER == command_code) && (index > 0) && (index <= MAX_RULE_TIMERS)) {
|
else if ((CMND_RULETIMER == command_code) && (index > 0) && (index <= MAX_RULE_TIMERS)) {
|
||||||
if (XdrvMailbox.data_len > 0) {
|
if (XdrvMailbox.data_len > 0) {
|
||||||
|
#ifdef USE_EXPRESSION
|
||||||
|
double timer_set = evaluateExpression(XdrvMailbox.data, XdrvMailbox.data_len);
|
||||||
|
rules_timer[index -1] = (timer_set > 0) ? millis() + (1000 * timer_set) : 0;
|
||||||
|
#else
|
||||||
rules_timer[index -1] = (XdrvMailbox.payload > 0) ? millis() + (1000 * XdrvMailbox.payload) : 0;
|
rules_timer[index -1] = (XdrvMailbox.payload > 0) ? millis() + (1000 * XdrvMailbox.payload) : 0;
|
||||||
|
#endif //USE_EXPRESSION
|
||||||
}
|
}
|
||||||
mqtt_data[0] = '\0';
|
mqtt_data[0] = '\0';
|
||||||
for (uint8_t i = 0; i < MAX_RULE_TIMERS; i++) {
|
for (uint8_t i = 0; i < MAX_RULE_TIMERS; i++) {
|
||||||
@ -636,14 +958,22 @@ bool RulesCommand(void)
|
|||||||
}
|
}
|
||||||
else if ((CMND_VAR == command_code) && (index > 0) && (index <= MAX_RULE_VARS)) {
|
else if ((CMND_VAR == command_code) && (index > 0) && (index <= MAX_RULE_VARS)) {
|
||||||
if (XdrvMailbox.data_len > 0) {
|
if (XdrvMailbox.data_len > 0) {
|
||||||
|
#ifdef USE_EXPRESSION
|
||||||
|
dtostrfd(evaluateExpression(XdrvMailbox.data, XdrvMailbox.data_len), Settings.flag2.calc_resolution, vars[index -1]);
|
||||||
|
#else
|
||||||
strlcpy(vars[index -1], ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data, sizeof(vars[index -1]));
|
strlcpy(vars[index -1], ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data, sizeof(vars[index -1]));
|
||||||
|
#endif //USE_EXPRESSION
|
||||||
bitSet(vars_event, index -1);
|
bitSet(vars_event, index -1);
|
||||||
}
|
}
|
||||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
|
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
|
||||||
}
|
}
|
||||||
else if ((CMND_MEM == command_code) && (index > 0) && (index <= MAX_RULE_MEMS)) {
|
else if ((CMND_MEM == command_code) && (index > 0) && (index <= MAX_RULE_MEMS)) {
|
||||||
if (XdrvMailbox.data_len > 0) {
|
if (XdrvMailbox.data_len > 0) {
|
||||||
|
#ifdef USE_EXPRESSION
|
||||||
|
dtostrfd(evaluateExpression(XdrvMailbox.data, XdrvMailbox.data_len), Settings.flag2.calc_resolution, Settings.mems[index -1]);
|
||||||
|
#else
|
||||||
strlcpy(Settings.mems[index -1], ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data, sizeof(Settings.mems[index -1]));
|
strlcpy(Settings.mems[index -1], ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data, sizeof(Settings.mems[index -1]));
|
||||||
|
#endif //USE_EXPRESSION
|
||||||
bitSet(mems_event, index -1);
|
bitSet(mems_event, index -1);
|
||||||
}
|
}
|
||||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.mems[index -1]);
|
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.mems[index -1]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user