led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago ![Max Prokhorov](/avatar/a910c37e6d4c9c832e6f6fab90bf5bbe) providers: relays, lights and buttons refactoring (#2414)
- gpio module now tracks the known providers (right now, hardware and mcp expander)
- refactored relay struct to use 'Provider' implementing setup,notify,change,boot instead of just BasePin actions
- refactored button module to use gpio provider instead of referencing types itself
- removed dual & stm code from buttons, migrate both to relay module
- added status notify and change callbacks for relayStatus (i.e. 'notify' when relay status was called, but not changed. and 'changed' when it did)
- relays runtime configuration keys
- relay command now shows configured relays and current & target statuses
- refactor the code using relayStatus(0, blah) under LIGHT_PROVIDER check to use lightState instead
- remove rfbridge code form relay module. implement through a basic state listener in the rfbridge module, depend on RELAY_SUPPORT
- allow to bind rf codes to real relays
- drop tuya-specific lights provider, remove tuya code from relays and lights modules
- integrate tuya via relay listeners and providers, use lights custom provider
- implement channel transitions for tuya. disabled by default, and transition time and step are overridden to 2000 + 100. needs to be set to some value below the total time (i.e. `total transition time / step time == number of steps`, we need to figure out a correct time that serial comms could handle)
- lights custom provider (global, not per-pin) and state listeners
- remove lights code from relay module. implement through providers & listeners in the lights module, depend on RELAY_SUPPORT
- lights per-channel relay provider (unused atm), depend on RELAY_SUPPORT
- refactored channel transition - calculate step only once, make sure time + step values are sane, generate quick transitions with very small delay (10ms hardcoded) for transitions during OFF state i.e. we no longer waste 500ms (or whatever transition time is set to) on boot doing nothing
- transition time + step parameter for the lightUpdate
- report mask parameter for the lightUpdate
- minor fixes across the board
resolve #2222 3 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago ![Max Prokhorov](/avatar/a910c37e6d4c9c832e6f6fab90bf5bbe) providers: relays, lights and buttons refactoring (#2414)
- gpio module now tracks the known providers (right now, hardware and mcp expander)
- refactored relay struct to use 'Provider' implementing setup,notify,change,boot instead of just BasePin actions
- refactored button module to use gpio provider instead of referencing types itself
- removed dual & stm code from buttons, migrate both to relay module
- added status notify and change callbacks for relayStatus (i.e. 'notify' when relay status was called, but not changed. and 'changed' when it did)
- relays runtime configuration keys
- relay command now shows configured relays and current & target statuses
- refactor the code using relayStatus(0, blah) under LIGHT_PROVIDER check to use lightState instead
- remove rfbridge code form relay module. implement through a basic state listener in the rfbridge module, depend on RELAY_SUPPORT
- allow to bind rf codes to real relays
- drop tuya-specific lights provider, remove tuya code from relays and lights modules
- integrate tuya via relay listeners and providers, use lights custom provider
- implement channel transitions for tuya. disabled by default, and transition time and step are overridden to 2000 + 100. needs to be set to some value below the total time (i.e. `total transition time / step time == number of steps`, we need to figure out a correct time that serial comms could handle)
- lights custom provider (global, not per-pin) and state listeners
- remove lights code from relay module. implement through providers & listeners in the lights module, depend on RELAY_SUPPORT
- lights per-channel relay provider (unused atm), depend on RELAY_SUPPORT
- refactored channel transition - calculate step only once, make sure time + step values are sane, generate quick transitions with very small delay (10ms hardcoded) for transitions during OFF state i.e. we no longer waste 500ms (or whatever transition time is set to) on boot doing nothing
- transition time + step parameter for the lightUpdate
- report mask parameter for the lightUpdate
- minor fixes across the board
resolve #2222 3 years ago ![Max Prokhorov](/avatar/a910c37e6d4c9c832e6f6fab90bf5bbe) providers: relays, lights and buttons refactoring (#2414)
- gpio module now tracks the known providers (right now, hardware and mcp expander)
- refactored relay struct to use 'Provider' implementing setup,notify,change,boot instead of just BasePin actions
- refactored button module to use gpio provider instead of referencing types itself
- removed dual & stm code from buttons, migrate both to relay module
- added status notify and change callbacks for relayStatus (i.e. 'notify' when relay status was called, but not changed. and 'changed' when it did)
- relays runtime configuration keys
- relay command now shows configured relays and current & target statuses
- refactor the code using relayStatus(0, blah) under LIGHT_PROVIDER check to use lightState instead
- remove rfbridge code form relay module. implement through a basic state listener in the rfbridge module, depend on RELAY_SUPPORT
- allow to bind rf codes to real relays
- drop tuya-specific lights provider, remove tuya code from relays and lights modules
- integrate tuya via relay listeners and providers, use lights custom provider
- implement channel transitions for tuya. disabled by default, and transition time and step are overridden to 2000 + 100. needs to be set to some value below the total time (i.e. `total transition time / step time == number of steps`, we need to figure out a correct time that serial comms could handle)
- lights custom provider (global, not per-pin) and state listeners
- remove lights code from relay module. implement through providers & listeners in the lights module, depend on RELAY_SUPPORT
- lights per-channel relay provider (unused atm), depend on RELAY_SUPPORT
- refactored channel transition - calculate step only once, make sure time + step values are sane, generate quick transitions with very small delay (10ms hardcoded) for transitions during OFF state i.e. we no longer waste 500ms (or whatever transition time is set to) on boot doing nothing
- transition time + step parameter for the lightUpdate
- report mask parameter for the lightUpdate
- minor fixes across the board
resolve #2222 3 years ago led: pattern fixes and terminal command
Implement strongly-typed time units via std::chrono,
compile-time checks with static delays and limit possible values in the
pattern parser. Clamp 'repeats' as well, instead of relying on overflow
Rework internal loop & template runners, so there's no need to
proxy status and led struct all over. Instead, simply declare two
separate funcs that are supposed to be run during the pattern and at
it's end.
Instead of cloning the 'delays' array, implement a sequence iterator
that is tracking the currently used delay and it's repeats, and which
also jumps to the next entry in the list.
(but, this uses c++ iterators, and *may* be prone to errors)
Implement small terminal command 'led <ID> [<PATTERN STRING>]'.
Running without the 'PATTERN STRING' resets the LED to the values in settings.
Move re2c-generated parser back into a separate file, use .cpp.inc as
include and .re as the source
ref. #2476, fix 'finite' pattern handling
2 years ago |
|
- /*
-
- LED MODULE
-
- Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
- Copyright (C) 2019-2021 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
-
- To (re)create the string -> pattern decoder .ipp files, add `re2c` to the $PATH and 'run' the environment:
- ```
- $ pio run -e ... -t espurna/led_pattern.re.ipp
- ```
- (see scripts/pio_pre.py and scripts/espurna_utils/build.py for more info)
-
- */
-
- #include "espurna.h"
-
- #if LED_SUPPORT
-
- #include <algorithm>
- #include <cstring>
- #include <ctime>
- #include <chrono>
- #include <forward_list>
- #include <vector>
-
- #include "led.h"
- #include "mqtt.h"
- #include "relay.h"
- #include "rpc.h"
-
- #if WEB_SUPPORT
- #include "ws.h"
- #endif
-
- namespace espurna {
- namespace led {
- namespace {
-
- // Some local-only time & counters implementation:
- // - Core conversion is done through macros, implement stronger types
- // - force unsigned instead of chrono's 'int64_t', since we want safe overflow
- // - bound to 32bits, to seamlessly handle ccount conversion from the 'time source'
- // - explicitly check for the maximum number of milliseconds that may be represented with ccount
-
- // TODO: full-width int for repeats instead of 8bit? right now, string parser will *force* [min:max] range,
- // but anything else is experiencing overflow mechanics
-
- struct alignas(8) Delay {
- using Source = espurna::time::CpuClock;
- using Duration = Source::duration;
- using TimePoint = Source::time_point;
-
- static constexpr auto ClockCyclesMax = Duration(Duration::max());
- static constexpr auto MillisecondsMax = std::chrono::duration_cast<espurna::duration::Milliseconds>(ClockCyclesMax);
-
- using Repeats = size_t;
- static constexpr Repeats RepeatsMin { std::numeric_limits<Repeats>::min() };
- static constexpr Repeats RepeatsMax { std::numeric_limits<Repeats>::max() };
-
- enum class Mode {
- Finite,
- Infinite,
- None
- };
-
- Delay() = delete;
-
- constexpr Delay(Duration on, Duration off, Repeats repeats) :
- _mode(repeats ? Mode::Finite : Mode::Infinite),
- _on(on),
- _off(off),
- _repeats(repeats)
- {}
-
- constexpr Mode mode() const {
- return _mode;
- }
-
- constexpr Duration on() const {
- return _on;
- }
-
- constexpr Duration off() const {
- return _off;
- }
-
- constexpr Repeats repeats() const {
- return _repeats;
- }
-
- private:
- Mode _mode;
- Duration _on;
- Duration _off;
- Repeats _repeats;
- };
-
- constexpr espurna::duration::ClockCycles Delay::ClockCyclesMax;
- constexpr espurna::duration::Milliseconds Delay::MillisecondsMax;
-
- struct Pattern {
- using Delays = std::vector<Delay>;
-
- Pattern() = default;
- Pattern(Pattern&&) = default;
- Pattern& operator=(Pattern&&) = default;
-
- explicit Pattern(espurna::StringView);
- explicit Pattern(Delays&& delays) :
- _delays(std::move(delays)),
- _sequence(_delays),
- _cycle(_delays)
- {}
-
- explicit operator bool() const {
- return _delays.size() > 0;
- }
-
- void start() {
- if (!_sequence) {
- _cycle = Delay::Duration::min();
- _sequence = _delays;
- }
- }
-
- void stop() {
- _cycle = Delay::Duration::min();
- std::move(_sequence) = _delays;
- }
-
- bool started() const {
- return static_cast<bool>(_sequence);
- }
-
- const Delays& delays() const {
- return _delays;
- }
-
- template <typename Status, typename Last>
- void run(Status&& status, Last&& last) {
- if (!_sequence) {
- return;
- }
-
- if (!_cycle) {
- return;
- }
-
- const auto currentStatus = status();
- _cycle = currentStatus
- ? _sequence.on() : _sequence.off();
-
- switch (_sequence.mode()) {
- case Delay::Mode::Finite:
- if (currentStatus && !_sequence.repeat()) {
- if (!_sequence.next()) {
- last();
- }
- }
-
- break;
- case Delay::Mode::Infinite:
- case Delay::Mode::None:
- break;
- }
- }
-
- private:
- // Sequence of pending 'delays', by default it's in the order they are specified in the underlying vector.
- // Notice that there are no checks that '_current' is dereferencable, it's up to the consumer to check via 'operator bool()' first
- // TODO: is it actually valid to have 'Sequence() = default', and not actually reference any particular object?
- struct Sequence {
- Sequence() = delete;
-
- Sequence(const Sequence&) = default;
- Sequence(Sequence&&) = default;
-
- explicit Sequence(const Delays& delays) :
- _current(delays.cbegin()),
- _end(delays.cend()),
- _repeats((_current != _end) ? (*_current).repeats() : 0)
- {}
-
- Sequence& operator=(const Sequence&) = default;
- Sequence& operator=(Sequence&&) = default;
-
- Sequence& operator=(const Delays& delays) & {
- return (*this = Sequence(delays));
- }
-
- Sequence& operator=(const Delays& delays) && {
- _current = delays.cend();
- _end = delays.cend();
- _repeats = 0;
- return *this;
- }
-
- explicit operator bool() const {
- return _current != _end;
- }
-
- Delay::Repeats repeats() const {
- return _repeats;
- }
-
- Delay::Mode mode() const {
- return (*_current).mode();
- }
-
- Delay::Duration on() const {
- return (*_current).on();
- }
-
- Delay::Duration off() const {
- return (*_current).off();
- }
-
- bool repeat() {
- if (_repeats) {
- --_repeats;
- return true;
- }
-
- return false;
- }
-
- bool next() {
- if (_current != _end) {
- ++_current;
- if (_current != _end) {
- _repeats = (*_current).repeats();
- return true;
- }
- }
-
- return false;
- }
-
- private:
- Delays::const_iterator _current;
- Delays::const_iterator _end;
- Delay::Repeats _repeats;
- };
-
- // Currently used delay value cycles between 'on' and 'off',
- // allow to set the current one and to wait until it expires
- struct Cycle {
- explicit Cycle(const Delays& delays) :
- _last(Delay::Source::now()),
- _delay(delays.size() ? delays.front().on() : Delay::Duration::min())
- {}
-
- Cycle& operator=(const Delays& delays) {
- return (*this = Cycle(delays));
- }
-
- Cycle& operator=(Delay::Duration duration) {
- _last = Delay::Source::now();
- _delay = duration;
- return *this;
- }
-
- explicit operator bool() const {
- return (Delay::Source::now() - _last > _delay);
- }
-
- private:
- Delay::TimePoint _last;
- Delay::Duration _delay;
- };
-
- Delays _delays;
-
- Sequence _sequence { _delays };
- Cycle _cycle { _delays };
- };
-
- struct Led {
- Led() = delete;
- Led(unsigned char pin, bool inverse, LedMode mode) :
- _pin(pin),
- _inverse(inverse),
- _mode(mode)
- {
- init();
- }
-
- unsigned char pin() const {
- return _pin;
- }
-
- LedMode mode() const {
- return _mode;
- }
-
- void mode(LedMode mode) {
- _mode = mode;
- }
-
- bool inverse() const {
- return _inverse;
- }
-
- Pattern& pattern() {
- return _pattern;
- }
-
- void pattern(Pattern&& pattern) {
- _pattern = std::move(pattern);
- }
-
- bool started() {
- return _pattern.started();
- }
-
- void stop() {
- _pattern.stop();
- }
-
- void init();
-
- bool status();
- bool status(bool new_status);
-
- bool toggle();
-
- void run() {
- _pattern.run(
- // notify the pattern about the 'current' status
- [&]() {
- return toggle();
- },
- // what happens when the pattern ends
- [&]() {
- status(false);
- });
- }
-
- private:
- unsigned char _pin;
- bool _inverse;
- LedMode _mode;
- Pattern _pattern;
- };
-
- void Led::init() {
- pinMode(_pin, OUTPUT);
- status(false);
- }
-
- bool Led::status() {
- bool result = digitalRead(_pin);
- return _inverse ? !result : result;
- }
-
- bool Led::status(bool new_status) {
- digitalWrite(_pin, _inverse ? !new_status : new_status);
- return new_status;
- }
-
- bool Led::toggle() {
- return status(!status());
- }
-
- #include "led_pattern.re.ipp"
-
- namespace settings {
- namespace keys {
-
- PROGMEM_STRING(Gpio, "ledGpio");
- PROGMEM_STRING(Inverse, "ledInv");
- PROGMEM_STRING(Mode, "ledMode");
- PROGMEM_STRING(Relay, "ledRelay");
- PROGMEM_STRING(Pattern, "ledPattern");
-
- } // namespace keys
-
- namespace options {
-
- using espurna::settings::options::Enumeration;
-
- PROGMEM_STRING(Manual, "manual");
- PROGMEM_STRING(WiFi, "wifi");
- PROGMEM_STRING(On, "on");
- PROGMEM_STRING(Off, "off");
-
- #if RELAY_SUPPORT
- PROGMEM_STRING(Relay, "relay");
- PROGMEM_STRING(RelayInverse, "relay-inverse");
-
- PROGMEM_STRING(FindMe, "findme");
- PROGMEM_STRING(FindMeWiFi, "findme-wifi");
-
- PROGMEM_STRING(Relays, "relays");
- PROGMEM_STRING(RelaysWiFi, "relays-wifi");
- #endif
-
- static constexpr Enumeration<LedMode> LedModeOptions[] PROGMEM {
- {LedMode::Manual, Manual},
- {LedMode::WiFi, WiFi},
- #if RELAY_SUPPORT
- {LedMode::Relay, Relay},
- {LedMode::RelayInverse, RelayInverse},
- {LedMode::FindMe, FindMe},
- {LedMode::FindMeWiFi, FindMeWiFi},
- #endif
- {LedMode::On, On},
- {LedMode::Off, Off},
- #if RELAY_SUPPORT
- {LedMode::Relays, Relays},
- {LedMode::RelaysWiFi, RelaysWiFi},
- #endif
- };
-
- } // namespace options
- } // namespace settings
- } // namespace
- } // namespace led
-
- // -----------------------------------------------------------------------------
-
- namespace settings {
- namespace internal {
- namespace {
-
- using led::settings::options::LedModeOptions;
-
- } // namespace
-
- template <>
- LedMode convert(const String& value) {
- return convert(LedModeOptions, value, LedMode::Manual);
- }
-
- String serialize(LedMode mode) {
- return serialize(LedModeOptions, mode);
- }
-
- } // namespace internal
- } // namespace settings
-
- // -----------------------------------------------------------------------------
-
- namespace led {
- namespace {
-
- namespace build {
-
- constexpr size_t LedsMax { 8ul };
-
- constexpr size_t preconfiguredLeds() {
- return 0ul
- #if LED1_PIN != GPIO_NONE
- + 1ul
- #endif
- #if LED2_PIN != GPIO_NONE
- + 1ul
- #endif
- #if LED3_PIN != GPIO_NONE
- + 1ul
- #endif
- #if LED4_PIN != GPIO_NONE
- + 1ul
- #endif
- #if LED5_PIN != GPIO_NONE
- + 1ul
- #endif
- #if LED6_PIN != GPIO_NONE
- + 1ul
- #endif
- #if LED7_PIN != GPIO_NONE
- + 1ul
- #endif
- #if LED8_PIN != GPIO_NONE
- + 1ul
- #endif
- ;
- }
-
- constexpr unsigned char pin(size_t index) {
- return (
- (index == 0) ? LED1_PIN :
- (index == 1) ? LED2_PIN :
- (index == 2) ? LED3_PIN :
- (index == 3) ? LED4_PIN :
- (index == 4) ? LED5_PIN :
- (index == 5) ? LED6_PIN :
- (index == 6) ? LED7_PIN :
- (index == 7) ? LED8_PIN : GPIO_NONE
- );
- }
-
- constexpr LedMode mode(size_t index) {
- return (
- (index == 0) ? LED1_MODE :
- (index == 1) ? LED2_MODE :
- (index == 2) ? LED3_MODE :
- (index == 3) ? LED4_MODE :
- (index == 4) ? LED5_MODE :
- (index == 5) ? LED6_MODE :
- (index == 6) ? LED7_MODE :
- (index == 7) ? LED8_MODE : LedMode::Manual
- );
- }
-
- constexpr unsigned char relay(size_t index) {
- return (
- (index == 0) ? (LED1_RELAY - 1) :
- (index == 1) ? (LED2_RELAY - 1) :
- (index == 2) ? (LED3_RELAY - 1) :
- (index == 3) ? (LED4_RELAY - 1) :
- (index == 4) ? (LED5_RELAY - 1) :
- (index == 5) ? (LED6_RELAY - 1) :
- (index == 6) ? (LED7_RELAY - 1) :
- (index == 7) ? (LED8_RELAY - 1) : RELAY_NONE
- );
- }
-
- constexpr bool inverse(size_t index) {
- return (
- (index == 0) ? (1 == LED1_PIN_INVERSE) :
- (index == 1) ? (1 == LED2_PIN_INVERSE) :
- (index == 2) ? (1 == LED3_PIN_INVERSE) :
- (index == 3) ? (1 == LED4_PIN_INVERSE) :
- (index == 4) ? (1 == LED5_PIN_INVERSE) :
- (index == 5) ? (1 == LED6_PIN_INVERSE) :
- (index == 6) ? (1 == LED7_PIN_INVERSE) :
- (index == 7) ? (1 == LED8_PIN_INVERSE) : false
- );
- }
-
- } // namespace build
-
- namespace settings {
-
- unsigned char pin(size_t id) {
- return getSetting({keys::Gpio, id}, build::pin(id));
- }
-
- bool inverse(size_t id) {
- return getSetting({keys::Inverse, id}, build::inverse(id));
- }
-
- LedMode mode(size_t id) {
- return getSetting({keys::Mode, id}, build::mode(id));
- }
-
- #if RELAY_SUPPORT
-
- size_t relay(size_t id) {
- return getSetting({keys::Relay, id}, build::relay(id));
- }
-
- #endif
-
- Pattern pattern(size_t id) {
- return Pattern(getSetting({keys::Pattern, id}));
- }
-
- void migrate(int version) {
- if (version < 5) {
- delSettingPrefix({
- keys::Gpio,
- PSTR("ledGPIO"),
- PSTR("ledLogic")
- });
- }
- }
-
- } // namespace settings
-
- // For network-based modes, indefinitely cycle ON <-> OFF
- // (TODO: template params containing structs like duration need -std=c++2a)
-
- #define LED_STATIC_DELAY(NAME, ON, OFF)\
- static constexpr auto NAME ## MillisecondsOn PROGMEM = espurna::duration::Milliseconds(ON);\
- static constexpr auto NAME ## MillisecondsOff PROGMEM = espurna::duration::Milliseconds(OFF);\
- static_assert(NAME ## MillisecondsOn < Delay::MillisecondsMax, "");\
- static_assert(NAME ## MillisecondsOff < Delay::MillisecondsMax, "");\
- static constexpr Delay NAME PROGMEM = Delay {\
- std::chrono::duration_cast<Delay::Duration>(NAME ## MillisecondsOn),\
- std::chrono::duration_cast<Delay::Duration>(NAME ## MillisecondsOff),\
- Delay::RepeatsMin }
-
- LED_STATIC_DELAY(NetworkConnected, 100, 4900);
- LED_STATIC_DELAY(NetworkConnectedInverse, 4900, 100);
- LED_STATIC_DELAY(NetworkConfig, 100, 900);
- LED_STATIC_DELAY(NetworkConfigInverse, 900, 100);
- LED_STATIC_DELAY(NetworkIdle, 500, 500);
-
- namespace internal {
-
- std::vector<Led> leds;
- bool update { false };
-
- } // namespace internal
-
- namespace settings {
- namespace query {
- namespace internal {
-
- #define ID_VALUE(NAME)\
- String NAME (size_t id) {\
- return espurna::settings::internal::serialize(\
- ::espurna::led::settings::NAME(id));\
- }
-
- ID_VALUE(pin)
- ID_VALUE(inverse)
- ID_VALUE(mode)
-
- #if RELAY_SUPPORT
- ID_VALUE(relay)
- #endif
-
- #undef ID_VALUE
-
- } // namespace internal
-
- static constexpr espurna::settings::query::IndexedSetting IndexedSettings[] PROGMEM {
- {keys::Gpio, internal::pin},
- {keys::Inverse, internal::inverse},
- {keys::Mode, internal::mode},
- #if RELAY_SUPPORT
- {keys::Relay, internal::relay},
- #endif
- };
-
- bool checkSamePrefix(StringView key) {
- return espurna::settings::query::samePrefix(key, STRING_VIEW("led"));
- }
-
- String findValueFrom(StringView key) {
- return espurna::settings::query::IndexedSetting::findValueFrom(
- ::espurna::led::internal::leds.size(), IndexedSettings, key);
- }
-
- void setup() {
- ::settingsRegisterQueryHandler({
- .check = checkSamePrefix,
- .get = findValueFrom
- });
- }
-
- } // namespace query
- } // namespace settings
-
- #if RELAY_SUPPORT
- namespace relay {
- namespace internal {
-
- struct Link {
- Led& led;
- size_t relayId;
- };
-
- std::forward_list<Link> relays;
-
- bool linked(const Link& link, const Led& led) {
- return &link.led == &led;
- }
-
- void unlink(Led& led) {
- relays.remove_if([&](const Link& link) {
- return linked(link, led);
- });
- }
-
- void link(Led& led, size_t id) {
- auto it = std::find_if(relays.begin(), relays.end(), [&](const Link& link) {
- return linked(link, led);
- });
-
- if (it != relays.end()) {
- (*it).relayId = id;
- return;
- }
-
- relays.emplace_front(Link{led, id});
- }
-
- size_t find(Led& led) {
- auto it = std::find_if(relays.begin(), relays.end(), [&](const Link& link) {
- return linked(link, led);
- });
-
- if (it != relays.end()) {
- return (*it).relayId;
- }
-
- return RelaysMax;
- }
-
- } // namespace internal
-
- void unlink(Led& led) {
- internal::unlink(led);
- }
-
- void link(Led& led, size_t id) {
- internal::link(led, id);
- }
-
- size_t find(Led& led) {
- return internal::find(led);
- }
-
- bool status(Led& led) {
- return relayStatus(find(led));
- }
-
- bool areAnyOn() {
- bool result { false };
- for (size_t id = 0; id < relayCount(); ++id) {
- if (relayStatus(id)) {
- result = true;
- break;
- }
- }
-
- return result;
- }
-
- } // namespace relay
- #endif
-
- size_t count() {
- return internal::leds.size();
- }
-
- bool scheduled() {
- return internal::update;
- }
-
- void schedule() {
- internal::update = true;
- }
-
- void cancel() {
- internal::update = false;
- }
-
- bool status(Led& led) {
- return led.started() || led.status();
- }
-
- bool status(size_t id) {
- return status(internal::leds[id]);
- }
-
- bool status(Led& led, bool status) {
- bool result = false;
-
- // when led has pattern, status depends on whether it's running
- // (notice that sending 'true' status multiple times does not restart the pattern)
- auto& pattern = led.pattern();
- if (pattern) {
- if (status) {
- pattern.start();
- result = true;
- } else {
- pattern.stop();
- led.status(false);
- result = false;
- }
- // if not, simply proxy status directly to the led pin
- } else {
- result = led.status(status);
- }
-
- return result;
- }
-
- bool status(size_t id, bool value) {
- return status(internal::leds[id], value);
- }
-
- void turn_off() {
- for (auto& led : internal::leds) {
- status(led, false);
- }
- }
-
- [[gnu::unused]]
- void pattern(Led& led, Pattern&& other) {
- led.pattern(std::move(other));
- status(led, true);
- }
-
- void payload_status(Led& led, StringView payload) {
- led.stop();
- led.status(false);
-
- led.mode(LedMode::Manual);
-
- const auto value = rpcParsePayload(payload);
- switch (value) {
- case PayloadStatus::On:
- case PayloadStatus::Off:
- led::status(led, (value == PayloadStatus::On));
- break;
- case PayloadStatus::Toggle:
- led::status(led, !led::status(led));
- break;
- case PayloadStatus::Unknown:
- pattern(led, Pattern(payload));
- break;
- }
- }
-
- void run(Led& led, const Delay& delay) {
- using TimeSource = espurna::time::CpuClock;
-
- static auto clock_last = TimeSource::now();
- static auto delay_for = delay.on();
-
- const auto clock_current = TimeSource::now();
- if (clock_current - clock_last >= delay_for) {
- delay_for = led.toggle() ? delay.on() : delay.off();
- clock_last = clock_current;
- }
- }
-
- void configure() {
- for (size_t id = 0; id < internal::leds.size(); ++id) {
- auto& led = internal::leds[id];
- led.mode(settings::mode(id));
- led.pattern(settings::pattern(id));
- #if RELAY_SUPPORT
- switch (internal::leds[id].mode()) {
- case LedMode::Relay:
- case LedMode::RelayInverse:
- relay::link(led, settings::relay(id));
- break;
- default:
- relay::unlink(led);
- break;
- }
- #endif
- }
- schedule();
- }
-
- void loop(Led& led) {
- switch (led.mode()) {
-
- case LedMode::Manual:
- break;
-
- case LedMode::WiFi:
- if (wifiConnected()) {
- run(led, NetworkConnected);
- } else if (wifiConnectable()) {
- run(led, NetworkConfig);
- } else {
- run(led, NetworkIdle);
- }
- break;
-
- case LedMode::FindMeWiFi:
- #if RELAY_SUPPORT
- if (wifiConnected()) {
- if (relay::areAnyOn()) {
- run(led, NetworkConnected);
- } else {
- run(led, NetworkConnectedInverse);
- }
- } else if (wifiConnectable()) {
- if (relay::areAnyOn()) {
- run(led, NetworkConfig);
- } else {
- run(led, NetworkConfigInverse);
- }
- } else {
- run(led, NetworkIdle);
- }
- #endif
- break;
-
- case LedMode::RelaysWiFi:
- #if RELAY_SUPPORT
- if (wifiConnected()) {
- if (!relay::areAnyOn()) {
- run(led, NetworkConnected);
- } else {
- run(led, NetworkConnectedInverse);
- }
- } else if (wifiConnectable()) {
- if (!relay::areAnyOn()) {
- run(led, NetworkConfig);
- } else {
- run(led, NetworkConfigInverse);
- }
- } else {
- run(led, NetworkIdle);
- }
- #endif
- break;
-
- case LedMode::Relay:
- #if RELAY_SUPPORT
- if (scheduled()) {
- status(led, relay::status(led));
- }
- #endif
- break;
-
- case LedMode::RelayInverse:
- #if RELAY_SUPPORT
- if (scheduled()) {
- status(led, !relay::status(led));
- }
- #endif
- break;
-
- case LedMode::FindMe:
- #if RELAY_SUPPORT
- if (scheduled()) {
- led::status(led, !relay::areAnyOn());
- }
- #endif
- break;
-
- case LedMode::Relays:
- #if RELAY_SUPPORT
- if (scheduled()) {
- led::status(led, relay::areAnyOn());
- }
- #endif
- break;
-
- case LedMode::On:
- if (scheduled()) {
- status(led, true);
- }
- break;
-
- case LedMode::Off:
- if (scheduled()) {
- status(led, false);
- }
- break;
-
- }
-
- led.run();
- }
-
- void loop() {
- for (auto& led : internal::leds) {
- loop(led);
- }
- cancel();
- }
-
- #if MQTT_SUPPORT
- namespace mqtt {
-
- void callback(unsigned int type, StringView topic, StringView payload) {
- if (type == MQTT_CONNECT_EVENT) {
- mqttSubscribe(MQTT_TOPIC_LED "/+");
- return;
- }
-
- // Only want `led/+/<MQTT_SETTER>`
- // We get the led ID from the `+`
- if (type == MQTT_MESSAGE_EVENT) {
- const auto magnitude = mqttMagnitude(topic);
- if (!magnitude.startsWith(MQTT_TOPIC_LED)) {
- return;
- }
-
- size_t ledID;
- if (tryParseIdPath(magnitude, ledCount(), ledID)) {
- payload_status(internal::leds[ledID], payload);
- }
-
- return;
- }
- }
-
- } // namespace mqtt
- #endif // MQTT_SUPPORT
-
- #if WEB_SUPPORT
- namespace web {
-
- bool onKeyCheck(StringView key, const JsonVariant&) {
- return settings::query::checkSamePrefix(key);
- }
-
- void onVisible(JsonObject& root) {
- wsPayloadModule(root, PSTR("led"));
- }
-
- void onConnected(JsonObject& root) {
- if (count()) {
- espurna::web::ws::EnumerableConfig config{root, STRING_VIEW("ledConfig")};
- config(STRING_VIEW("leds"), ::espurna::led::count(), settings::query::IndexedSettings);
- }
- }
-
- } // namespace web
- #endif // WEB_SUPPORT
-
- #if TERMINAL_SUPPORT
- namespace terminal {
-
- PROGMEM_STRING(Led, "LED");
-
- void led(::terminal::CommandContext&& ctx) {
- if (ctx.argv.size() > 1) {
- size_t id;
- if (!tryParseId(ctx.argv[1], ledCount(), id)) {
- terminalError(ctx, F("Invalid ledID"));
- return;
- }
-
- auto& led = internal::leds[id];
- if (ctx.argv.size() == 2) {
- settingsDump(ctx, settings::query::IndexedSettings, id);
- } else if (ctx.argv.size() > 2) {
- payload_status(led, ctx.argv[2]);
- }
-
- schedule();
- terminalOK(ctx);
-
- return;
- }
-
- size_t id { 0 };
- for (const auto& led : internal::leds) {
- ctx.output.printf_P(
- PSTR("led%u {Gpio=%hhu Mode=%s}\n"), id++, led.pin(),
- espurna::settings::internal::serialize(led.mode()).c_str());
- }
- }
-
- static constexpr ::terminal::Command Commands[] PROGMEM {
- {Led, led},
- };
-
- void setup() {
- espurna::terminal::add(Commands);
- }
-
- } // namespace terminal
- #endif
-
- void setup() {
- migrateVersion(settings::migrate);
- internal::leds.reserve(build::preconfiguredLeds());
-
- for (size_t index = 0; index < build::LedsMax; ++index) {
- const auto pin = settings::pin(index);
- if (!gpioLock(pin)) {
- break;
- }
-
- internal::leds.emplace_back(pin,
- settings::inverse(index), settings::mode(index));
- }
-
- const auto leds = internal::leds.size();
- DEBUG_MSG_P(PSTR("[LED] Number of leds: %u\n"), leds);
- if (leds) {
- espurna::led::settings::query::setup();
- #if MQTT_SUPPORT
- ::mqttRegister(mqtt::callback);
- #endif
- #if WEB_SUPPORT
- ::wsRegister()
- .onVisible(web::onVisible)
- .onConnected(web::onConnected)
- .onKeyCheck(web::onKeyCheck);
- #endif
- #if RELAY_SUPPORT
- ::relayOnStatusChange([](size_t, bool) {
- schedule();
- });
- #endif
- #if TERMINAL_SUPPORT
- terminal::setup();
- #endif
-
- systemBeforeSleep(turn_off);
- systemAfterSleep(schedule);
-
- ::espurnaRegisterLoop(loop);
-
- ::espurnaRegisterReload(configure);
- configure();
- }
- }
-
- } // namespace
- } // namespace led
- } // namespace espurna
-
- bool ledStatus(size_t id, bool status) {
- if (id < espurna::led::count()) {
- return espurna::led::status(id, status);
- }
-
- return status;
- }
-
- bool ledStatus(size_t id) {
- if (id < espurna::led::count()) {
- return espurna::led::status(id);
- }
-
- return false;
- }
-
- size_t ledCount() {
- return espurna::led::count();
- }
-
- void ledLoop() {
- espurna::led::loop();
- }
-
- void ledSetup() {
- espurna::led::setup();
- }
-
- #endif // LED_SUPPORT
|