Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

932 lines
28 KiB

Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
  1. /*
  2. RPN RULES MODULE
  3. Use RPNLib library (https://github.com/xoseperez/rpnlib)
  4. Copyright (C) 2019 by Xose Pérez <xose dot perez at gmail dot com>
  5. */
  6. #include "rpnrules.h"
  7. #if RPN_RULES_SUPPORT
  8. #include "broker.h"
  9. #include "mqtt.h"
  10. #include "ntp.h"
  11. #include "relay.h"
  12. #include "rfbridge.h"
  13. #include "rpc.h"
  14. #include "rtcmem.h"
  15. #include "sensor.h"
  16. #include "terminal.h"
  17. #include "wifi.h"
  18. #include "ws.h"
  19. #include <list>
  20. #include <vector>
  21. // -----------------------------------------------------------------------------
  22. // Custom commands
  23. // -----------------------------------------------------------------------------
  24. rpn_context _rpn_ctxt;
  25. bool _rpn_run = false;
  26. unsigned long _rpn_delay = RPN_DELAY;
  27. unsigned long _rpn_last = 0;
  28. struct RpnRunner {
  29. enum class Policy {
  30. OneShot,
  31. Periodic
  32. };
  33. RpnRunner(Policy policy_, uint32_t period_) :
  34. policy(policy_),
  35. period(period_),
  36. last(millis())
  37. {}
  38. Policy policy { Policy::Periodic };
  39. uint32_t period { 0ul };
  40. uint32_t last { 0ul };
  41. bool expired { false };
  42. };
  43. std::vector<RpnRunner> _rpn_runners;
  44. rpn_operator_error _rpnRunnerHandler(rpn_context & ctxt, RpnRunner::Policy policy, uint32_t time) {
  45. for (auto& runner : _rpn_runners) {
  46. if ((policy == runner.policy) && (time == runner.period)) {
  47. return runner.expired
  48. ? rpn_operator_error::Ok
  49. : rpn_operator_error::CannotContinue;
  50. }
  51. }
  52. _rpn_runners.emplace_back(policy, time);
  53. return rpn_operator_error::CannotContinue;
  54. }
  55. // -----------------------------------------------------------------------------
  56. bool _rpnWebSocketOnKeyCheck(const char * key, JsonVariant& value) {
  57. return (strncmp(key, "rpn", 3) == 0);
  58. }
  59. void _rpnWebSocketOnConnected(JsonObject& root) {
  60. root["rpnSticky"] = getSetting("rpnSticky", 1 == RPN_STICKY);
  61. root["rpnDelay"] = getSetting("rpnDelay", RPN_DELAY);
  62. JsonArray& rules = root.createNestedArray("rpnRules");
  63. unsigned char i = 0;
  64. String rule = getSetting({"rpnRule", i});
  65. while (rule.length()) {
  66. rules.add(rule);
  67. rule = getSetting({"rpnRule", ++i});
  68. }
  69. #if MQTT_SUPPORT
  70. i=0;
  71. JsonArray& topics = root.createNestedArray("rpnTopics");
  72. JsonArray& names = root.createNestedArray("rpnNames");
  73. String rpn_topic = getSetting({"rpnTopic", i});
  74. while (rpn_topic.length() > 0) {
  75. String rpn_name = getSetting({"rpnName", i});
  76. topics.add(rpn_topic);
  77. names.add(rpn_name);
  78. rpn_topic = getSetting({"rpnTopic", ++i});
  79. }
  80. #endif
  81. }
  82. #if MQTT_SUPPORT
  83. void _rpnMQTTSubscribe() {
  84. unsigned char i = 0;
  85. String rpn_topic = getSetting({"rpnTopic", i});
  86. while (rpn_topic.length()) {
  87. mqttSubscribeRaw(rpn_topic.c_str());
  88. rpn_topic = getSetting({"rpnTopic", ++i});
  89. }
  90. }
  91. void _rpnMQTTCallback(unsigned int type, const char * topic, const char * payload) {
  92. if (type == MQTT_CONNECT_EVENT) {
  93. _rpnMQTTSubscribe();
  94. }
  95. if (type == MQTT_MESSAGE_EVENT) {
  96. unsigned char i = 0;
  97. String rpn_topic = getSetting({"rpnTopic", i});
  98. while (rpn_topic.length()) {
  99. if (rpn_topic.equals(topic)) {
  100. String rpn_name = getSetting({"rpnName", i});
  101. if (rpn_name.length()) {
  102. rpn_value value { atof(payload) };
  103. rpn_variable_set(_rpn_ctxt, rpn_name, value);
  104. _rpn_run = true;
  105. break;
  106. }
  107. }
  108. rpn_topic = getSetting({"rpnTopic", ++i});
  109. }
  110. }
  111. }
  112. #endif // MQTT_SUPPORT
  113. void _rpnConfigure() {
  114. #if MQTT_SUPPORT
  115. if (mqttConnected()) _rpnMQTTSubscribe();
  116. #endif
  117. _rpn_delay = getSetting("rpnDelay", RPN_DELAY);
  118. }
  119. void _rpnBrokerCallback(const String& topic, unsigned char id, double value, const char*) {
  120. char name[32] = {0};
  121. snprintf(name, sizeof(name), "%s%u", topic.c_str(), id);
  122. if (topic == MQTT_TOPIC_RELAY) {
  123. rpn_variable_set(_rpn_ctxt, name, rpn_value(static_cast<bool>(value)));
  124. } else {
  125. rpn_variable_set(_rpn_ctxt, name, rpn_value(value));
  126. }
  127. _rpn_run = true;
  128. }
  129. void _rpnBrokerStatus(const String& topic, unsigned char id, unsigned int value) {
  130. _rpnBrokerCallback(topic, id, double(value), nullptr);
  131. }
  132. #if NTP_SUPPORT
  133. rpn_error _rpnNtpNow(rpn_context & ctxt) {
  134. if (!ntpSynced()) return rpn_operator_error::CannotContinue;
  135. rpn_value ts { static_cast<rpn_int>(now()) };
  136. rpn_stack_push(ctxt, ts);
  137. return 0;
  138. }
  139. rpn_error _rpnNtpFunc(rpn_context & ctxt, rpn_int (*func)(time_t)) {
  140. rpn_value value;
  141. rpn_stack_pop(ctxt, value);
  142. value = rpn_value(func(value.toInt()));
  143. rpn_stack_push(ctxt, value);
  144. return 0;
  145. }
  146. #endif // NTP_SUPPORT
  147. String _rpnValueToString(const rpn_value& value) {
  148. String out;
  149. if (value.isString()) {
  150. out = value.toString();
  151. } else if (value.isFloat()) {
  152. out = String(value.toFloat(), 10);
  153. } else if (value.isInt()) {
  154. out = String(value.toInt(), 10);
  155. } else if (value.isUint()) {
  156. out = String(value.toUint(), 10);
  157. } else if (value.isBoolean()) {
  158. out = String(value.toBoolean() ? "true" : "false");
  159. } else if (value.isNull()) {
  160. out = F("(null)");
  161. }
  162. return out;
  163. }
  164. char _rpnStackTypeTag(rpn_stack_value::Type type) {
  165. switch (type) {
  166. case rpn_stack_value::Type::None:
  167. return 'N';
  168. case rpn_stack_value::Type::Variable:
  169. return '$';
  170. case rpn_stack_value::Type::Array:
  171. return 'A';
  172. case rpn_stack_value::Type::Value:
  173. default:
  174. return ' ';
  175. }
  176. }
  177. #if RELAY_SUPPORT
  178. rpn_error _rpnRelayStatus(rpn_context & ctxt, bool force) {
  179. rpn_value id;
  180. rpn_value status;
  181. rpn_stack_pop(ctxt, id);
  182. rpn_stack_pop(ctxt, status);
  183. rpn_uint value = status.toUint();
  184. if (value == 2) {
  185. relayToggle(id.toUint());
  186. } else if (relayStatusTarget(id.toUint()) != (value == 1)) {
  187. relayStatus(id.toUint(), value == 1);
  188. }
  189. return 0;
  190. }
  191. #endif // RELAY_SUPPORT
  192. #if RFB_SUPPORT
  193. struct rpn_rfbridge_code {
  194. unsigned char protocol;
  195. String raw;
  196. size_t count;
  197. decltype(millis()) last;
  198. };
  199. // TODO: in theory, we could do with forward_list. however, this would require a more complicated removal process,
  200. // as we would no longer know the previous element and would need to track 2 elements at a time
  201. static std::list<rpn_rfbridge_code> _rfb_codes;
  202. static uint32_t _rfb_code_repeat_window;
  203. static uint32_t _rfb_code_stale_delay;
  204. static uint32_t _rfb_code_match_window;
  205. struct rpn_rfbridge_match {
  206. unsigned char protocol;
  207. String raw;
  208. };
  209. rpn_error _rpnRfbSequence(rpn_context& ctxt) {
  210. auto raw_second = rpn_stack_pop(ctxt);
  211. auto proto_second = rpn_stack_pop(ctxt);
  212. auto raw_first = rpn_stack_pop(ctxt);
  213. auto proto_first = rpn_stack_pop(ctxt);
  214. // find 2 codes in the same order and save pointers
  215. rpn_rfbridge_match match[2] {
  216. {static_cast<unsigned char>(proto_first.toUint()), raw_first.toString()},
  217. {static_cast<unsigned char>(proto_second.toUint()), raw_second.toString()}
  218. };
  219. rpn_rfbridge_code* refs[2] {nullptr, nullptr};
  220. for (auto& recent : _rfb_codes) {
  221. if ((refs[0] != nullptr) && (refs[1] != nullptr)) {
  222. break;
  223. }
  224. for (int index = 0; index < 2; ++index) {
  225. if ((refs[index] == nullptr)
  226. && (match[index].protocol == recent.protocol)
  227. && (match[index].raw == recent.raw)) {
  228. refs[index] = &recent;
  229. }
  230. }
  231. }
  232. if ((refs[0] == nullptr) || (refs[1] == nullptr)) {
  233. return rpn_operator_error::CannotContinue;
  234. }
  235. // purge codes to avoid matching again on the next rules run
  236. if ((millis() - refs[0]->last) > (millis() - refs[1]->last)) {
  237. _rfb_codes.remove_if([&refs](rpn_rfbridge_code& code) {
  238. return (refs[0] == &code) || (refs[1] == &code);
  239. });
  240. return rpn_operator_error::Ok;
  241. }
  242. return rpn_operator_error::CannotContinue;
  243. }
  244. decltype(_rfb_codes)::iterator _rpnRfbFindCode(unsigned char protocol, const String& match) {
  245. return std::find_if(_rfb_codes.begin(), _rfb_codes.end(), [protocol, &match](const rpn_rfbridge_code& code) {
  246. return (code.protocol == protocol) && (code.raw == match);
  247. });
  248. }
  249. rpn_error _rpnRfbPop(rpn_context& ctxt) {
  250. auto code = rpn_stack_pop(ctxt);
  251. auto proto = rpn_stack_pop(ctxt);
  252. auto result = _rpnRfbFindCode(proto.toUint(), code.toString());
  253. if (result == _rfb_codes.end()) {
  254. return rpn_operator_error::CannotContinue;
  255. }
  256. _rfb_codes.erase(result);
  257. return rpn_operator_error::Ok;
  258. }
  259. rpn_error _rpnRfbInfo(rpn_context& ctxt) {
  260. auto code = rpn_stack_pop(ctxt);
  261. auto proto = rpn_stack_pop(ctxt);
  262. auto result = _rpnRfbFindCode(proto.toUint(), code.toString());
  263. if (result == _rfb_codes.end()) {
  264. return rpn_operator_error::CannotContinue;
  265. }
  266. rpn_stack_push(ctxt, rpn_value(
  267. static_cast<rpn_uint>((*result).count)));
  268. rpn_stack_push(ctxt, rpn_value(
  269. static_cast<rpn_uint>((*result).last)));
  270. return rpn_operator_error::Ok;
  271. }
  272. rpn_error _rpnRfbWaitMatch(rpn_context& ctxt) {
  273. auto code = rpn_stack_pop(ctxt);
  274. auto proto = rpn_stack_pop(ctxt);
  275. auto count = rpn_stack_pop(ctxt);
  276. auto time = rpn_stack_pop(ctxt);
  277. auto result = _rpnRfbFindCode(proto.toUint(), code.toString());
  278. if (result == _rfb_codes.end()) {
  279. return rpn_operator_error::CannotContinue;
  280. }
  281. if ((*result).count < count.toUint()) {
  282. return rpn_operator_error::CannotContinue;
  283. }
  284. // purge code to avoid matching again on the next rules run
  285. if (rpn_operator_error::Ok == _rpnRunnerHandler(ctxt, RpnRunner::Policy::OneShot, time.toUint())) {
  286. _rfb_codes.erase(result);
  287. return rpn_operator_error::Ok;
  288. }
  289. return rpn_operator_error::CannotContinue;
  290. }
  291. rpn_error _rpnRfbMatcher(rpn_context& ctxt) {
  292. auto code = rpn_stack_pop(ctxt);
  293. auto proto = rpn_stack_pop(ctxt);
  294. auto count = rpn_stack_pop(ctxt);
  295. auto result = _rpnRfbFindCode(proto.toUint(), code.toString());
  296. if (result == _rfb_codes.end()) {
  297. return rpn_operator_error::CannotContinue;
  298. }
  299. // only process recent codes, ignore when rule is processing outside of this small window
  300. if (millis() - (*result).last >= _rfb_code_match_window) {
  301. return rpn_operator_error::CannotContinue;
  302. }
  303. // purge code to avoid matching again on the next rules run
  304. if ((*result).count == count.toUint()) {
  305. _rfb_codes.erase(result);
  306. return rpn_operator_error::Ok;
  307. }
  308. return rpn_operator_error::CannotContinue;
  309. }
  310. void _rpnBrokerRfbridgeCallback(unsigned char protocol, const char* raw_code) {
  311. // remove really old codes that we have not seen in a while to avoid memory exhaustion
  312. auto ts = millis();
  313. auto old = std::remove_if(_rfb_codes.begin(), _rfb_codes.end(), [ts](rpn_rfbridge_code& code) {
  314. return (ts - code.last) >= _rfb_code_stale_delay;
  315. });
  316. if (old != _rfb_codes.end()) {
  317. _rfb_codes.erase(old, _rfb_codes.end());
  318. }
  319. auto result = _rpnRfbFindCode(protocol, raw_code);
  320. if (result != _rfb_codes.end()) {
  321. // we also need to reset the counter at a certain point to allow next batch of repeats to go through
  322. if (millis() - (*result).last >= _rfb_code_repeat_window) {
  323. (*result).count = 0;
  324. }
  325. (*result).last = millis();
  326. (*result).count += 1u;
  327. } else {
  328. _rfb_codes.push_back({protocol, raw_code, 1u, millis()});
  329. }
  330. _rpn_run = true;
  331. }
  332. void _rpnRfbSetup() {
  333. // - Repeat window is an arbitrary time, just about 3-4 more times it takes for
  334. // a code to be sent again when holding a generic remote button
  335. // Code counter is reset to 0 when outside of the window.
  336. // - Stale delay allows broker callback to remove really old codes.
  337. // (TODO: can this happen in loop() cb instead?)
  338. _rfb_code_repeat_window = getSetting("rfbRepeatWindow", 2000ul);
  339. _rfb_code_match_window = getSetting("rfbMatchWindow", 2000ul);
  340. _rfb_code_stale_delay = getSetting("rfbStaleDelay", 10000ul);
  341. #if TERMINAL_SUPPORT
  342. terminalRegisterCommand(F("RFB.CODES"), [](const terminal::CommandContext& ctx) {
  343. for (auto& code : _rfb_codes) {
  344. char buffer[128] = {0};
  345. snprintf_P(buffer, sizeof(buffer),
  346. PSTR("proto=%u raw=\"%s\" count=%u last=%u"),
  347. code.protocol,
  348. code.raw.c_str(),
  349. code.count,
  350. code.last
  351. );
  352. ctx.output.println(buffer);
  353. }
  354. });
  355. #endif
  356. // Main bulk of the processing goes on in here
  357. RfbridgeBroker::Register(_rpnBrokerRfbridgeCallback);
  358. }
  359. #endif // RFB_SUPPORT
  360. void _rpnShowStack(Print& print) {
  361. print.println(F("Stack:"));
  362. auto index = rpn_stack_size(_rpn_ctxt);
  363. if (!index) {
  364. print.println(F(" (empty)"));
  365. return;
  366. }
  367. rpn_stack_foreach(_rpn_ctxt, [&index, &print](rpn_stack_value::Type type, const rpn_value& value) {
  368. print.printf("%c %02u: %s\n",
  369. _rpnStackTypeTag(type), index--,
  370. _rpnValueToString(value).c_str()
  371. );
  372. });
  373. }
  374. void _rpnInit() {
  375. // Init context
  376. rpn_init(_rpn_ctxt);
  377. // Time functions need NTP support
  378. // TODO: since 1.15.0, timelib+ntpclientlib are no longer used with latest Cores
  379. // `now` is always in UTC, `utc_...` functions to be used instead to convert time
  380. #if NTP_SUPPORT && !NTP_LEGACY_SUPPORT
  381. rpn_operator_set(_rpn_ctxt, "utc", 0, _rpnNtpNow);
  382. rpn_operator_set(_rpn_ctxt, "now", 0, _rpnNtpNow);
  383. rpn_operator_set(_rpn_ctxt, "utc_month", 1, [](rpn_context & ctxt) {
  384. return _rpnNtpFunc(ctxt, utc_month);
  385. });
  386. rpn_operator_set(_rpn_ctxt, "month", 1, [](rpn_context & ctxt) {
  387. return _rpnNtpFunc(ctxt, month);
  388. });
  389. rpn_operator_set(_rpn_ctxt, "utc_day", 1, [](rpn_context & ctxt) {
  390. return _rpnNtpFunc(ctxt, utc_day);
  391. });
  392. rpn_operator_set(_rpn_ctxt, "day", 1, [](rpn_context & ctxt) {
  393. return _rpnNtpFunc(ctxt, day);
  394. });
  395. rpn_operator_set(_rpn_ctxt, "utc_dow", 1, [](rpn_context & ctxt) {
  396. return _rpnNtpFunc(ctxt, utc_weekday);
  397. });
  398. rpn_operator_set(_rpn_ctxt, "dow", 1, [](rpn_context & ctxt) {
  399. return _rpnNtpFunc(ctxt, weekday);
  400. });
  401. rpn_operator_set(_rpn_ctxt, "utc_hour", 1, [](rpn_context & ctxt) {
  402. return _rpnNtpFunc(ctxt, utc_hour);
  403. });
  404. rpn_operator_set(_rpn_ctxt, "hour", 1, [](rpn_context & ctxt) {
  405. return _rpnNtpFunc(ctxt, hour);
  406. });
  407. rpn_operator_set(_rpn_ctxt, "utc_minute", 1, [](rpn_context & ctxt) {
  408. return _rpnNtpFunc(ctxt, utc_minute);
  409. });
  410. rpn_operator_set(_rpn_ctxt, "minute", 1, [](rpn_context & ctxt) {
  411. return _rpnNtpFunc(ctxt, minute);
  412. });
  413. #endif
  414. // TODO: 1.14.0 weekday(...) conversion seemed to have 0..6 range with Monday as 0
  415. // using classic Sunday as first, but instead of 0 it is 1
  416. // Implementation above also uses 1 for Sunday, staying compatible with TimeLib
  417. #if NTP_SUPPORT && NTP_LEGACY_SUPPORT
  418. rpn_operator_set(_rpn_ctxt, "utc", 0, [](rpn_context & ctxt) -> rpn_error {
  419. if (!ntpSynced()) return rpn_operator_error::CannotContinue;
  420. rpn_value ts { static_cast<rpn_int>(ntpLocal2UTC(now())) };
  421. rpn_stack_push(ctxt, ts);
  422. return 0;
  423. });
  424. rpn_operator_set(_rpn_ctxt, "now", 0, _rpnNtpNow);
  425. rpn_operator_set(_rpn_ctxt, "month", 1, [](rpn_context & ctxt) {
  426. return _rpnNtpFunc(ctxt, month);
  427. });
  428. rpn_operator_set(_rpn_ctxt, "day", 1, [](rpn_context & ctxt) {
  429. return _rpnNtpFunc(ctxt, day);
  430. });
  431. rpn_operator_set(_rpn_ctxt, "dow", 1, [](rpn_context & ctxt) {
  432. return _rpnNtpFunc(ctxt, weekday);
  433. });
  434. rpn_operator_set(_rpn_ctxt, "hour", 1, [](rpn_context & ctxt) {
  435. return _rpnNtpFunc(ctxt, hour);
  436. });
  437. rpn_operator_set(_rpn_ctxt, "minute", 1, [](rpn_context & ctxt) {
  438. return _rpnNtpFunc(ctxt, minute);
  439. });
  440. #endif
  441. // Accept relay number and numeric API status value (0, 1 and 2)
  442. #if RELAY_SUPPORT
  443. // apply status and reset timers when called
  444. rpn_operator_set(_rpn_ctxt, "relay_reset", 2, [](rpn_context & ctxt) {
  445. return _rpnRelayStatus(ctxt, true);
  446. });
  447. // only update status when target status differs, keep running timers
  448. rpn_operator_set(_rpn_ctxt, "relay", 2, [](rpn_context & ctxt) {
  449. return _rpnRelayStatus(ctxt, false);
  450. });
  451. #endif // RELAY_SUPPORT == 1
  452. // Channel operators
  453. #if RELAY_PROVIDER == RELAY_PROVIDER_LIGHT
  454. rpn_operator_set(_rpn_ctxt, "update", 0, [](rpn_context & ctxt) -> rpn_error {
  455. lightUpdate(true, true);
  456. return 0;
  457. });
  458. rpn_operator_set(_rpn_ctxt, "black", 0, [](rpn_context & ctxt) -> rpn_error {
  459. lightColor((unsigned long) 0);
  460. return 0;
  461. });
  462. rpn_operator_set(_rpn_ctxt, "channel", 2, [](rpn_context & ctxt) -> rpn_error {
  463. rpn_value value;
  464. rpn_value id;
  465. rpn_stack_pop(ctxt, id);
  466. rpn_stack_pop(ctxt, value);
  467. lightChannel(id.toUint(), id.toInt());
  468. return 0;
  469. });
  470. #endif
  471. #if RFB_SUPPORT
  472. rpn_operator_set(_rpn_ctxt, "rfb_pop", 2, _rpnRfbPop);
  473. rpn_operator_set(_rpn_ctxt, "rfb_info", 2, _rpnRfbInfo);
  474. rpn_operator_set(_rpn_ctxt, "rfb_sequence", 4, _rpnRfbSequence);
  475. rpn_operator_set(_rpn_ctxt, "rfb_match", 3, _rpnRfbMatcher);
  476. rpn_operator_set(_rpn_ctxt, "rfb_match_wait", 4, _rpnRfbWaitMatch);
  477. #endif
  478. #if MQTT_SUPPORT
  479. rpn_operator_set(_rpn_ctxt, "mqtt_send", 2, [](rpn_context & ctxt) -> rpn_error {
  480. rpn_value message;
  481. rpn_stack_pop(ctxt, message);
  482. rpn_value topic;
  483. rpn_stack_pop(ctxt, topic);
  484. return mqttSendRaw(topic.toString().c_str(), message.toString().c_str())
  485. ? rpn_operator_error::Ok
  486. : rpn_operator_error::CannotContinue;
  487. });
  488. #endif
  489. // Some debugging. Dump stack contents
  490. #if TERMINAL_SUPPORT
  491. rpn_operator_set(_rpn_ctxt, "showstack", 0, [](rpn_context & ctxt) -> rpn_error {
  492. _rpnShowStack(terminalDefaultStream());
  493. return 0;
  494. });
  495. #endif
  496. // And, simple string logging
  497. #if DEBUG_SUPPORT
  498. rpn_operator_set(_rpn_ctxt, "dbgmsg", 1, [](rpn_context & ctxt) -> rpn_error {
  499. rpn_value message;
  500. rpn_stack_pop(ctxt, message);
  501. DEBUG_MSG_P(PSTR("[RPN] %s\n"), message.toString().c_str());
  502. return 0;
  503. });
  504. #endif
  505. rpn_operator_set(_rpn_ctxt, "mem?", 0, [](rpn_context & ctxt) -> rpn_error {
  506. rpn_stack_push(ctxt, rpn_value(rtcmemStatus()));
  507. return 0;
  508. });
  509. rpn_operator_set(_rpn_ctxt, "mem_write", 2, [](rpn_context & ctxt) -> rpn_error {
  510. auto addr = rpn_stack_pop(ctxt).toUint();
  511. auto value = rpn_stack_pop(ctxt).toUint();
  512. if (addr < RTCMEM_BLOCKS) {
  513. auto* rtcmem = reinterpret_cast<volatile uint32_t*>(RTCMEM_ADDR);
  514. *(rtcmem + addr) = value;
  515. return 0;
  516. }
  517. return rpn_operator_error::InvalidArgument;
  518. });
  519. rpn_operator_set(_rpn_ctxt, "mem_read", 1, [](rpn_context & ctxt) -> rpn_error {
  520. auto addr = rpn_stack_pop(ctxt).toUint();
  521. if (addr < RTCMEM_BLOCKS) {
  522. auto* rtcmem = reinterpret_cast<volatile uint32_t*>(RTCMEM_ADDR);
  523. rpn_uint result = *(rtcmem + addr);
  524. rpn_stack_push(ctxt, rpn_value(result));
  525. return 0;
  526. }
  527. return rpn_operator_error::InvalidArgument;
  528. });
  529. rpn_operator_set(_rpn_ctxt, "sleep", 2, [](rpn_context & ctxt) -> rpn_error {
  530. static bool once { false };
  531. if (once) return rpn_operator_error::CannotContinue;
  532. auto value = rpn_stack_pop(ctxt).checkedToUint();
  533. if (!value.ok()) {
  534. return value.error();
  535. }
  536. uint64_t duration = value.value();
  537. if (!duration) {
  538. return rpn_operator_error::CannotContinue;
  539. }
  540. auto mode = rpn_stack_pop(ctxt).toUint();
  541. once = true;
  542. schedule_function([duration, mode]() {
  543. wifiTurnOff();
  544. ESP.deepSleep(duration * 1000000ull, static_cast<RFMode>(mode));
  545. });
  546. return 0;
  547. });
  548. rpn_operator_set(_rpn_ctxt, "stations", 0, [](rpn_context & ctxt) -> rpn_error {
  549. if (!(WiFi.getMode() & WIFI_AP)) return rpn_operator_error::CannotContinue;
  550. rpn_stack_push(ctxt, rpn_value(static_cast<rpn_uint>(WiFi.softAPgetStationNum())));
  551. return 0;
  552. });
  553. rpn_operator_set(_rpn_ctxt, "disconnect", 0, [](rpn_context & ctxt) -> rpn_error {
  554. wifiDisconnect();
  555. return 0;
  556. });
  557. rpn_operator_set(_rpn_ctxt, "rssi", 0, [](rpn_context & ctxt) -> rpn_error {
  558. if (!wifiConnected()) return rpn_operator_error::CannotContinue;
  559. rpn_stack_push(ctxt, rpn_value(static_cast<rpn_int>(WiFi.RSSI())));
  560. return 0;
  561. });
  562. rpn_operator_set(_rpn_ctxt, "delay", 1, [](rpn_context & ctxt) -> rpn_error {
  563. auto ms = rpn_stack_pop(ctxt);
  564. delay(ms.toUint());
  565. return 0;
  566. });
  567. rpn_operator_set(_rpn_ctxt, "yield", 0, [](rpn_context & ctxt) -> rpn_error {
  568. yield();
  569. return 0;
  570. });
  571. rpn_operator_set(_rpn_ctxt, "reset", 0, [](rpn_context & ctxt) -> rpn_error {
  572. static bool once = ([]() {
  573. deferredReset(100, CUSTOM_RESET_TERMINAL);
  574. return true;
  575. })();
  576. return once
  577. ? rpn_operator_error::CannotContinue
  578. : rpn_operator_error::Ok;
  579. });
  580. rpn_operator_set(_rpn_ctxt, "millis", 0, [](rpn_context & ctxt) -> rpn_error {
  581. rpn_stack_push(ctxt, rpn_value(static_cast<uint32_t>(millis())));
  582. return 0;
  583. });
  584. rpn_operator_set(_rpn_ctxt, "oneshot_ms", 1, [](rpn_context & ctxt) -> rpn_error {
  585. auto every = rpn_stack_pop(ctxt);
  586. return _rpnRunnerHandler(ctxt, RpnRunner::Policy::OneShot, every.toUint());
  587. });
  588. rpn_operator_set(_rpn_ctxt, "every_ms", 1, [](rpn_context & ctxt) -> rpn_error {
  589. auto every = rpn_stack_pop(ctxt);
  590. return _rpnRunnerHandler(ctxt, RpnRunner::Policy::Periodic, every.toUint());
  591. });
  592. // XXX: workaround for the vector 2x growth on push. will need to fix this in the rpnlib
  593. _rpn_ctxt.operators.shrink_to_fit();
  594. DEBUG_MSG_P(PSTR("[RPN] Registered %u operators\n"), _rpn_ctxt.operators.size());
  595. }
  596. #if TERMINAL_SUPPORT
  597. void _rpnInitCommands() {
  598. terminalRegisterCommand(F("RPN.RUNNERS"), [](const terminal::CommandContext& ctx) {
  599. if (!_rpn_runners.size()) {
  600. terminalError(ctx, F("No active runners"));
  601. return;
  602. }
  603. for (auto& runner : _rpn_runners) {
  604. char buffer[128] = {0};
  605. snprintf_P(buffer, sizeof(buffer), PSTR("%p %s %u ms, last %u ms"),
  606. &runner, (RpnRunner::Policy::Periodic == runner.policy) ? "every" : "one-shot",
  607. runner.period, runner.last
  608. );
  609. ctx.output.println(buffer);
  610. }
  611. terminalOK(ctx);
  612. });
  613. terminalRegisterCommand(F("RPN.VARS"), [](const terminal::CommandContext& ctx) {
  614. rpn_variables_foreach(_rpn_ctxt, [&ctx](const String& name, const rpn_value& value) {
  615. char buffer[256] = {0};
  616. snprintf_P(buffer, sizeof(buffer), PSTR(" %s: %s"), name.c_str(), _rpnValueToString(value).c_str());
  617. ctx.output.println(buffer);
  618. });
  619. terminalOK(ctx);
  620. });
  621. terminalRegisterCommand(F("RPN.OPS"), [](const terminal::CommandContext& ctx) {
  622. rpn_operators_foreach(_rpn_ctxt, [&ctx](const String& name, size_t argc, rpn_operator::callback_type) {
  623. char buffer[128] = {0};
  624. snprintf_P(buffer, sizeof(buffer), PSTR(" %s (%d)"), name.c_str(), argc);
  625. ctx.output.println(buffer);
  626. });
  627. terminalOK(ctx);
  628. });
  629. terminalRegisterCommand(F("RPN.TEST"), [](const terminal::CommandContext& ctx) {
  630. if (ctx.argc != 2) {
  631. terminalError(F("Wrong arguments"));
  632. return;
  633. }
  634. ctx.output.print(F("Running RPN expression: "));
  635. ctx.output.println(ctx.argv[1].c_str());
  636. if (!rpn_process(_rpn_ctxt, ctx.argv[1].c_str())) {
  637. rpn_stack_clear(_rpn_ctxt);
  638. char buffer[64] = {0};
  639. snprintf_P(buffer, sizeof(buffer), PSTR("position=%u category=%d code=%d"),
  640. _rpn_ctxt.error.position, static_cast<int>(_rpn_ctxt.error.category), _rpn_ctxt.error.code);
  641. terminalError(ctx, buffer);
  642. return;
  643. }
  644. _rpnShowStack(ctx.output);
  645. rpn_stack_clear(_rpn_ctxt);
  646. terminalOK(ctx);
  647. });
  648. }
  649. #endif
  650. // enables us to use rules without any events firing
  651. // notice: requires rpnRun to trigger at least once so that we can install runners
  652. void _rpnRunnersCheck() {
  653. auto ts = millis();
  654. for (auto& runner : _rpn_runners) {
  655. if (ts - runner.last >= runner.period) {
  656. runner.expired = true;
  657. runner.last = ts;
  658. _rpn_run = true;
  659. }
  660. }
  661. }
  662. void _rpnRunnersReset() {
  663. auto old = std::remove_if(_rpn_runners.begin(), _rpn_runners.end(), [](RpnRunner& runner) {
  664. return (RpnRunner::Policy::OneShot == runner.policy) && runner.expired;
  665. });
  666. if (old != _rpn_runners.end()) {
  667. _rpn_runners.erase(old, _rpn_runners.end());
  668. }
  669. for (auto& runner : _rpn_runners) {
  670. runner.expired = false;
  671. }
  672. }
  673. void _rpnRun() {
  674. if (!_rpn_run) {
  675. return;
  676. }
  677. if (millis() - _rpn_last <= _rpn_delay) {
  678. return;
  679. }
  680. _rpn_last = millis();
  681. _rpn_run = false;
  682. String rule;
  683. unsigned char i = 0;
  684. while ((rule = getSetting({"rpnRule", i++})).length()) {
  685. rpn_process(_rpn_ctxt, rule.c_str());
  686. rpn_stack_clear(_rpn_ctxt);
  687. }
  688. if (!getSetting("rpnSticky", 1 == RPN_STICKY)) {
  689. rpn_variables_clear(_rpn_ctxt);
  690. }
  691. }
  692. void _rpnLoop() {
  693. _rpnRunnersCheck();
  694. _rpnRun();
  695. _rpnRunnersReset();
  696. }
  697. void rpnSetup() {
  698. // Init context
  699. _rpnInit();
  700. // Load & cache settings
  701. _rpnConfigure();
  702. // Terminal commands
  703. #if TERMINAL_SUPPORT
  704. _rpnInitCommands();
  705. #endif
  706. // Websockets
  707. #if WEB_SUPPORT
  708. wsRegister()
  709. .onVisible([](JsonObject& root) { root["rpnVisible"] = 1; })
  710. .onConnected(_rpnWebSocketOnConnected)
  711. .onKeyCheck(_rpnWebSocketOnKeyCheck);
  712. #endif
  713. // MQTT
  714. #if MQTT_SUPPORT
  715. mqttRegister(_rpnMQTTCallback);
  716. #endif
  717. #if NTP_SUPPORT
  718. NtpBroker::Register([](const NtpTick tick, time_t timestamp, const String& datetime) {
  719. static const String tick_every_hour(F("tick1h"));
  720. static const String tick_every_minute(F("tick1m"));
  721. const char* ptr =
  722. (tick == NtpTick::EveryMinute) ? tick_every_minute.c_str() :
  723. (tick == NtpTick::EveryHour) ? tick_every_hour.c_str() : nullptr;
  724. if (ptr != nullptr) {
  725. rpn_value value { static_cast<rpn_int>(timestamp) };
  726. rpn_variable_set(_rpn_ctxt, ptr, value);
  727. _rpn_run = true;
  728. }
  729. });
  730. #endif
  731. StatusBroker::Register(_rpnBrokerStatus);
  732. #if RFB_SUPPORT
  733. _rpnRfbSetup();
  734. #endif
  735. #if SENSOR_SUPPORT
  736. SensorReadBroker::Register(_rpnBrokerCallback);
  737. #endif
  738. espurnaRegisterReload(_rpnConfigure);
  739. espurnaRegisterLoop(_rpnLoop);
  740. _rpn_last = millis();
  741. _rpn_run = true;
  742. }
  743. #endif // RPN_RULES_SUPPORT