|
|
|
/* -*- mode: c++ -*-
|
|
|
|
* Kaleidoscope-LED-Wavepool
|
|
|
|
* Copyright (C) 2017 Selene Scriven
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if defined(ARDUINO_AVR_MODEL01) || defined(ARDUINO_keyboardio_model_100)
|
|
|
|
|
|
|
|
#include "kaleidoscope/plugin/LED-Wavepool.h"
|
|
|
|
|
|
|
|
#include <Arduino.h> // for pgm_read_byte, PROGMEM, abs
|
|
|
|
#include <stdint.h> // for int8_t, uint8_t, int16_t, intptr_t
|
|
|
|
|
|
|
|
#include "kaleidoscope/KeyAddr.h" // for MatrixAddr, KeyAddr, MatrixAddr<>::...
|
|
|
|
#include "kaleidoscope/KeyEvent.h" // for KeyEvent
|
|
|
|
#include "kaleidoscope/Runtime.h" // for Runtime, Runtime_
|
|
|
|
#include "kaleidoscope/device/device.h" // for Device, cRGB
|
|
|
|
#include "kaleidoscope/event_handler_result.h" // for EventHandlerResult, EventHandlerRes...
|
|
|
|
#include "kaleidoscope/keyswitch_state.h" // for keyIsPressed
|
|
|
|
#include "kaleidoscope/plugin/LEDControl.h" // for LEDControl
|
|
|
|
#include "kaleidoscope/plugin/LEDControl/LEDUtils.h" // for hsvToRgb
|
|
|
|
|
|
|
|
namespace kaleidoscope {
|
|
|
|
namespace plugin {
|
|
|
|
|
|
|
|
#define INTERPOLATE 1 // smoother, slower animation
|
|
|
|
#define MS_PER_FRAME 40 // 40 = 25 fps
|
|
|
|
#define FRAMES_PER_DROP 120 // max time between raindrops during idle animation
|
|
|
|
|
|
|
|
uint16_t WavepoolEffect::idle_timeout = 5000; // 5 seconds
|
|
|
|
int16_t WavepoolEffect::ripple_hue = WavepoolEffect::rainbow_hue; // automatic hue
|
|
|
|
|
|
|
|
// map native keyboard coordinates (16x4) into geometric space (14x5)
|
|
|
|
PROGMEM const uint8_t WavepoolEffect::TransientLEDMode::rc2pos[Runtime.device().numKeys()] = {
|
|
|
|
// clang-format off
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 59, 66, 7, 8, 9, 10, 11, 12, 13,
|
|
|
|
14, 15, 16, 17, 18, 19, 34, 60, 65, 35, 22, 23, 24, 25, 26, 27,
|
|
|
|
28, 29, 30, 31, 32, 33, 48, 61, 64, 49, 36, 37, 38, 39, 40, 41,
|
|
|
|
42, 43, 44, 45, 46, 47, 58, 62, 63, 67, 50, 51, 52, 53, 54, 55,
|
|
|
|
// clang-format on
|
|
|
|
};
|
|
|
|
|
Introduced dynamic LED modes
This PR introduces the concept of dynamic LED modes. Those are LED modes whose class instances
have a restricted lifetime that lasts only as long as a LED mode is active. By this means
it is possible to support a greater amount of LED modes - especially RAM-hungry ones - in the same firmware build. The amount of RAM used to store dynamic LED modes is now bounded
by the maximum size (`sizeof(...)`) of the largest dynamic LED mode.
Old-style LED modes are furtheron called _static_ in the terminology of this PR. They are still supported and blend in nicely with the newly introduced dynamic LED modes.
All changes are entirely backward compatible. No user sketches or existing user plugins require changes.
The greatest benefit of this change is that it drastically reduces the consumption of RAM
when multiple complex LED modes are used. Currently the most complex stock LED mode is
the wavepool effect. Its plugin requires around 140 bytes of RAM that are statically allocated and cannot be shared with any other features.
With this change it becomes possible to have a large number of such resource-hungry LED modes in parallel without a significant gain in RAM consumption.
For the stock firmware this change means a small (~30 byte) growth in terms of PROGMEM. On the other hand it reduces the amount of statically consumed RAM by ~90 bytes. As the current atmel architectures come with around ten times as much PROGMEM as RAM, this means a great improvement as RAM is the more critical resource.
If the wavepool effect, a especially RAM-hungry LED mode is added to the stock firmware,
the saving of RAM increases to 160 bytes which is almost 8% of RAM of the Keyboardio Model01.
A new interface class `LEDModeInterface` was introduced that those plugins
that export dynamic LED modes inherit from. To remain backward compatible, the `LEDMode` class that all pre-existing LED mode plugins inherited from is also derived from `LEDModeInterface`.
The new interface class currently lives in header `LEDMode.h` (see information about this new header below). This is because `LEDMode` and `LEDModeInterface` will
always be used together by dynamic LED modes. Thus, an extra header for `LEDModeInterface` would only mean extra include work for users writing plugins.
Those plugins that export dynamic LED modes must furtheron provide a exported type `DynamicLEDMode`.
This can either be done by defining a nested class of that name or by typedef-ing a class that is defined at global scope to `DynamicLEDMode`. See the modified stock LED modes for examples.
Some of those plugins that export dynamic led modes require access to their particular
dynamic LED mode. By adding the macro `ACCESS_THIS_LED_MODE` to the plugin class definition,
additional data and methods (an integer `led_mode_id_) are synthesized, that enable the plugin class to gain access to their particular dynamic LED mode instance (as long as it is active).
The synthesized integer member `led_mode_id_` can be used to query if the currently active LED mode is the oned handled by the plugin class instance (note that there might be more than one plugin instance of the same class and thus also several dynamic LED modes, see e.g. the solid color LED mode).
A query in the plugin's event handler e.g. looks as follows.
```cpp
if (::LEDControl.get_mode_index() != led_mode_id_)
return EventHandlerResult::OK;
```
All stock LED modes have been adapted to export dynamic LED modes (if possible).
This does not apply to all of them as for some the transition would have provided no gain.
It would even have meant a deterioration of resource consumption for those few pre-existing stock LED mode plugins that hardly have no (static) data-members at all (like e.g. `LEDOff`).
To reduce the amount of compile unit and header interdependencies, the class `LEDMode` has been moved to a header/implementation file of its own.
The `LEDControl` class now does not have a static array anymore to store LED mode pointers.
Instead, it delegates the core LED mode handling to a newly introduced `LEDModeManager` class
that lives in internal namespace. The `LEDModeManager` class is there to restrict access
to LED modes but also to wrap up core LED mode handling. If this functionality would
have been added to class `LEDControl`, far too much of the internals of LED mode handling would have been exposed to users through header `LEDControl.h`.
The new internal header `array_like_storage.h` contains a template class that is used to generate
array-like storages. Here array-like means that the contained pieces of information
are stored contiguously in memory in the same way as they would be when defining
language intrinsic (C-style) arrays. This type of storage is especially useful to generate array-like data struktures
in PROGMEM at compile time based on a list of global objects or POD data. By casting the array-like storage's address
to the content's pointer type, an array-like indexed access is possible.
In this PR an array-like data structure is used to generate a PROGMEM
array of LED mode factories. Array-like data structures could also become useful in other places and for future applications.
The most complex part of the implementation of the new LED mode handling is wrapped up in
`LEDModeManager.h` and `LEDModeManager.cpp` to hide it from users' site.
There, recursive template classes are used to setup an array-like data structure of `LEDModeFactory` instances in PROGMEM. Each of the stored `LEDModeFactory`s are associated with one LED mode-plugin as specified in the sketch. The template mechanism filters out any other plugins unrelated to LED modes. `LEDModeFactory`s thereby handle both static and dynamic LED modes.
Class `LEDModeManager` provides access to the LED mode factories and LED modes in general. It exports methods to query the number of LED modes and to activate a LED mode by its mode-ID. Most of this is only available to `LEDControl` that represents the actual user interface.
When a dynamic LED mode is activated, a dedicated `LEDModeFactory` generates an instance of the dynamic LED mode class in the
LED mode buffer. This buffer is shared by all dynamic LED modes. Its size has been determined at compile time by examining all exported dynamic LED mode types and determining the maximum necessary amount of RAM to store any of those.
All LED mode handling related data structures are generated at compile time, based on
the list of plugins that are passed to `KALEIDOSCOPE_INIT_PLUGINS(...)`. This function macro invokes a new function macro `_INIT_LED_MODE_MANAGER` from `LEDModeManager.h` that handles the LED mode related stuff.
Signed-off-by: Florian Fleissner <florian.fleissner@inpartik.de>
6 years ago
|
|
|
WavepoolEffect::TransientLEDMode::TransientLEDMode(const WavepoolEffect *parent)
|
|
|
|
: frames_since_event_(0),
|
Introduced dynamic LED modes
This PR introduces the concept of dynamic LED modes. Those are LED modes whose class instances
have a restricted lifetime that lasts only as long as a LED mode is active. By this means
it is possible to support a greater amount of LED modes - especially RAM-hungry ones - in the same firmware build. The amount of RAM used to store dynamic LED modes is now bounded
by the maximum size (`sizeof(...)`) of the largest dynamic LED mode.
Old-style LED modes are furtheron called _static_ in the terminology of this PR. They are still supported and blend in nicely with the newly introduced dynamic LED modes.
All changes are entirely backward compatible. No user sketches or existing user plugins require changes.
The greatest benefit of this change is that it drastically reduces the consumption of RAM
when multiple complex LED modes are used. Currently the most complex stock LED mode is
the wavepool effect. Its plugin requires around 140 bytes of RAM that are statically allocated and cannot be shared with any other features.
With this change it becomes possible to have a large number of such resource-hungry LED modes in parallel without a significant gain in RAM consumption.
For the stock firmware this change means a small (~30 byte) growth in terms of PROGMEM. On the other hand it reduces the amount of statically consumed RAM by ~90 bytes. As the current atmel architectures come with around ten times as much PROGMEM as RAM, this means a great improvement as RAM is the more critical resource.
If the wavepool effect, a especially RAM-hungry LED mode is added to the stock firmware,
the saving of RAM increases to 160 bytes which is almost 8% of RAM of the Keyboardio Model01.
A new interface class `LEDModeInterface` was introduced that those plugins
that export dynamic LED modes inherit from. To remain backward compatible, the `LEDMode` class that all pre-existing LED mode plugins inherited from is also derived from `LEDModeInterface`.
The new interface class currently lives in header `LEDMode.h` (see information about this new header below). This is because `LEDMode` and `LEDModeInterface` will
always be used together by dynamic LED modes. Thus, an extra header for `LEDModeInterface` would only mean extra include work for users writing plugins.
Those plugins that export dynamic LED modes must furtheron provide a exported type `DynamicLEDMode`.
This can either be done by defining a nested class of that name or by typedef-ing a class that is defined at global scope to `DynamicLEDMode`. See the modified stock LED modes for examples.
Some of those plugins that export dynamic led modes require access to their particular
dynamic LED mode. By adding the macro `ACCESS_THIS_LED_MODE` to the plugin class definition,
additional data and methods (an integer `led_mode_id_) are synthesized, that enable the plugin class to gain access to their particular dynamic LED mode instance (as long as it is active).
The synthesized integer member `led_mode_id_` can be used to query if the currently active LED mode is the oned handled by the plugin class instance (note that there might be more than one plugin instance of the same class and thus also several dynamic LED modes, see e.g. the solid color LED mode).
A query in the plugin's event handler e.g. looks as follows.
```cpp
if (::LEDControl.get_mode_index() != led_mode_id_)
return EventHandlerResult::OK;
```
All stock LED modes have been adapted to export dynamic LED modes (if possible).
This does not apply to all of them as for some the transition would have provided no gain.
It would even have meant a deterioration of resource consumption for those few pre-existing stock LED mode plugins that hardly have no (static) data-members at all (like e.g. `LEDOff`).
To reduce the amount of compile unit and header interdependencies, the class `LEDMode` has been moved to a header/implementation file of its own.
The `LEDControl` class now does not have a static array anymore to store LED mode pointers.
Instead, it delegates the core LED mode handling to a newly introduced `LEDModeManager` class
that lives in internal namespace. The `LEDModeManager` class is there to restrict access
to LED modes but also to wrap up core LED mode handling. If this functionality would
have been added to class `LEDControl`, far too much of the internals of LED mode handling would have been exposed to users through header `LEDControl.h`.
The new internal header `array_like_storage.h` contains a template class that is used to generate
array-like storages. Here array-like means that the contained pieces of information
are stored contiguously in memory in the same way as they would be when defining
language intrinsic (C-style) arrays. This type of storage is especially useful to generate array-like data struktures
in PROGMEM at compile time based on a list of global objects or POD data. By casting the array-like storage's address
to the content's pointer type, an array-like indexed access is possible.
In this PR an array-like data structure is used to generate a PROGMEM
array of LED mode factories. Array-like data structures could also become useful in other places and for future applications.
The most complex part of the implementation of the new LED mode handling is wrapped up in
`LEDModeManager.h` and `LEDModeManager.cpp` to hide it from users' site.
There, recursive template classes are used to setup an array-like data structure of `LEDModeFactory` instances in PROGMEM. Each of the stored `LEDModeFactory`s are associated with one LED mode-plugin as specified in the sketch. The template mechanism filters out any other plugins unrelated to LED modes. `LEDModeFactory`s thereby handle both static and dynamic LED modes.
Class `LEDModeManager` provides access to the LED mode factories and LED modes in general. It exports methods to query the number of LED modes and to activate a LED mode by its mode-ID. Most of this is only available to `LEDControl` that represents the actual user interface.
When a dynamic LED mode is activated, a dedicated `LEDModeFactory` generates an instance of the dynamic LED mode class in the
LED mode buffer. This buffer is shared by all dynamic LED modes. Its size has been determined at compile time by examining all exported dynamic LED mode types and determining the maximum necessary amount of RAM to store any of those.
All LED mode handling related data structures are generated at compile time, based on
the list of plugins that are passed to `KALEIDOSCOPE_INIT_PLUGINS(...)`. This function macro invokes a new function macro `_INIT_LED_MODE_MANAGER` from `LEDModeManager.h` that handles the LED mode related stuff.
Signed-off-by: Florian Fleissner <florian.fleissner@inpartik.de>
6 years ago
|
|
|
surface_{},
|
|
|
|
page_(0) {}
|
Introduced dynamic LED modes
This PR introduces the concept of dynamic LED modes. Those are LED modes whose class instances
have a restricted lifetime that lasts only as long as a LED mode is active. By this means
it is possible to support a greater amount of LED modes - especially RAM-hungry ones - in the same firmware build. The amount of RAM used to store dynamic LED modes is now bounded
by the maximum size (`sizeof(...)`) of the largest dynamic LED mode.
Old-style LED modes are furtheron called _static_ in the terminology of this PR. They are still supported and blend in nicely with the newly introduced dynamic LED modes.
All changes are entirely backward compatible. No user sketches or existing user plugins require changes.
The greatest benefit of this change is that it drastically reduces the consumption of RAM
when multiple complex LED modes are used. Currently the most complex stock LED mode is
the wavepool effect. Its plugin requires around 140 bytes of RAM that are statically allocated and cannot be shared with any other features.
With this change it becomes possible to have a large number of such resource-hungry LED modes in parallel without a significant gain in RAM consumption.
For the stock firmware this change means a small (~30 byte) growth in terms of PROGMEM. On the other hand it reduces the amount of statically consumed RAM by ~90 bytes. As the current atmel architectures come with around ten times as much PROGMEM as RAM, this means a great improvement as RAM is the more critical resource.
If the wavepool effect, a especially RAM-hungry LED mode is added to the stock firmware,
the saving of RAM increases to 160 bytes which is almost 8% of RAM of the Keyboardio Model01.
A new interface class `LEDModeInterface` was introduced that those plugins
that export dynamic LED modes inherit from. To remain backward compatible, the `LEDMode` class that all pre-existing LED mode plugins inherited from is also derived from `LEDModeInterface`.
The new interface class currently lives in header `LEDMode.h` (see information about this new header below). This is because `LEDMode` and `LEDModeInterface` will
always be used together by dynamic LED modes. Thus, an extra header for `LEDModeInterface` would only mean extra include work for users writing plugins.
Those plugins that export dynamic LED modes must furtheron provide a exported type `DynamicLEDMode`.
This can either be done by defining a nested class of that name or by typedef-ing a class that is defined at global scope to `DynamicLEDMode`. See the modified stock LED modes for examples.
Some of those plugins that export dynamic led modes require access to their particular
dynamic LED mode. By adding the macro `ACCESS_THIS_LED_MODE` to the plugin class definition,
additional data and methods (an integer `led_mode_id_) are synthesized, that enable the plugin class to gain access to their particular dynamic LED mode instance (as long as it is active).
The synthesized integer member `led_mode_id_` can be used to query if the currently active LED mode is the oned handled by the plugin class instance (note that there might be more than one plugin instance of the same class and thus also several dynamic LED modes, see e.g. the solid color LED mode).
A query in the plugin's event handler e.g. looks as follows.
```cpp
if (::LEDControl.get_mode_index() != led_mode_id_)
return EventHandlerResult::OK;
```
All stock LED modes have been adapted to export dynamic LED modes (if possible).
This does not apply to all of them as for some the transition would have provided no gain.
It would even have meant a deterioration of resource consumption for those few pre-existing stock LED mode plugins that hardly have no (static) data-members at all (like e.g. `LEDOff`).
To reduce the amount of compile unit and header interdependencies, the class `LEDMode` has been moved to a header/implementation file of its own.
The `LEDControl` class now does not have a static array anymore to store LED mode pointers.
Instead, it delegates the core LED mode handling to a newly introduced `LEDModeManager` class
that lives in internal namespace. The `LEDModeManager` class is there to restrict access
to LED modes but also to wrap up core LED mode handling. If this functionality would
have been added to class `LEDControl`, far too much of the internals of LED mode handling would have been exposed to users through header `LEDControl.h`.
The new internal header `array_like_storage.h` contains a template class that is used to generate
array-like storages. Here array-like means that the contained pieces of information
are stored contiguously in memory in the same way as they would be when defining
language intrinsic (C-style) arrays. This type of storage is especially useful to generate array-like data struktures
in PROGMEM at compile time based on a list of global objects or POD data. By casting the array-like storage's address
to the content's pointer type, an array-like indexed access is possible.
In this PR an array-like data structure is used to generate a PROGMEM
array of LED mode factories. Array-like data structures could also become useful in other places and for future applications.
The most complex part of the implementation of the new LED mode handling is wrapped up in
`LEDModeManager.h` and `LEDModeManager.cpp` to hide it from users' site.
There, recursive template classes are used to setup an array-like data structure of `LEDModeFactory` instances in PROGMEM. Each of the stored `LEDModeFactory`s are associated with one LED mode-plugin as specified in the sketch. The template mechanism filters out any other plugins unrelated to LED modes. `LEDModeFactory`s thereby handle both static and dynamic LED modes.
Class `LEDModeManager` provides access to the LED mode factories and LED modes in general. It exports methods to query the number of LED modes and to activate a LED mode by its mode-ID. Most of this is only available to `LEDControl` that represents the actual user interface.
When a dynamic LED mode is activated, a dedicated `LEDModeFactory` generates an instance of the dynamic LED mode class in the
LED mode buffer. This buffer is shared by all dynamic LED modes. Its size has been determined at compile time by examining all exported dynamic LED mode types and determining the maximum necessary amount of RAM to store any of those.
All LED mode handling related data structures are generated at compile time, based on
the list of plugins that are passed to `KALEIDOSCOPE_INIT_PLUGINS(...)`. This function macro invokes a new function macro `_INIT_LED_MODE_MANAGER` from `LEDModeManager.h` that handles the LED mode related stuff.
Signed-off-by: Florian Fleissner <florian.fleissner@inpartik.de>
6 years ago
|
|
|
|
|
|
|
EventHandlerResult WavepoolEffect::onKeyEvent(KeyEvent &event) {
|
|
|
|
if (!event.addr.isValid())
|
|
|
|
return EventHandlerResult::OK;
|
|
|
|
|
Introduced dynamic LED modes
This PR introduces the concept of dynamic LED modes. Those are LED modes whose class instances
have a restricted lifetime that lasts only as long as a LED mode is active. By this means
it is possible to support a greater amount of LED modes - especially RAM-hungry ones - in the same firmware build. The amount of RAM used to store dynamic LED modes is now bounded
by the maximum size (`sizeof(...)`) of the largest dynamic LED mode.
Old-style LED modes are furtheron called _static_ in the terminology of this PR. They are still supported and blend in nicely with the newly introduced dynamic LED modes.
All changes are entirely backward compatible. No user sketches or existing user plugins require changes.
The greatest benefit of this change is that it drastically reduces the consumption of RAM
when multiple complex LED modes are used. Currently the most complex stock LED mode is
the wavepool effect. Its plugin requires around 140 bytes of RAM that are statically allocated and cannot be shared with any other features.
With this change it becomes possible to have a large number of such resource-hungry LED modes in parallel without a significant gain in RAM consumption.
For the stock firmware this change means a small (~30 byte) growth in terms of PROGMEM. On the other hand it reduces the amount of statically consumed RAM by ~90 bytes. As the current atmel architectures come with around ten times as much PROGMEM as RAM, this means a great improvement as RAM is the more critical resource.
If the wavepool effect, a especially RAM-hungry LED mode is added to the stock firmware,
the saving of RAM increases to 160 bytes which is almost 8% of RAM of the Keyboardio Model01.
A new interface class `LEDModeInterface` was introduced that those plugins
that export dynamic LED modes inherit from. To remain backward compatible, the `LEDMode` class that all pre-existing LED mode plugins inherited from is also derived from `LEDModeInterface`.
The new interface class currently lives in header `LEDMode.h` (see information about this new header below). This is because `LEDMode` and `LEDModeInterface` will
always be used together by dynamic LED modes. Thus, an extra header for `LEDModeInterface` would only mean extra include work for users writing plugins.
Those plugins that export dynamic LED modes must furtheron provide a exported type `DynamicLEDMode`.
This can either be done by defining a nested class of that name or by typedef-ing a class that is defined at global scope to `DynamicLEDMode`. See the modified stock LED modes for examples.
Some of those plugins that export dynamic led modes require access to their particular
dynamic LED mode. By adding the macro `ACCESS_THIS_LED_MODE` to the plugin class definition,
additional data and methods (an integer `led_mode_id_) are synthesized, that enable the plugin class to gain access to their particular dynamic LED mode instance (as long as it is active).
The synthesized integer member `led_mode_id_` can be used to query if the currently active LED mode is the oned handled by the plugin class instance (note that there might be more than one plugin instance of the same class and thus also several dynamic LED modes, see e.g. the solid color LED mode).
A query in the plugin's event handler e.g. looks as follows.
```cpp
if (::LEDControl.get_mode_index() != led_mode_id_)
return EventHandlerResult::OK;
```
All stock LED modes have been adapted to export dynamic LED modes (if possible).
This does not apply to all of them as for some the transition would have provided no gain.
It would even have meant a deterioration of resource consumption for those few pre-existing stock LED mode plugins that hardly have no (static) data-members at all (like e.g. `LEDOff`).
To reduce the amount of compile unit and header interdependencies, the class `LEDMode` has been moved to a header/implementation file of its own.
The `LEDControl` class now does not have a static array anymore to store LED mode pointers.
Instead, it delegates the core LED mode handling to a newly introduced `LEDModeManager` class
that lives in internal namespace. The `LEDModeManager` class is there to restrict access
to LED modes but also to wrap up core LED mode handling. If this functionality would
have been added to class `LEDControl`, far too much of the internals of LED mode handling would have been exposed to users through header `LEDControl.h`.
The new internal header `array_like_storage.h` contains a template class that is used to generate
array-like storages. Here array-like means that the contained pieces of information
are stored contiguously in memory in the same way as they would be when defining
language intrinsic (C-style) arrays. This type of storage is especially useful to generate array-like data struktures
in PROGMEM at compile time based on a list of global objects or POD data. By casting the array-like storage's address
to the content's pointer type, an array-like indexed access is possible.
In this PR an array-like data structure is used to generate a PROGMEM
array of LED mode factories. Array-like data structures could also become useful in other places and for future applications.
The most complex part of the implementation of the new LED mode handling is wrapped up in
`LEDModeManager.h` and `LEDModeManager.cpp` to hide it from users' site.
There, recursive template classes are used to setup an array-like data structure of `LEDModeFactory` instances in PROGMEM. Each of the stored `LEDModeFactory`s are associated with one LED mode-plugin as specified in the sketch. The template mechanism filters out any other plugins unrelated to LED modes. `LEDModeFactory`s thereby handle both static and dynamic LED modes.
Class `LEDModeManager` provides access to the LED mode factories and LED modes in general. It exports methods to query the number of LED modes and to activate a LED mode by its mode-ID. Most of this is only available to `LEDControl` that represents the actual user interface.
When a dynamic LED mode is activated, a dedicated `LEDModeFactory` generates an instance of the dynamic LED mode class in the
LED mode buffer. This buffer is shared by all dynamic LED modes. Its size has been determined at compile time by examining all exported dynamic LED mode types and determining the maximum necessary amount of RAM to store any of those.
All LED mode handling related data structures are generated at compile time, based on
the list of plugins that are passed to `KALEIDOSCOPE_INIT_PLUGINS(...)`. This function macro invokes a new function macro `_INIT_LED_MODE_MANAGER` from `LEDModeManager.h` that handles the LED mode related stuff.
Signed-off-by: Florian Fleissner <florian.fleissner@inpartik.de>
6 years ago
|
|
|
if (::LEDControl.get_mode_index() != led_mode_id_)
|
|
|
|
return EventHandlerResult::OK;
|
|
|
|
|
|
|
|
return ::LEDControl.get_mode<TransientLEDMode>()->onKeyEvent(event);
|
Introduced dynamic LED modes
This PR introduces the concept of dynamic LED modes. Those are LED modes whose class instances
have a restricted lifetime that lasts only as long as a LED mode is active. By this means
it is possible to support a greater amount of LED modes - especially RAM-hungry ones - in the same firmware build. The amount of RAM used to store dynamic LED modes is now bounded
by the maximum size (`sizeof(...)`) of the largest dynamic LED mode.
Old-style LED modes are furtheron called _static_ in the terminology of this PR. They are still supported and blend in nicely with the newly introduced dynamic LED modes.
All changes are entirely backward compatible. No user sketches or existing user plugins require changes.
The greatest benefit of this change is that it drastically reduces the consumption of RAM
when multiple complex LED modes are used. Currently the most complex stock LED mode is
the wavepool effect. Its plugin requires around 140 bytes of RAM that are statically allocated and cannot be shared with any other features.
With this change it becomes possible to have a large number of such resource-hungry LED modes in parallel without a significant gain in RAM consumption.
For the stock firmware this change means a small (~30 byte) growth in terms of PROGMEM. On the other hand it reduces the amount of statically consumed RAM by ~90 bytes. As the current atmel architectures come with around ten times as much PROGMEM as RAM, this means a great improvement as RAM is the more critical resource.
If the wavepool effect, a especially RAM-hungry LED mode is added to the stock firmware,
the saving of RAM increases to 160 bytes which is almost 8% of RAM of the Keyboardio Model01.
A new interface class `LEDModeInterface` was introduced that those plugins
that export dynamic LED modes inherit from. To remain backward compatible, the `LEDMode` class that all pre-existing LED mode plugins inherited from is also derived from `LEDModeInterface`.
The new interface class currently lives in header `LEDMode.h` (see information about this new header below). This is because `LEDMode` and `LEDModeInterface` will
always be used together by dynamic LED modes. Thus, an extra header for `LEDModeInterface` would only mean extra include work for users writing plugins.
Those plugins that export dynamic LED modes must furtheron provide a exported type `DynamicLEDMode`.
This can either be done by defining a nested class of that name or by typedef-ing a class that is defined at global scope to `DynamicLEDMode`. See the modified stock LED modes for examples.
Some of those plugins that export dynamic led modes require access to their particular
dynamic LED mode. By adding the macro `ACCESS_THIS_LED_MODE` to the plugin class definition,
additional data and methods (an integer `led_mode_id_) are synthesized, that enable the plugin class to gain access to their particular dynamic LED mode instance (as long as it is active).
The synthesized integer member `led_mode_id_` can be used to query if the currently active LED mode is the oned handled by the plugin class instance (note that there might be more than one plugin instance of the same class and thus also several dynamic LED modes, see e.g. the solid color LED mode).
A query in the plugin's event handler e.g. looks as follows.
```cpp
if (::LEDControl.get_mode_index() != led_mode_id_)
return EventHandlerResult::OK;
```
All stock LED modes have been adapted to export dynamic LED modes (if possible).
This does not apply to all of them as for some the transition would have provided no gain.
It would even have meant a deterioration of resource consumption for those few pre-existing stock LED mode plugins that hardly have no (static) data-members at all (like e.g. `LEDOff`).
To reduce the amount of compile unit and header interdependencies, the class `LEDMode` has been moved to a header/implementation file of its own.
The `LEDControl` class now does not have a static array anymore to store LED mode pointers.
Instead, it delegates the core LED mode handling to a newly introduced `LEDModeManager` class
that lives in internal namespace. The `LEDModeManager` class is there to restrict access
to LED modes but also to wrap up core LED mode handling. If this functionality would
have been added to class `LEDControl`, far too much of the internals of LED mode handling would have been exposed to users through header `LEDControl.h`.
The new internal header `array_like_storage.h` contains a template class that is used to generate
array-like storages. Here array-like means that the contained pieces of information
are stored contiguously in memory in the same way as they would be when defining
language intrinsic (C-style) arrays. This type of storage is especially useful to generate array-like data struktures
in PROGMEM at compile time based on a list of global objects or POD data. By casting the array-like storage's address
to the content's pointer type, an array-like indexed access is possible.
In this PR an array-like data structure is used to generate a PROGMEM
array of LED mode factories. Array-like data structures could also become useful in other places and for future applications.
The most complex part of the implementation of the new LED mode handling is wrapped up in
`LEDModeManager.h` and `LEDModeManager.cpp` to hide it from users' site.
There, recursive template classes are used to setup an array-like data structure of `LEDModeFactory` instances in PROGMEM. Each of the stored `LEDModeFactory`s are associated with one LED mode-plugin as specified in the sketch. The template mechanism filters out any other plugins unrelated to LED modes. `LEDModeFactory`s thereby handle both static and dynamic LED modes.
Class `LEDModeManager` provides access to the LED mode factories and LED modes in general. It exports methods to query the number of LED modes and to activate a LED mode by its mode-ID. Most of this is only available to `LEDControl` that represents the actual user interface.
When a dynamic LED mode is activated, a dedicated `LEDModeFactory` generates an instance of the dynamic LED mode class in the
LED mode buffer. This buffer is shared by all dynamic LED modes. Its size has been determined at compile time by examining all exported dynamic LED mode types and determining the maximum necessary amount of RAM to store any of those.
All LED mode handling related data structures are generated at compile time, based on
the list of plugins that are passed to `KALEIDOSCOPE_INIT_PLUGINS(...)`. This function macro invokes a new function macro `_INIT_LED_MODE_MANAGER` from `LEDModeManager.h` that handles the LED mode related stuff.
Signed-off-by: Florian Fleissner <florian.fleissner@inpartik.de>
6 years ago
|
|
|
}
|
|
|
|
|
|
|
|
EventHandlerResult WavepoolEffect::TransientLEDMode::onKeyEvent(KeyEvent &event) {
|
|
|
|
// It might be better to trigger on both toggle-on and toggle-off, but maybe
|
|
|
|
// just the former.
|
|
|
|
if (keyIsPressed(event.state)) {
|
|
|
|
surface_[page_][pgm_read_byte(rc2pos + event.addr.toInt())] = 0x7f;
|
|
|
|
frames_since_event_ = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EventHandlerResult::OK;
|
|
|
|
}
|
|
|
|
|
Introduced dynamic LED modes
This PR introduces the concept of dynamic LED modes. Those are LED modes whose class instances
have a restricted lifetime that lasts only as long as a LED mode is active. By this means
it is possible to support a greater amount of LED modes - especially RAM-hungry ones - in the same firmware build. The amount of RAM used to store dynamic LED modes is now bounded
by the maximum size (`sizeof(...)`) of the largest dynamic LED mode.
Old-style LED modes are furtheron called _static_ in the terminology of this PR. They are still supported and blend in nicely with the newly introduced dynamic LED modes.
All changes are entirely backward compatible. No user sketches or existing user plugins require changes.
The greatest benefit of this change is that it drastically reduces the consumption of RAM
when multiple complex LED modes are used. Currently the most complex stock LED mode is
the wavepool effect. Its plugin requires around 140 bytes of RAM that are statically allocated and cannot be shared with any other features.
With this change it becomes possible to have a large number of such resource-hungry LED modes in parallel without a significant gain in RAM consumption.
For the stock firmware this change means a small (~30 byte) growth in terms of PROGMEM. On the other hand it reduces the amount of statically consumed RAM by ~90 bytes. As the current atmel architectures come with around ten times as much PROGMEM as RAM, this means a great improvement as RAM is the more critical resource.
If the wavepool effect, a especially RAM-hungry LED mode is added to the stock firmware,
the saving of RAM increases to 160 bytes which is almost 8% of RAM of the Keyboardio Model01.
A new interface class `LEDModeInterface` was introduced that those plugins
that export dynamic LED modes inherit from. To remain backward compatible, the `LEDMode` class that all pre-existing LED mode plugins inherited from is also derived from `LEDModeInterface`.
The new interface class currently lives in header `LEDMode.h` (see information about this new header below). This is because `LEDMode` and `LEDModeInterface` will
always be used together by dynamic LED modes. Thus, an extra header for `LEDModeInterface` would only mean extra include work for users writing plugins.
Those plugins that export dynamic LED modes must furtheron provide a exported type `DynamicLEDMode`.
This can either be done by defining a nested class of that name or by typedef-ing a class that is defined at global scope to `DynamicLEDMode`. See the modified stock LED modes for examples.
Some of those plugins that export dynamic led modes require access to their particular
dynamic LED mode. By adding the macro `ACCESS_THIS_LED_MODE` to the plugin class definition,
additional data and methods (an integer `led_mode_id_) are synthesized, that enable the plugin class to gain access to their particular dynamic LED mode instance (as long as it is active).
The synthesized integer member `led_mode_id_` can be used to query if the currently active LED mode is the oned handled by the plugin class instance (note that there might be more than one plugin instance of the same class and thus also several dynamic LED modes, see e.g. the solid color LED mode).
A query in the plugin's event handler e.g. looks as follows.
```cpp
if (::LEDControl.get_mode_index() != led_mode_id_)
return EventHandlerResult::OK;
```
All stock LED modes have been adapted to export dynamic LED modes (if possible).
This does not apply to all of them as for some the transition would have provided no gain.
It would even have meant a deterioration of resource consumption for those few pre-existing stock LED mode plugins that hardly have no (static) data-members at all (like e.g. `LEDOff`).
To reduce the amount of compile unit and header interdependencies, the class `LEDMode` has been moved to a header/implementation file of its own.
The `LEDControl` class now does not have a static array anymore to store LED mode pointers.
Instead, it delegates the core LED mode handling to a newly introduced `LEDModeManager` class
that lives in internal namespace. The `LEDModeManager` class is there to restrict access
to LED modes but also to wrap up core LED mode handling. If this functionality would
have been added to class `LEDControl`, far too much of the internals of LED mode handling would have been exposed to users through header `LEDControl.h`.
The new internal header `array_like_storage.h` contains a template class that is used to generate
array-like storages. Here array-like means that the contained pieces of information
are stored contiguously in memory in the same way as they would be when defining
language intrinsic (C-style) arrays. This type of storage is especially useful to generate array-like data struktures
in PROGMEM at compile time based on a list of global objects or POD data. By casting the array-like storage's address
to the content's pointer type, an array-like indexed access is possible.
In this PR an array-like data structure is used to generate a PROGMEM
array of LED mode factories. Array-like data structures could also become useful in other places and for future applications.
The most complex part of the implementation of the new LED mode handling is wrapped up in
`LEDModeManager.h` and `LEDModeManager.cpp` to hide it from users' site.
There, recursive template classes are used to setup an array-like data structure of `LEDModeFactory` instances in PROGMEM. Each of the stored `LEDModeFactory`s are associated with one LED mode-plugin as specified in the sketch. The template mechanism filters out any other plugins unrelated to LED modes. `LEDModeFactory`s thereby handle both static and dynamic LED modes.
Class `LEDModeManager` provides access to the LED mode factories and LED modes in general. It exports methods to query the number of LED modes and to activate a LED mode by its mode-ID. Most of this is only available to `LEDControl` that represents the actual user interface.
When a dynamic LED mode is activated, a dedicated `LEDModeFactory` generates an instance of the dynamic LED mode class in the
LED mode buffer. This buffer is shared by all dynamic LED modes. Its size has been determined at compile time by examining all exported dynamic LED mode types and determining the maximum necessary amount of RAM to store any of those.
All LED mode handling related data structures are generated at compile time, based on
the list of plugins that are passed to `KALEIDOSCOPE_INIT_PLUGINS(...)`. This function macro invokes a new function macro `_INIT_LED_MODE_MANAGER` from `LEDModeManager.h` that handles the LED mode related stuff.
Signed-off-by: Florian Fleissner <florian.fleissner@inpartik.de>
6 years ago
|
|
|
void WavepoolEffect::TransientLEDMode::raindrop(uint8_t x, uint8_t y, int8_t *page_) {
|
|
|
|
uint8_t rainspot = (y * WP_WID) + x;
|
|
|
|
|
Introduced dynamic LED modes
This PR introduces the concept of dynamic LED modes. Those are LED modes whose class instances
have a restricted lifetime that lasts only as long as a LED mode is active. By this means
it is possible to support a greater amount of LED modes - especially RAM-hungry ones - in the same firmware build. The amount of RAM used to store dynamic LED modes is now bounded
by the maximum size (`sizeof(...)`) of the largest dynamic LED mode.
Old-style LED modes are furtheron called _static_ in the terminology of this PR. They are still supported and blend in nicely with the newly introduced dynamic LED modes.
All changes are entirely backward compatible. No user sketches or existing user plugins require changes.
The greatest benefit of this change is that it drastically reduces the consumption of RAM
when multiple complex LED modes are used. Currently the most complex stock LED mode is
the wavepool effect. Its plugin requires around 140 bytes of RAM that are statically allocated and cannot be shared with any other features.
With this change it becomes possible to have a large number of such resource-hungry LED modes in parallel without a significant gain in RAM consumption.
For the stock firmware this change means a small (~30 byte) growth in terms of PROGMEM. On the other hand it reduces the amount of statically consumed RAM by ~90 bytes. As the current atmel architectures come with around ten times as much PROGMEM as RAM, this means a great improvement as RAM is the more critical resource.
If the wavepool effect, a especially RAM-hungry LED mode is added to the stock firmware,
the saving of RAM increases to 160 bytes which is almost 8% of RAM of the Keyboardio Model01.
A new interface class `LEDModeInterface` was introduced that those plugins
that export dynamic LED modes inherit from. To remain backward compatible, the `LEDMode` class that all pre-existing LED mode plugins inherited from is also derived from `LEDModeInterface`.
The new interface class currently lives in header `LEDMode.h` (see information about this new header below). This is because `LEDMode` and `LEDModeInterface` will
always be used together by dynamic LED modes. Thus, an extra header for `LEDModeInterface` would only mean extra include work for users writing plugins.
Those plugins that export dynamic LED modes must furtheron provide a exported type `DynamicLEDMode`.
This can either be done by defining a nested class of that name or by typedef-ing a class that is defined at global scope to `DynamicLEDMode`. See the modified stock LED modes for examples.
Some of those plugins that export dynamic led modes require access to their particular
dynamic LED mode. By adding the macro `ACCESS_THIS_LED_MODE` to the plugin class definition,
additional data and methods (an integer `led_mode_id_) are synthesized, that enable the plugin class to gain access to their particular dynamic LED mode instance (as long as it is active).
The synthesized integer member `led_mode_id_` can be used to query if the currently active LED mode is the oned handled by the plugin class instance (note that there might be more than one plugin instance of the same class and thus also several dynamic LED modes, see e.g. the solid color LED mode).
A query in the plugin's event handler e.g. looks as follows.
```cpp
if (::LEDControl.get_mode_index() != led_mode_id_)
return EventHandlerResult::OK;
```
All stock LED modes have been adapted to export dynamic LED modes (if possible).
This does not apply to all of them as for some the transition would have provided no gain.
It would even have meant a deterioration of resource consumption for those few pre-existing stock LED mode plugins that hardly have no (static) data-members at all (like e.g. `LEDOff`).
To reduce the amount of compile unit and header interdependencies, the class `LEDMode` has been moved to a header/implementation file of its own.
The `LEDControl` class now does not have a static array anymore to store LED mode pointers.
Instead, it delegates the core LED mode handling to a newly introduced `LEDModeManager` class
that lives in internal namespace. The `LEDModeManager` class is there to restrict access
to LED modes but also to wrap up core LED mode handling. If this functionality would
have been added to class `LEDControl`, far too much of the internals of LED mode handling would have been exposed to users through header `LEDControl.h`.
The new internal header `array_like_storage.h` contains a template class that is used to generate
array-like storages. Here array-like means that the contained pieces of information
are stored contiguously in memory in the same way as they would be when defining
language intrinsic (C-style) arrays. This type of storage is especially useful to generate array-like data struktures
in PROGMEM at compile time based on a list of global objects or POD data. By casting the array-like storage's address
to the content's pointer type, an array-like indexed access is possible.
In this PR an array-like data structure is used to generate a PROGMEM
array of LED mode factories. Array-like data structures could also become useful in other places and for future applications.
The most complex part of the implementation of the new LED mode handling is wrapped up in
`LEDModeManager.h` and `LEDModeManager.cpp` to hide it from users' site.
There, recursive template classes are used to setup an array-like data structure of `LEDModeFactory` instances in PROGMEM. Each of the stored `LEDModeFactory`s are associated with one LED mode-plugin as specified in the sketch. The template mechanism filters out any other plugins unrelated to LED modes. `LEDModeFactory`s thereby handle both static and dynamic LED modes.
Class `LEDModeManager` provides access to the LED mode factories and LED modes in general. It exports methods to query the number of LED modes and to activate a LED mode by its mode-ID. Most of this is only available to `LEDControl` that represents the actual user interface.
When a dynamic LED mode is activated, a dedicated `LEDModeFactory` generates an instance of the dynamic LED mode class in the
LED mode buffer. This buffer is shared by all dynamic LED modes. Its size has been determined at compile time by examining all exported dynamic LED mode types and determining the maximum necessary amount of RAM to store any of those.
All LED mode handling related data structures are generated at compile time, based on
the list of plugins that are passed to `KALEIDOSCOPE_INIT_PLUGINS(...)`. This function macro invokes a new function macro `_INIT_LED_MODE_MANAGER` from `LEDModeManager.h` that handles the LED mode related stuff.
Signed-off-by: Florian Fleissner <florian.fleissner@inpartik.de>
6 years ago
|
|
|
page_[rainspot] = 0x7f;
|
|
|
|
if (y > 0) page_[rainspot - WP_WID] = 0x60;
|
|
|
|
if (y < (WP_HGT - 1)) page_[rainspot + WP_WID] = 0x60;
|
|
|
|
if (x > 0) page_[rainspot - 1] = 0x60;
|
|
|
|
if (x < (WP_WID - 1)) page_[rainspot + 1] = 0x60;
|
|
|
|
}
|
|
|
|
|
|
|
|
// this is a lot smaller than the standard library's rand(),
|
|
|
|
// and still looks random-ish
|
Introduced dynamic LED modes
This PR introduces the concept of dynamic LED modes. Those are LED modes whose class instances
have a restricted lifetime that lasts only as long as a LED mode is active. By this means
it is possible to support a greater amount of LED modes - especially RAM-hungry ones - in the same firmware build. The amount of RAM used to store dynamic LED modes is now bounded
by the maximum size (`sizeof(...)`) of the largest dynamic LED mode.
Old-style LED modes are furtheron called _static_ in the terminology of this PR. They are still supported and blend in nicely with the newly introduced dynamic LED modes.
All changes are entirely backward compatible. No user sketches or existing user plugins require changes.
The greatest benefit of this change is that it drastically reduces the consumption of RAM
when multiple complex LED modes are used. Currently the most complex stock LED mode is
the wavepool effect. Its plugin requires around 140 bytes of RAM that are statically allocated and cannot be shared with any other features.
With this change it becomes possible to have a large number of such resource-hungry LED modes in parallel without a significant gain in RAM consumption.
For the stock firmware this change means a small (~30 byte) growth in terms of PROGMEM. On the other hand it reduces the amount of statically consumed RAM by ~90 bytes. As the current atmel architectures come with around ten times as much PROGMEM as RAM, this means a great improvement as RAM is the more critical resource.
If the wavepool effect, a especially RAM-hungry LED mode is added to the stock firmware,
the saving of RAM increases to 160 bytes which is almost 8% of RAM of the Keyboardio Model01.
A new interface class `LEDModeInterface` was introduced that those plugins
that export dynamic LED modes inherit from. To remain backward compatible, the `LEDMode` class that all pre-existing LED mode plugins inherited from is also derived from `LEDModeInterface`.
The new interface class currently lives in header `LEDMode.h` (see information about this new header below). This is because `LEDMode` and `LEDModeInterface` will
always be used together by dynamic LED modes. Thus, an extra header for `LEDModeInterface` would only mean extra include work for users writing plugins.
Those plugins that export dynamic LED modes must furtheron provide a exported type `DynamicLEDMode`.
This can either be done by defining a nested class of that name or by typedef-ing a class that is defined at global scope to `DynamicLEDMode`. See the modified stock LED modes for examples.
Some of those plugins that export dynamic led modes require access to their particular
dynamic LED mode. By adding the macro `ACCESS_THIS_LED_MODE` to the plugin class definition,
additional data and methods (an integer `led_mode_id_) are synthesized, that enable the plugin class to gain access to their particular dynamic LED mode instance (as long as it is active).
The synthesized integer member `led_mode_id_` can be used to query if the currently active LED mode is the oned handled by the plugin class instance (note that there might be more than one plugin instance of the same class and thus also several dynamic LED modes, see e.g. the solid color LED mode).
A query in the plugin's event handler e.g. looks as follows.
```cpp
if (::LEDControl.get_mode_index() != led_mode_id_)
return EventHandlerResult::OK;
```
All stock LED modes have been adapted to export dynamic LED modes (if possible).
This does not apply to all of them as for some the transition would have provided no gain.
It would even have meant a deterioration of resource consumption for those few pre-existing stock LED mode plugins that hardly have no (static) data-members at all (like e.g. `LEDOff`).
To reduce the amount of compile unit and header interdependencies, the class `LEDMode` has been moved to a header/implementation file of its own.
The `LEDControl` class now does not have a static array anymore to store LED mode pointers.
Instead, it delegates the core LED mode handling to a newly introduced `LEDModeManager` class
that lives in internal namespace. The `LEDModeManager` class is there to restrict access
to LED modes but also to wrap up core LED mode handling. If this functionality would
have been added to class `LEDControl`, far too much of the internals of LED mode handling would have been exposed to users through header `LEDControl.h`.
The new internal header `array_like_storage.h` contains a template class that is used to generate
array-like storages. Here array-like means that the contained pieces of information
are stored contiguously in memory in the same way as they would be when defining
language intrinsic (C-style) arrays. This type of storage is especially useful to generate array-like data struktures
in PROGMEM at compile time based on a list of global objects or POD data. By casting the array-like storage's address
to the content's pointer type, an array-like indexed access is possible.
In this PR an array-like data structure is used to generate a PROGMEM
array of LED mode factories. Array-like data structures could also become useful in other places and for future applications.
The most complex part of the implementation of the new LED mode handling is wrapped up in
`LEDModeManager.h` and `LEDModeManager.cpp` to hide it from users' site.
There, recursive template classes are used to setup an array-like data structure of `LEDModeFactory` instances in PROGMEM. Each of the stored `LEDModeFactory`s are associated with one LED mode-plugin as specified in the sketch. The template mechanism filters out any other plugins unrelated to LED modes. `LEDModeFactory`s thereby handle both static and dynamic LED modes.
Class `LEDModeManager` provides access to the LED mode factories and LED modes in general. It exports methods to query the number of LED modes and to activate a LED mode by its mode-ID. Most of this is only available to `LEDControl` that represents the actual user interface.
When a dynamic LED mode is activated, a dedicated `LEDModeFactory` generates an instance of the dynamic LED mode class in the
LED mode buffer. This buffer is shared by all dynamic LED modes. Its size has been determined at compile time by examining all exported dynamic LED mode types and determining the maximum necessary amount of RAM to store any of those.
All LED mode handling related data structures are generated at compile time, based on
the list of plugins that are passed to `KALEIDOSCOPE_INIT_PLUGINS(...)`. This function macro invokes a new function macro `_INIT_LED_MODE_MANAGER` from `LEDModeManager.h` that handles the LED mode related stuff.
Signed-off-by: Florian Fleissner <florian.fleissner@inpartik.de>
6 years ago
|
|
|
uint8_t WavepoolEffect::TransientLEDMode::wp_rand() {
|
|
|
|
static intptr_t offset = 0x400;
|
|
|
|
offset = ((offset + 1) & 0x4fff) | 0x400;
|
|
|
|
return (Runtime.millisAtCycleStart() / MS_PER_FRAME) + pgm_read_byte((const uint8_t *)offset);
|
|
|
|
}
|
|
|
|
|
Introduced dynamic LED modes
This PR introduces the concept of dynamic LED modes. Those are LED modes whose class instances
have a restricted lifetime that lasts only as long as a LED mode is active. By this means
it is possible to support a greater amount of LED modes - especially RAM-hungry ones - in the same firmware build. The amount of RAM used to store dynamic LED modes is now bounded
by the maximum size (`sizeof(...)`) of the largest dynamic LED mode.
Old-style LED modes are furtheron called _static_ in the terminology of this PR. They are still supported and blend in nicely with the newly introduced dynamic LED modes.
All changes are entirely backward compatible. No user sketches or existing user plugins require changes.
The greatest benefit of this change is that it drastically reduces the consumption of RAM
when multiple complex LED modes are used. Currently the most complex stock LED mode is
the wavepool effect. Its plugin requires around 140 bytes of RAM that are statically allocated and cannot be shared with any other features.
With this change it becomes possible to have a large number of such resource-hungry LED modes in parallel without a significant gain in RAM consumption.
For the stock firmware this change means a small (~30 byte) growth in terms of PROGMEM. On the other hand it reduces the amount of statically consumed RAM by ~90 bytes. As the current atmel architectures come with around ten times as much PROGMEM as RAM, this means a great improvement as RAM is the more critical resource.
If the wavepool effect, a especially RAM-hungry LED mode is added to the stock firmware,
the saving of RAM increases to 160 bytes which is almost 8% of RAM of the Keyboardio Model01.
A new interface class `LEDModeInterface` was introduced that those plugins
that export dynamic LED modes inherit from. To remain backward compatible, the `LEDMode` class that all pre-existing LED mode plugins inherited from is also derived from `LEDModeInterface`.
The new interface class currently lives in header `LEDMode.h` (see information about this new header below). This is because `LEDMode` and `LEDModeInterface` will
always be used together by dynamic LED modes. Thus, an extra header for `LEDModeInterface` would only mean extra include work for users writing plugins.
Those plugins that export dynamic LED modes must furtheron provide a exported type `DynamicLEDMode`.
This can either be done by defining a nested class of that name or by typedef-ing a class that is defined at global scope to `DynamicLEDMode`. See the modified stock LED modes for examples.
Some of those plugins that export dynamic led modes require access to their particular
dynamic LED mode. By adding the macro `ACCESS_THIS_LED_MODE` to the plugin class definition,
additional data and methods (an integer `led_mode_id_) are synthesized, that enable the plugin class to gain access to their particular dynamic LED mode instance (as long as it is active).
The synthesized integer member `led_mode_id_` can be used to query if the currently active LED mode is the oned handled by the plugin class instance (note that there might be more than one plugin instance of the same class and thus also several dynamic LED modes, see e.g. the solid color LED mode).
A query in the plugin's event handler e.g. looks as follows.
```cpp
if (::LEDControl.get_mode_index() != led_mode_id_)
return EventHandlerResult::OK;
```
All stock LED modes have been adapted to export dynamic LED modes (if possible).
This does not apply to all of them as for some the transition would have provided no gain.
It would even have meant a deterioration of resource consumption for those few pre-existing stock LED mode plugins that hardly have no (static) data-members at all (like e.g. `LEDOff`).
To reduce the amount of compile unit and header interdependencies, the class `LEDMode` has been moved to a header/implementation file of its own.
The `LEDControl` class now does not have a static array anymore to store LED mode pointers.
Instead, it delegates the core LED mode handling to a newly introduced `LEDModeManager` class
that lives in internal namespace. The `LEDModeManager` class is there to restrict access
to LED modes but also to wrap up core LED mode handling. If this functionality would
have been added to class `LEDControl`, far too much of the internals of LED mode handling would have been exposed to users through header `LEDControl.h`.
The new internal header `array_like_storage.h` contains a template class that is used to generate
array-like storages. Here array-like means that the contained pieces of information
are stored contiguously in memory in the same way as they would be when defining
language intrinsic (C-style) arrays. This type of storage is especially useful to generate array-like data struktures
in PROGMEM at compile time based on a list of global objects or POD data. By casting the array-like storage's address
to the content's pointer type, an array-like indexed access is possible.
In this PR an array-like data structure is used to generate a PROGMEM
array of LED mode factories. Array-like data structures could also become useful in other places and for future applications.
The most complex part of the implementation of the new LED mode handling is wrapped up in
`LEDModeManager.h` and `LEDModeManager.cpp` to hide it from users' site.
There, recursive template classes are used to setup an array-like data structure of `LEDModeFactory` instances in PROGMEM. Each of the stored `LEDModeFactory`s are associated with one LED mode-plugin as specified in the sketch. The template mechanism filters out any other plugins unrelated to LED modes. `LEDModeFactory`s thereby handle both static and dynamic LED modes.
Class `LEDModeManager` provides access to the LED mode factories and LED modes in general. It exports methods to query the number of LED modes and to activate a LED mode by its mode-ID. Most of this is only available to `LEDControl` that represents the actual user interface.
When a dynamic LED mode is activated, a dedicated `LEDModeFactory` generates an instance of the dynamic LED mode class in the
LED mode buffer. This buffer is shared by all dynamic LED modes. Its size has been determined at compile time by examining all exported dynamic LED mode types and determining the maximum necessary amount of RAM to store any of those.
All LED mode handling related data structures are generated at compile time, based on
the list of plugins that are passed to `KALEIDOSCOPE_INIT_PLUGINS(...)`. This function macro invokes a new function macro `_INIT_LED_MODE_MANAGER` from `LEDModeManager.h` that handles the LED mode related stuff.
Signed-off-by: Florian Fleissner <florian.fleissner@inpartik.de>
6 years ago
|
|
|
void WavepoolEffect::TransientLEDMode::update(void) {
|
|
|
|
|
|
|
|
// limit the frame rate; one frame every 64 ms
|
|
|
|
static uint8_t prev_time = 0;
|
|
|
|
uint8_t now = Runtime.millisAtCycleStart() / MS_PER_FRAME;
|
|
|
|
if (now != prev_time) {
|
|
|
|
prev_time = now;
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// rotate the colors over time
|
|
|
|
// (side note: it's weird that this is a 16-bit int instead of 8-bit,
|
|
|
|
// but that's what the library function wants)
|
|
|
|
static uint8_t current_hue = 0;
|
|
|
|
current_hue++;
|
|
|
|
|
|
|
|
frames_since_event_++;
|
|
|
|
|
|
|
|
// needs two pages of height map to do the calculations
|
Introduced dynamic LED modes
This PR introduces the concept of dynamic LED modes. Those are LED modes whose class instances
have a restricted lifetime that lasts only as long as a LED mode is active. By this means
it is possible to support a greater amount of LED modes - especially RAM-hungry ones - in the same firmware build. The amount of RAM used to store dynamic LED modes is now bounded
by the maximum size (`sizeof(...)`) of the largest dynamic LED mode.
Old-style LED modes are furtheron called _static_ in the terminology of this PR. They are still supported and blend in nicely with the newly introduced dynamic LED modes.
All changes are entirely backward compatible. No user sketches or existing user plugins require changes.
The greatest benefit of this change is that it drastically reduces the consumption of RAM
when multiple complex LED modes are used. Currently the most complex stock LED mode is
the wavepool effect. Its plugin requires around 140 bytes of RAM that are statically allocated and cannot be shared with any other features.
With this change it becomes possible to have a large number of such resource-hungry LED modes in parallel without a significant gain in RAM consumption.
For the stock firmware this change means a small (~30 byte) growth in terms of PROGMEM. On the other hand it reduces the amount of statically consumed RAM by ~90 bytes. As the current atmel architectures come with around ten times as much PROGMEM as RAM, this means a great improvement as RAM is the more critical resource.
If the wavepool effect, a especially RAM-hungry LED mode is added to the stock firmware,
the saving of RAM increases to 160 bytes which is almost 8% of RAM of the Keyboardio Model01.
A new interface class `LEDModeInterface` was introduced that those plugins
that export dynamic LED modes inherit from. To remain backward compatible, the `LEDMode` class that all pre-existing LED mode plugins inherited from is also derived from `LEDModeInterface`.
The new interface class currently lives in header `LEDMode.h` (see information about this new header below). This is because `LEDMode` and `LEDModeInterface` will
always be used together by dynamic LED modes. Thus, an extra header for `LEDModeInterface` would only mean extra include work for users writing plugins.
Those plugins that export dynamic LED modes must furtheron provide a exported type `DynamicLEDMode`.
This can either be done by defining a nested class of that name or by typedef-ing a class that is defined at global scope to `DynamicLEDMode`. See the modified stock LED modes for examples.
Some of those plugins that export dynamic led modes require access to their particular
dynamic LED mode. By adding the macro `ACCESS_THIS_LED_MODE` to the plugin class definition,
additional data and methods (an integer `led_mode_id_) are synthesized, that enable the plugin class to gain access to their particular dynamic LED mode instance (as long as it is active).
The synthesized integer member `led_mode_id_` can be used to query if the currently active LED mode is the oned handled by the plugin class instance (note that there might be more than one plugin instance of the same class and thus also several dynamic LED modes, see e.g. the solid color LED mode).
A query in the plugin's event handler e.g. looks as follows.
```cpp
if (::LEDControl.get_mode_index() != led_mode_id_)
return EventHandlerResult::OK;
```
All stock LED modes have been adapted to export dynamic LED modes (if possible).
This does not apply to all of them as for some the transition would have provided no gain.
It would even have meant a deterioration of resource consumption for those few pre-existing stock LED mode plugins that hardly have no (static) data-members at all (like e.g. `LEDOff`).
To reduce the amount of compile unit and header interdependencies, the class `LEDMode` has been moved to a header/implementation file of its own.
The `LEDControl` class now does not have a static array anymore to store LED mode pointers.
Instead, it delegates the core LED mode handling to a newly introduced `LEDModeManager` class
that lives in internal namespace. The `LEDModeManager` class is there to restrict access
to LED modes but also to wrap up core LED mode handling. If this functionality would
have been added to class `LEDControl`, far too much of the internals of LED mode handling would have been exposed to users through header `LEDControl.h`.
The new internal header `array_like_storage.h` contains a template class that is used to generate
array-like storages. Here array-like means that the contained pieces of information
are stored contiguously in memory in the same way as they would be when defining
language intrinsic (C-style) arrays. This type of storage is especially useful to generate array-like data struktures
in PROGMEM at compile time based on a list of global objects or POD data. By casting the array-like storage's address
to the content's pointer type, an array-like indexed access is possible.
In this PR an array-like data structure is used to generate a PROGMEM
array of LED mode factories. Array-like data structures could also become useful in other places and for future applications.
The most complex part of the implementation of the new LED mode handling is wrapped up in
`LEDModeManager.h` and `LEDModeManager.cpp` to hide it from users' site.
There, recursive template classes are used to setup an array-like data structure of `LEDModeFactory` instances in PROGMEM. Each of the stored `LEDModeFactory`s are associated with one LED mode-plugin as specified in the sketch. The template mechanism filters out any other plugins unrelated to LED modes. `LEDModeFactory`s thereby handle both static and dynamic LED modes.
Class `LEDModeManager` provides access to the LED mode factories and LED modes in general. It exports methods to query the number of LED modes and to activate a LED mode by its mode-ID. Most of this is only available to `LEDControl` that represents the actual user interface.
When a dynamic LED mode is activated, a dedicated `LEDModeFactory` generates an instance of the dynamic LED mode class in the
LED mode buffer. This buffer is shared by all dynamic LED modes. Its size has been determined at compile time by examining all exported dynamic LED mode types and determining the maximum necessary amount of RAM to store any of those.
All LED mode handling related data structures are generated at compile time, based on
the list of plugins that are passed to `KALEIDOSCOPE_INIT_PLUGINS(...)`. This function macro invokes a new function macro `_INIT_LED_MODE_MANAGER` from `LEDModeManager.h` that handles the LED mode related stuff.
Signed-off-by: Florian Fleissner <florian.fleissner@inpartik.de>
6 years ago
|
|
|
int8_t *newpg = &surface_[page_ ^ 1][0];
|
|
|
|
int8_t *oldpg = &surface_[page_][0];
|
|
|
|
|
|
|
|
// rain a bit while idle
|
|
|
|
static uint8_t frames_till_next_drop = 0;
|
|
|
|
static int8_t prev_x = -1;
|
|
|
|
static int8_t prev_y = -1;
|
|
|
|
#ifdef INTERPOLATE
|
|
|
|
// even frames: water movement and page flipping
|
|
|
|
// odd frames: raindrops and tweening
|
|
|
|
// (this arrangement seems to look best overall)
|
|
|
|
if (((now & 1)) && (idle_timeout > 0)) {
|
|
|
|
#else
|
|
|
|
if (idle_timeout > 0) {
|
|
|
|
#endif
|
|
|
|
// repeat previous raindrop to give it a slightly better effect
|
|
|
|
if (prev_x >= 0) {
|
|
|
|
raindrop(prev_x, prev_y, oldpg);
|
|
|
|
prev_x = prev_y = -1;
|
|
|
|
}
|
|
|
|
if (frames_since_event_ >= (frames_till_next_drop + (idle_timeout / MS_PER_FRAME))) {
|
|
|
|
frames_till_next_drop = 4 + (wp_rand() % FRAMES_PER_DROP);
|
|
|
|
frames_since_event_ = idle_timeout / MS_PER_FRAME;
|
|
|
|
|
|
|
|
uint8_t x = wp_rand() % WP_WID;
|
|
|
|
uint8_t y = wp_rand() % WP_HGT;
|
|
|
|
raindrop(x, y, oldpg);
|
|
|
|
|
|
|
|
prev_x = x;
|
|
|
|
prev_y = y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// calculate water movement
|
|
|
|
// (originally skipped edges, but this keyboard is too small for that)
|
|
|
|
//for (uint8_t y = 1; y < WP_HGT-1; y++) {
|
|
|
|
// for (uint8_t x = 1; x < WP_WID-1; x++) {
|
|
|
|
#ifdef INTERPOLATE
|
|
|
|
if (!(now & 1)) { // even frames only
|
|
|
|
#endif
|
|
|
|
for (uint8_t y = 0; y < WP_HGT; y++) {
|
|
|
|
for (uint8_t x = 0; x < WP_WID; x++) {
|
|
|
|
uint8_t offset = (y * WP_WID) + x;
|
|
|
|
|
|
|
|
int16_t value;
|
|
|
|
int8_t offsets[] = {
|
|
|
|
// clang-format off
|
|
|
|
-WP_WID, WP_WID,
|
|
|
|
-1, 1,
|
|
|
|
-WP_WID - 1, -WP_WID + 1,
|
|
|
|
WP_WID - 1, WP_WID + 1
|
|
|
|
// clang-format on
|
|
|
|
};
|
|
|
|
// don't wrap around edges or go out of bounds
|
|
|
|
if (y == 0) {
|
|
|
|
offsets[0] = 0;
|
|
|
|
offsets[4] += WP_WID;
|
|
|
|
offsets[5] += WP_WID;
|
|
|
|
} else if (y == WP_HGT - 1) {
|
|
|
|
offsets[1] = 0;
|
|
|
|
offsets[6] -= WP_WID;
|
|
|
|
offsets[7] -= WP_WID;
|
|
|
|
}
|
|
|
|
if (x == 0) {
|
|
|
|
offsets[2] = 0;
|
|
|
|
offsets[4] += 1;
|
|
|
|
offsets[6] += 1;
|
|
|
|
} else if (x == WP_WID - 1) {
|
|
|
|
offsets[3] = 0;
|
|
|
|
offsets[5] -= 1;
|
|
|
|
offsets[7] -= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add up all samples, divide, subtract prev frame's center
|
|
|
|
int8_t *p;
|
|
|
|
for (p = offsets, value = 0; p < offsets + 8; p++)
|
|
|
|
value += oldpg[offset + (*p)];
|
|
|
|
value = (value >> 2) - newpg[offset];
|
|
|
|
|
|
|
|
// reduce intensity gradually over time
|
|
|
|
newpg[offset] = value - (value >> 3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef INTERPOLATE
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// draw the water on the keys
|
|
|
|
for (auto key_addr : KeyAddr::all()) {
|
|
|
|
int8_t height = oldpg[pgm_read_byte(rc2pos + key_addr.toInt())];
|
|
|
|
#ifdef INTERPOLATE
|
|
|
|
if (now & 1) { // odd frames only
|
|
|
|
// average height with other frame
|
|
|
|
height = ((int16_t)height + newpg[pgm_read_byte(rc2pos + key_addr.toInt())]) >> 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
uint8_t intensity = abs(height) * 2;
|
|
|
|
uint8_t saturation = 0xff - intensity;
|
|
|
|
uint8_t value = (intensity >= 128) ? 255 : intensity << 1;
|
|
|
|
int16_t hue = ripple_hue;
|
|
|
|
|
|
|
|
if (ripple_hue == WavepoolEffect::rainbow_hue) {
|
|
|
|
// color starts white but gets dimmer and more saturated as it fades,
|
|
|
|
// with hue wobbling according to height map
|
|
|
|
hue = (current_hue + height + (height >> 1)) & 0xff;
|
|
|
|
}
|
|
|
|
|
|
|
|
cRGB color = hsvToRgb(hue, saturation, value);
|
|
|
|
|
|
|
|
::LEDControl.setCrgbAt(key_addr, color);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef INTERPOLATE
|
|
|
|
// swap pages every other frame
|
Introduced dynamic LED modes
This PR introduces the concept of dynamic LED modes. Those are LED modes whose class instances
have a restricted lifetime that lasts only as long as a LED mode is active. By this means
it is possible to support a greater amount of LED modes - especially RAM-hungry ones - in the same firmware build. The amount of RAM used to store dynamic LED modes is now bounded
by the maximum size (`sizeof(...)`) of the largest dynamic LED mode.
Old-style LED modes are furtheron called _static_ in the terminology of this PR. They are still supported and blend in nicely with the newly introduced dynamic LED modes.
All changes are entirely backward compatible. No user sketches or existing user plugins require changes.
The greatest benefit of this change is that it drastically reduces the consumption of RAM
when multiple complex LED modes are used. Currently the most complex stock LED mode is
the wavepool effect. Its plugin requires around 140 bytes of RAM that are statically allocated and cannot be shared with any other features.
With this change it becomes possible to have a large number of such resource-hungry LED modes in parallel without a significant gain in RAM consumption.
For the stock firmware this change means a small (~30 byte) growth in terms of PROGMEM. On the other hand it reduces the amount of statically consumed RAM by ~90 bytes. As the current atmel architectures come with around ten times as much PROGMEM as RAM, this means a great improvement as RAM is the more critical resource.
If the wavepool effect, a especially RAM-hungry LED mode is added to the stock firmware,
the saving of RAM increases to 160 bytes which is almost 8% of RAM of the Keyboardio Model01.
A new interface class `LEDModeInterface` was introduced that those plugins
that export dynamic LED modes inherit from. To remain backward compatible, the `LEDMode` class that all pre-existing LED mode plugins inherited from is also derived from `LEDModeInterface`.
The new interface class currently lives in header `LEDMode.h` (see information about this new header below). This is because `LEDMode` and `LEDModeInterface` will
always be used together by dynamic LED modes. Thus, an extra header for `LEDModeInterface` would only mean extra include work for users writing plugins.
Those plugins that export dynamic LED modes must furtheron provide a exported type `DynamicLEDMode`.
This can either be done by defining a nested class of that name or by typedef-ing a class that is defined at global scope to `DynamicLEDMode`. See the modified stock LED modes for examples.
Some of those plugins that export dynamic led modes require access to their particular
dynamic LED mode. By adding the macro `ACCESS_THIS_LED_MODE` to the plugin class definition,
additional data and methods (an integer `led_mode_id_) are synthesized, that enable the plugin class to gain access to their particular dynamic LED mode instance (as long as it is active).
The synthesized integer member `led_mode_id_` can be used to query if the currently active LED mode is the oned handled by the plugin class instance (note that there might be more than one plugin instance of the same class and thus also several dynamic LED modes, see e.g. the solid color LED mode).
A query in the plugin's event handler e.g. looks as follows.
```cpp
if (::LEDControl.get_mode_index() != led_mode_id_)
return EventHandlerResult::OK;
```
All stock LED modes have been adapted to export dynamic LED modes (if possible).
This does not apply to all of them as for some the transition would have provided no gain.
It would even have meant a deterioration of resource consumption for those few pre-existing stock LED mode plugins that hardly have no (static) data-members at all (like e.g. `LEDOff`).
To reduce the amount of compile unit and header interdependencies, the class `LEDMode` has been moved to a header/implementation file of its own.
The `LEDControl` class now does not have a static array anymore to store LED mode pointers.
Instead, it delegates the core LED mode handling to a newly introduced `LEDModeManager` class
that lives in internal namespace. The `LEDModeManager` class is there to restrict access
to LED modes but also to wrap up core LED mode handling. If this functionality would
have been added to class `LEDControl`, far too much of the internals of LED mode handling would have been exposed to users through header `LEDControl.h`.
The new internal header `array_like_storage.h` contains a template class that is used to generate
array-like storages. Here array-like means that the contained pieces of information
are stored contiguously in memory in the same way as they would be when defining
language intrinsic (C-style) arrays. This type of storage is especially useful to generate array-like data struktures
in PROGMEM at compile time based on a list of global objects or POD data. By casting the array-like storage's address
to the content's pointer type, an array-like indexed access is possible.
In this PR an array-like data structure is used to generate a PROGMEM
array of LED mode factories. Array-like data structures could also become useful in other places and for future applications.
The most complex part of the implementation of the new LED mode handling is wrapped up in
`LEDModeManager.h` and `LEDModeManager.cpp` to hide it from users' site.
There, recursive template classes are used to setup an array-like data structure of `LEDModeFactory` instances in PROGMEM. Each of the stored `LEDModeFactory`s are associated with one LED mode-plugin as specified in the sketch. The template mechanism filters out any other plugins unrelated to LED modes. `LEDModeFactory`s thereby handle both static and dynamic LED modes.
Class `LEDModeManager` provides access to the LED mode factories and LED modes in general. It exports methods to query the number of LED modes and to activate a LED mode by its mode-ID. Most of this is only available to `LEDControl` that represents the actual user interface.
When a dynamic LED mode is activated, a dedicated `LEDModeFactory` generates an instance of the dynamic LED mode class in the
LED mode buffer. This buffer is shared by all dynamic LED modes. Its size has been determined at compile time by examining all exported dynamic LED mode types and determining the maximum necessary amount of RAM to store any of those.
All LED mode handling related data structures are generated at compile time, based on
the list of plugins that are passed to `KALEIDOSCOPE_INIT_PLUGINS(...)`. This function macro invokes a new function macro `_INIT_LED_MODE_MANAGER` from `LEDModeManager.h` that handles the LED mode related stuff.
Signed-off-by: Florian Fleissner <florian.fleissner@inpartik.de>
6 years ago
|
|
|
if (!(now & 1)) page_ ^= 1;
|
|
|
|
#else
|
|
|
|
// swap pages every frame
|
Introduced dynamic LED modes
This PR introduces the concept of dynamic LED modes. Those are LED modes whose class instances
have a restricted lifetime that lasts only as long as a LED mode is active. By this means
it is possible to support a greater amount of LED modes - especially RAM-hungry ones - in the same firmware build. The amount of RAM used to store dynamic LED modes is now bounded
by the maximum size (`sizeof(...)`) of the largest dynamic LED mode.
Old-style LED modes are furtheron called _static_ in the terminology of this PR. They are still supported and blend in nicely with the newly introduced dynamic LED modes.
All changes are entirely backward compatible. No user sketches or existing user plugins require changes.
The greatest benefit of this change is that it drastically reduces the consumption of RAM
when multiple complex LED modes are used. Currently the most complex stock LED mode is
the wavepool effect. Its plugin requires around 140 bytes of RAM that are statically allocated and cannot be shared with any other features.
With this change it becomes possible to have a large number of such resource-hungry LED modes in parallel without a significant gain in RAM consumption.
For the stock firmware this change means a small (~30 byte) growth in terms of PROGMEM. On the other hand it reduces the amount of statically consumed RAM by ~90 bytes. As the current atmel architectures come with around ten times as much PROGMEM as RAM, this means a great improvement as RAM is the more critical resource.
If the wavepool effect, a especially RAM-hungry LED mode is added to the stock firmware,
the saving of RAM increases to 160 bytes which is almost 8% of RAM of the Keyboardio Model01.
A new interface class `LEDModeInterface` was introduced that those plugins
that export dynamic LED modes inherit from. To remain backward compatible, the `LEDMode` class that all pre-existing LED mode plugins inherited from is also derived from `LEDModeInterface`.
The new interface class currently lives in header `LEDMode.h` (see information about this new header below). This is because `LEDMode` and `LEDModeInterface` will
always be used together by dynamic LED modes. Thus, an extra header for `LEDModeInterface` would only mean extra include work for users writing plugins.
Those plugins that export dynamic LED modes must furtheron provide a exported type `DynamicLEDMode`.
This can either be done by defining a nested class of that name or by typedef-ing a class that is defined at global scope to `DynamicLEDMode`. See the modified stock LED modes for examples.
Some of those plugins that export dynamic led modes require access to their particular
dynamic LED mode. By adding the macro `ACCESS_THIS_LED_MODE` to the plugin class definition,
additional data and methods (an integer `led_mode_id_) are synthesized, that enable the plugin class to gain access to their particular dynamic LED mode instance (as long as it is active).
The synthesized integer member `led_mode_id_` can be used to query if the currently active LED mode is the oned handled by the plugin class instance (note that there might be more than one plugin instance of the same class and thus also several dynamic LED modes, see e.g. the solid color LED mode).
A query in the plugin's event handler e.g. looks as follows.
```cpp
if (::LEDControl.get_mode_index() != led_mode_id_)
return EventHandlerResult::OK;
```
All stock LED modes have been adapted to export dynamic LED modes (if possible).
This does not apply to all of them as for some the transition would have provided no gain.
It would even have meant a deterioration of resource consumption for those few pre-existing stock LED mode plugins that hardly have no (static) data-members at all (like e.g. `LEDOff`).
To reduce the amount of compile unit and header interdependencies, the class `LEDMode` has been moved to a header/implementation file of its own.
The `LEDControl` class now does not have a static array anymore to store LED mode pointers.
Instead, it delegates the core LED mode handling to a newly introduced `LEDModeManager` class
that lives in internal namespace. The `LEDModeManager` class is there to restrict access
to LED modes but also to wrap up core LED mode handling. If this functionality would
have been added to class `LEDControl`, far too much of the internals of LED mode handling would have been exposed to users through header `LEDControl.h`.
The new internal header `array_like_storage.h` contains a template class that is used to generate
array-like storages. Here array-like means that the contained pieces of information
are stored contiguously in memory in the same way as they would be when defining
language intrinsic (C-style) arrays. This type of storage is especially useful to generate array-like data struktures
in PROGMEM at compile time based on a list of global objects or POD data. By casting the array-like storage's address
to the content's pointer type, an array-like indexed access is possible.
In this PR an array-like data structure is used to generate a PROGMEM
array of LED mode factories. Array-like data structures could also become useful in other places and for future applications.
The most complex part of the implementation of the new LED mode handling is wrapped up in
`LEDModeManager.h` and `LEDModeManager.cpp` to hide it from users' site.
There, recursive template classes are used to setup an array-like data structure of `LEDModeFactory` instances in PROGMEM. Each of the stored `LEDModeFactory`s are associated with one LED mode-plugin as specified in the sketch. The template mechanism filters out any other plugins unrelated to LED modes. `LEDModeFactory`s thereby handle both static and dynamic LED modes.
Class `LEDModeManager` provides access to the LED mode factories and LED modes in general. It exports methods to query the number of LED modes and to activate a LED mode by its mode-ID. Most of this is only available to `LEDControl` that represents the actual user interface.
When a dynamic LED mode is activated, a dedicated `LEDModeFactory` generates an instance of the dynamic LED mode class in the
LED mode buffer. This buffer is shared by all dynamic LED modes. Its size has been determined at compile time by examining all exported dynamic LED mode types and determining the maximum necessary amount of RAM to store any of those.
All LED mode handling related data structures are generated at compile time, based on
the list of plugins that are passed to `KALEIDOSCOPE_INIT_PLUGINS(...)`. This function macro invokes a new function macro `_INIT_LED_MODE_MANAGER` from `LEDModeManager.h` that handles the LED mode related stuff.
Signed-off-by: Florian Fleissner <florian.fleissner@inpartik.de>
6 years ago
|
|
|
page_ ^= 1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
Standardize namespace block closing comments
This standardizes namespace closing brackets for namespace blocks. Each one is
on its own line, with a comment clearly marking which namespace it closes.
Consecutive lines closing namespace blocks have no whitespace between them, but
there is one blank line before and after a set of namespace block closing lines.
To generate the namespace comments, I used clang-format, with
`FixNamespaceComments: true`. But since clang-format can't exactly duplicate
our astyle formatting, it made lots of other changes, too. To isolate the
namespace comments from the other formatting changes, I first ran clang-format
with `FixNamespaceComments: false`, committed those changes, then ran it again
to generate the namespace comments. Then I stashed the namespace comments,
reset `HEAD` to remove the other changes, applied the stashed namespace
comments, and committed the results (after examining them and making a few minor
adjustments by hand).
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
3 years ago
|
|
|
} // namespace plugin
|
|
|
|
} // namespace kaleidoscope
|
|
|
|
|
|
|
|
kaleidoscope::plugin::WavepoolEffect WavepoolEffect;
|
|
|
|
|
|
|
|
#endif
|