From e59a09e19e914b0c172544900aff5d22a927c0a3 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sun, 29 May 2022 02:48:10 +0200 Subject: [PATCH] Colormap: Add a new (optional) plugin: DefaultColormap This new plugin lets us store a default palette and colormap in PROGMEM. Rather than teaching Colormap to pull from either EEPROM or PROGMEM, this implements an entirely separate plugin, `DefaultColormap`, which is able to *push* a palette and colormaps into Colormap. When `DefaultColormap.setup()` is called, it checks if Colormap's storage area is empty (both palette and the map must be empty), and if so, copies the built-in palette and colormap over, and forces a refresh, and it has done its job. It does provide an additional Focus command too, `colormap.install`, which will forcibly copy both palette and colormaps over. Useful for resetting back to a factory setting. Signed-off-by: Gergely Nagy --- plugins/Kaleidoscope-Colormap/README.md | 53 +++++++++- .../src/Kaleidoscope-Colormap.h | 5 +- .../src/kaleidoscope/plugin/Colormap.cpp | 13 ++- .../src/kaleidoscope/plugin/Colormap.h | 5 +- .../kaleidoscope/plugin/DefaultColormap.cpp | 94 ++++++++++++++++++ .../src/kaleidoscope/plugin/DefaultColormap.h | 98 +++++++++++++++++++ 6 files changed, 263 insertions(+), 5 deletions(-) create mode 100644 plugins/Kaleidoscope-Colormap/src/kaleidoscope/plugin/DefaultColormap.cpp create mode 100644 plugins/Kaleidoscope-Colormap/src/kaleidoscope/plugin/DefaultColormap.h diff --git a/plugins/Kaleidoscope-Colormap/README.md b/plugins/Kaleidoscope-Colormap/README.md index f5a438f9..30ea3605 100644 --- a/plugins/Kaleidoscope-Colormap/README.md +++ b/plugins/Kaleidoscope-Colormap/README.md @@ -11,30 +11,60 @@ plugin, which also provides palette editing capabilities. [plugin:focusserial]: Kaleidoscope-FocusSerial.md [plugin:l-p-t]: Kaleidoscope-LED-Palette-Theme.md +It is also possible to set up a default palette and colormap, using the +`DefaultColormap` plugin, also provided by this package. See below for its +documentation. + ## Using the extension To use the extension, include the header, tell it the number of layers you have, -register the `Focus` hooks, and it will do the rest. +register the `Focus` hooks, and it will do the rest. We'll also set up a default +for both the palette, and the colormap. ```c++ #include #include +#include #include #include #include KALEIDOSCOPE_INIT_PLUGINS(EEPROMSettings, + LEDControl, LEDPaletteTheme, ColormapEffect, + DefaultColormap, Focus); +PALETTE( + /* A list of 16 cRGB colors... */ +) + +COLORMAPS( + [0] = COLORMAP( + // List of palette indexes for each key, using the same layout + // as the `KEYMAP` macro does for keys. + ), + [1] = COLORMAP_STACKED( + // List of palette indexes for each key, using the same layout + // as the `KEYMAP_STACKED` macro does for keys. + ) +) + void setup() { Kaleidoscope.setup(); ColormapEffect.max_layers(1); + DefaultColormap.setup(); } ``` +The `PALETTE` and `COLORMAPS` macros are only used for the `DefaultColormap` +plugin, `ColormapEffect` itself makes no use of them. The `PALETTE` must always +contain a full 16-color palette. `COLORMAPS` can define colormaps for as many +layers as one wishes, but the `DefaultColormap` plugin will only copy over as +many as `ColormapEffect` is configured to support. + ## Plugin methods The extension provides an `ColormapEffect` singleton object, with a single method: @@ -44,6 +74,19 @@ The extension provides an `ColormapEffect` singleton object, with a single metho > Tells the extension to reserve space in EEPROM for up to `max` layers. Can > only be called once, any subsequent call will be a no-op. +Also provided is an optional `DefaultColormap` plugin, with two methods: + +### `.setup()` + +> Intended to be called from the `setup()` method of the sketch, it checks if +> the `ColormapEffect` plugin is initialized, and if not, then copies the +> palette and the colormap over from the firmware to EEPROM. + +### `.install()` + +> Same as `.setup()` above, but without the initialized check. Intended to be +> used when one wants to restore the colormap to factory settings. + ## Focus commands ### `colormap.map` @@ -55,6 +98,14 @@ The extension provides an `ColormapEffect` singleton object, with a single metho > ignore anything past the last key on the last layer (as set by the > `.max_layers()` method). +If the `DefaultColormap` plugin is also in use, an additional focus command is +made available: + +### `colormap.install` + +> Copies the default colormap and palette built into the firmware into EEPROM, +> effectively performing a factory reset for both. + ## Dependencies * [Kaleidoscope-EEPROM-Settings](Kaleidoscope-EEPROM-Settings.md) diff --git a/plugins/Kaleidoscope-Colormap/src/Kaleidoscope-Colormap.h b/plugins/Kaleidoscope-Colormap/src/Kaleidoscope-Colormap.h index 994d288d..b06e1e43 100644 --- a/plugins/Kaleidoscope-Colormap/src/Kaleidoscope-Colormap.h +++ b/plugins/Kaleidoscope-Colormap/src/Kaleidoscope-Colormap.h @@ -1,6 +1,6 @@ /* -*- mode: c++ -*- * Kaleidoscope-Colormap -- Per-layer colormap effect - * Copyright (C) 2016, 2017 Keyboard.io, Inc + * Copyright (C) 2016-2022 Keyboard.io, Inc * * This program is free software: you can redistribute it and/or modify it under it under * the terms of the GNU General Public License as published by the Free Software @@ -17,4 +17,5 @@ #pragma once -#include "kaleidoscope/plugin/Colormap.h" // IWYU pragma: export +#include "kaleidoscope/plugin/Colormap.h" // IWYU pragma: export +#include "kaleidoscope/plugin/DefaultColormap.h" // IWYU pragma: export diff --git a/plugins/Kaleidoscope-Colormap/src/kaleidoscope/plugin/Colormap.cpp b/plugins/Kaleidoscope-Colormap/src/kaleidoscope/plugin/Colormap.cpp index 371614d7..ad20194e 100644 --- a/plugins/Kaleidoscope-Colormap/src/kaleidoscope/plugin/Colormap.cpp +++ b/plugins/Kaleidoscope-Colormap/src/kaleidoscope/plugin/Colormap.cpp @@ -1,6 +1,6 @@ /* -*- mode: c++ -*- * Kaleidoscope-Colormap -- Per-layer colormap effect - * Copyright (C) 2016, 2017, 2018, 2021 Keyboard.io, Inc + * Copyright (C) 2016-2022 Keyboard.io, Inc * * This program is free software: you can redistribute it and/or modify it under it under * the terms of the GNU General Public License as published by the Free Software @@ -47,6 +47,17 @@ EventHandlerResult ColormapEffect::onNameQuery() { return ::Focus.sendName(F("ColormapEffect")); } +bool ColormapEffect::isUninitialized() { + return ::LEDPaletteTheme.isThemeUninitialized(map_base_, max_layers_); +} + +void ColormapEffect::updateColorIndexAtPosition(uint8_t layer, uint16_t position, uint8_t palette_index) { + if (layer >= max_layers_) return; + + uint16_t index = Runtime.device().led_count * layer + position; + ::LEDPaletteTheme.updateColorIndexAtPosition(map_base_, index, palette_index); +} + void ColormapEffect::TransientLEDMode::onActivate() { if (!Runtime.has_leds) return; diff --git a/plugins/Kaleidoscope-Colormap/src/kaleidoscope/plugin/Colormap.h b/plugins/Kaleidoscope-Colormap/src/kaleidoscope/plugin/Colormap.h index 76583519..3a9403ed 100644 --- a/plugins/Kaleidoscope-Colormap/src/kaleidoscope/plugin/Colormap.h +++ b/plugins/Kaleidoscope-Colormap/src/kaleidoscope/plugin/Colormap.h @@ -1,6 +1,6 @@ /* -*- mode: c++ -*- * Kaleidoscope-Colormap -- Per-layer colormap effect - * Copyright (C) 2016, 2017, 2018, 2021 Keyboard.io, Inc + * Copyright (C) 2016-2022 Keyboard.io, Inc * * This program is free software: you can redistribute it and/or modify it under it under * the terms of the GNU General Public License as published by the Free Software @@ -38,6 +38,9 @@ class ColormapEffect : public Plugin, EventHandlerResult onNameQuery(); EventHandlerResult onFocusEvent(const char *command); + static bool isUninitialized(); + static void updateColorIndexAtPosition(uint8_t layer, uint16_t position, uint8_t palette_index); + // This class' instance has dynamic lifetime // class TransientLEDMode : public LEDMode { diff --git a/plugins/Kaleidoscope-Colormap/src/kaleidoscope/plugin/DefaultColormap.cpp b/plugins/Kaleidoscope-Colormap/src/kaleidoscope/plugin/DefaultColormap.cpp new file mode 100644 index 00000000..e0eb7f35 --- /dev/null +++ b/plugins/Kaleidoscope-Colormap/src/kaleidoscope/plugin/DefaultColormap.cpp @@ -0,0 +1,94 @@ +/* -*- mode: c++ -*- + * Kaleidoscope-Colormap -- Per-layer colormap effect + * Copyright (C) 2022 Keyboard.io, Inc + * + * This program is free software: you can redistribute it and/or modify it under it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but WITHOUT 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 along with + * this program. If not, see . + */ + +#include "kaleidoscope/plugin/Colormap.h" // for Colormap +#include "kaleidoscope/plugin/DefaultColormap.h" + +#include // for F, PSTR, __FlashStringHelper +#include // for Focus, FocusSerial +#include // for LEDControl +#include // for LEDPaletteTheme +#include // for uint8_t, uint16_t + +#include "kaleidoscope/KeyAddr.h" // for KeyAddr +#include "kaleidoscope/Runtime.h" // for Runtime, Runtime_ + +namespace kaleidoscope { +namespace plugin { + +namespace defaultcolormap { +__attribute__((weak)) extern const cRGB palette[] = {}; +__attribute__((weak)) extern bool palette_defined = false; +__attribute__((weak)) extern const uint8_t colormaps[][kaleidoscope_internal::device.matrix_rows * kaleidoscope_internal::device.matrix_columns] = {}; +__attribute__((weak)) extern uint8_t colormap_layers = 0; +} // namespace defaultcolormap + +void DefaultColormap::setup() { + // If the colormap is already initialized, return early. + if (!::ColormapEffect.isUninitialized()) + return; + + install(); +} + +void DefaultColormap::install() { + if (!defaultcolormap::palette_defined) return; + + for (uint8_t i = 0; i < 16; i++) { + cRGB color; + + color.r = pgm_read_byte(&(defaultcolormap::palette[i].r)); + color.g = pgm_read_byte(&(defaultcolormap::palette[i].g)); + color.b = pgm_read_byte(&(defaultcolormap::palette[i].b)); + + ::LEDPaletteTheme.updatePaletteColor(i, color); + } + + if (defaultcolormap::colormap_layers == 0) return; + + for (uint8_t layer = 0; layer < defaultcolormap::colormap_layers; layer++) { + for (int8_t i = 0; i < Runtime.device().numKeys(); i++) { + const int8_t post = Runtime.device().ledDriver().getLedIndex(i); + const uint8_t idx = pgm_read_byte(&(defaultcolormap::colormaps[layer][i])); + ::ColormapEffect.updateColorIndexAtPosition(layer, post, idx); + } + } + Runtime.storage().commit(); + + ::LEDControl.refreshAll(); +} + +EventHandlerResult DefaultColormap::onFocusEvent(const char *command) { + if (!Runtime.has_leds) + return EventHandlerResult::OK; + + const char *cmd = PSTR("colormap.install"); + + if (::Focus.handleHelp(command, cmd)) + return EventHandlerResult::OK; + + if (strcmp_P(command, cmd) != 0) + return EventHandlerResult::OK; + + install(); + return EventHandlerResult::EVENT_CONSUMED; +} + +} // namespace plugin +} // namespace kaleidoscope + +kaleidoscope::plugin::DefaultColormap DefaultColormap; diff --git a/plugins/Kaleidoscope-Colormap/src/kaleidoscope/plugin/DefaultColormap.h b/plugins/Kaleidoscope-Colormap/src/kaleidoscope/plugin/DefaultColormap.h new file mode 100644 index 00000000..315224ce --- /dev/null +++ b/plugins/Kaleidoscope-Colormap/src/kaleidoscope/plugin/DefaultColormap.h @@ -0,0 +1,98 @@ +/* -*- mode: c++ -*- + * Kaleidoscope-Colormap -- Per-layer colormap effect + * Copyright (C) 2022 Keyboard.io, Inc + * + * This program is free software: you can redistribute it and/or modify it under it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but WITHOUT 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 along with + * this program. If not, see . + */ + +#pragma once + +#include // for PROGMEM +#include // for uint8_t + +#include "kaleidoscope_internal/device.h" // for device +#include "kaleidoscope/device/device.h" // for cRGB +#include "kaleidoscope/event_handler_result.h" // for EventHandlerResult +#include "kaleidoscope/plugin.h" // for Plugin + +namespace kaleidoscope { +namespace plugin { + +// clang-format off + +#define COLORMAPS(layers...) \ + namespace kaleidoscope { \ + namespace plugin { \ + namespace defaultcolormap { \ + const uint8_t colormaps[][kaleidoscope_internal::device.matrix_rows * kaleidoscope_internal::device.matrix_columns] PROGMEM = { \ + layers \ + }; \ + uint8_t colormap_layers = \ + sizeof(colormaps) / sizeof(*colormaps); \ + } /* defaultcolormap */ \ + } /* plugin */ \ + } /* kaleidoscope */ + +#define __IDENTITY__(X) X + +#ifdef PER_KEY_DATA_STACKED +#define COLORMAP_STACKED(...) \ + { \ + MAP_LIST(__IDENTITY__, PER_KEY_DATA_STACKED(0, __VA_ARGS__)) \ + } +#endif + +#ifdef PER_KEY_DATA +#define COLORMAP(...) \ + { \ + MAP_LIST(__IDENTITY__, PER_KEY_DATA(0, __VA_ARGS__)) \ + } +#endif + +#define PALETTE(p0, p1, p2, p3, p4, p5, p6, p7, \ + p8, p9, pa, pb, pc, pd, pe, pf) \ + namespace kaleidoscope { \ + namespace plugin { \ + namespace defaultcolormap { \ + const cRGB palette[] PROGMEM = { \ + p0, p1, p2, p3, p4, p5, p6, p7, \ + p8, p9, pa, pb, pc, pd, pe, pf \ + }; \ + bool palette_defined = true; \ + } /* defaultcolormap */ \ + } /* plugin */ \ + } /* kaleidoscope */ + +// clang-format on + +namespace defaultcolormap { +extern bool palette_defined; +extern const cRGB palette[]; +extern const uint8_t colormaps[][kaleidoscope_internal::device.matrix_rows * kaleidoscope_internal::device.matrix_columns]; +extern uint8_t colormap_layers; +} // namespace defaultcolormap + +class DefaultColormap : public Plugin { + public: + static void setup(); + + EventHandlerResult onFocusEvent(const char *command); + + private: + static void install(); +}; + +} // namespace plugin +} // namespace kaleidoscope + +extern kaleidoscope::plugin::DefaultColormap DefaultColormap;