-
-
Notifications
You must be signed in to change notification settings - Fork 40k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RGB Matrix: Custom effects on a kb/user level #5338
Conversation
63376e0
to
f518e06
Compare
if possible, could you add documentation for this, as well as an example of how to utilize this? |
Due to the in-flux nature of the interface, I was going to write the Docs once the implementation was settled-on. There is a brief example in the PR's body though, if you want to play around with it yourself. |
I think it would be great if both rgb matrix and rgb underglow had more commonality in terms of how the user specifies which modes they want enabled in their firmware. Underglow is via defines which lets you disable those you aren't interested in but currently has no mechanism to add user modes, so something like this would be useful there. Does this PR let you disable preexisting modes you don't like? (And ideally reclaim the firmware space) |
Not a huge fan of const uint8_t rgb_matrix_effects_kb_count;
const uint8_t rgb_matrix_effects_user_count; is there some way to look at size of array at compile time and avoid the manual book keeping? |
@Lenbok I agree, but I don't think those changes fall under the scope of this PR. @yanfali I agree, it's not great, but unfortunately, the size of arrays can't be easily reconstructed in another compilation unit when using weakly-linked symbols. Some sort of count has to be manually maintained. One potential alternative to get around this is to introduce a helper macro, something like the following: #define EXPORT_RGB_MATRIX_EFFECTS_USER(...) \
const rgb_matrix_effect_f rgb_matrix_effects_user[] = { __VA_ARGS__ }; \
const uint8_t rgb_matrix_effects_user_count = sizeof(rgb_matrix_effects_user)/sizeof(rgb_matrix_effects_user[0]);
// same thing for KB
// usage (in keymap.c):
static void my_kool_effect(bool init) {}
static void my_kool_effect2(bool init) {}
EXPORT_RGB_MATRIX_EFFECTS_USER(
my_kool_effect,
my_kool_effect2
); Thoughts on this Macro based approach? |
@daniel5151 if it's less error prone for users I think it's probably worth considering. Managing a count for something that you've already defined just seems like a recipe for people coming to the discord help channel. |
So I applied this function pointer approach to rgb_matrix (branch here) as a test and here's my notes
I wonder if an approach similar to keycodes are handled might not be a safer & smaller solution. ex: |
Just to clarify something though, this PR isn't aiming to do a full function-pointer conversion. Moreover, I'd just like to stress that this PR doesn't bloat the firmware size, given that it merely adds a couple of hooks, exports a couple of symbols, and tweaks some statements here and there. |
So I think the PR implementation is great, and want to approve it, but I think it is worth discussing the pros and cons a bit more and the limitations or issues of this approach is all.
I'm going to look at the assembly and see what the hell caused that size increase, cause that is just crazy. |
I've gone ahead an added in the helper macros as discussed above, along with some OOB checks that should prevent any nastiness when removing custom effects on boards with EEPROM. I've added docs on how to define custom effects, and also updated the PR's description to reflect the new recommended usage. There hasn't been too much pushback on this current design (weakly-linked array+len with bookkeeping macros), so I think we can push forward with it. |
Will be looking at the size increase a bit more this weekend, but wanted to follow back up before then with a request for a small api change on the function pointer: typedef bool (*rgb_matrix_effect_f)(bool init, uint8_t iter); This api change is needed to allow for rendering of a single frame over several update ticks. The animation function returns true if it needs to do more work, false if not. iter is a count of how many times it has been called while it still needed more work to be done. This allows us to break up calculating the led data over several ticks instead of all at once potentially causing scanning delays. |
SGTM. Could you give an example of how this should be used in the custom effect fn + how the the effects should be called from rgb_matrix.c? I'll update the API + docs accordingly. |
I still need to verify some ideas around this, task to do this weekend, but here's an example: bool rgb_matrix_solid_splash(bool init, uint8_t iter) {
// solid_splash is expensive, we know it ranges from 4ms to 10ms
// so we want it to iterate 2 to 5 times based on the number of items we are tracking
// So setup the range we need to operate over
uint8_t count = 2 + (g_last_hit_tracker.count + 3 - 1) / 3;
uint8_t led_count = (DRIVER_LED_TOTAL + count - 1) / count;
uint8_t led_min = led_count * iter;
uint8_t led_max = led_min + led_count;
if (led_max > DRIVER_LED_TOTAL)
led_max = DRIVER_LED_TOTAL;
for (uint8_t i = led_min; i < led_max; i++) {
// Do work on this led range
}
return led_max < DRIVER_LED_TOTAL;
} The idea is that the animation time slices itself base on it's own knowledge of it's performance characteristics at the time of being called. It will do work each tick until it is complete, and once it is complete, the buffers (rgb_config_t, ticks, etc) that drive the animations will then be updated via a memcpy from an internal double buffer. Most of this loop setup can be extracted out into a utility function with the correct parameters for easier use in custom animations. So that way an animation like solid can just run normally without doing anything special, but the heavier ones can be designed in a way that lets them scale. |
Ah, gotcha. My one concern would be the feature-creep that this change entails. I don't think this PR should be the one to implement the (what I assume to be) non-trivial logic to support the returned I don't mind changing the fn signature as a future-proofing measure for once your RGB Matrix overhaul PR lands, though I think it might be best to stub-out the extended functionality this modified API suggests, and add a note that the Thoughts? |
Ya, I was thinking the same. Stub it out until a future PR lands with the work. I don't think my matrix refactor will contain this work either as it's already fairly long too. But I do want to use that refactor as a base for this timeslice implementation |
@daniel5151 Here's the final implementation I ended up with: |
@drashna status update on potentially getting this merged? The interface has been agreed upon and stabilized, and the docs have been updated accordingly 😄 |
I'm waiting on other people to approve the changes here, actually. |
@daniel5151 mind updating the API one more time: typedef struct {
uint8_t iter;
uint8_t flags;
bool init; // debating on if this should be rolled into flags
} effect_params_t;
typedef bool (*rgb_matrix_effect_f)(effect_params_t* params); The idea behind this change is so that, one, we can update animation parameters as needed without changing a bunch of code, and two, the additional flags parameter will go a long ways to allowing different animations running on different sets of LEDs. For example, using flags I can mask out LEDs to have breathing effect on modifiers, cycle left to right on underglow, and reactive on the remainder. I'll be stubbing it out in the rgb overhaul pr later tonight. |
I was thinking about that single-macro approach, and while slick, I thought it was a bit too magical. I've gone ahead and pushed what I think is a good compromise between compactness and readability. I'll copy-paste the relevant excerpt from the updated docs here: By setting To declare new effects, create a new // !!! DO NOT ADD #pragma once !!! //
// Step 1.
// Declare custom effects using the RGB_MATRIX_EFFECT macro
// (note the lack of semicolon after the macro!)
RGB_MATRIX_EFFECT(my_cool_effect)
RGB_MATRIX_EFFECT(my_cool_effect2)
// Step 2.
// Define effects inside the `RGB_MATRIX_CUSTOM_EFFECT_IMPLS` ifdef block
#ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS
// e.g: A simple effect, self-contained within a single method
static bool my_cool_effect(effect_params_t* params) {
RGB_MATRIX_USE_LIMITS(led_min, led_max);
for (uint8_t i = led_min; i < led_max; i++) {
rgb_matrix_set_color(i, 0xff, 0xff, 0x00);
}
return led_max < DRIVER_LED_TOTAL;
}
// e.g: A more complex effect, relying on external methods and state, with
// dedicated init and run methods
static uint8_t some_global_state;
static void my_cool_effect2_complex_init(effect_params_t* params) {
some_global_state = 1;
}
static bool my_cool_effect2_complex_run(effect_params_t* params) {
RGB_MATRIX_USE_LIMITS(led_min, led_max);
for (uint8_t i = led_min; i < led_max; i++) {
rgb_matrix_set_color(i, 0xff, some_global_state++, 0xff);
}
return led_max < DRIVER_LED_TOTAL;
}
static bool my_cool_effect2(effect_params_t* params) {
if (params->init) my_cool_effect2_complex_init(params);
return my_cool_effect2_complex_run(params);
}
#endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS |
See docs for example usage
c9b10e5
to
ced4c96
Compare
Looking good! |
Well, one concern I have: To make sure, the From the documentation, it's not exactly clear (or I am an idiot and completely missed it) |
As long as I can update the documentation to make that more clear. |
Override default effect using RGB_MATRIX_STARTUP_MODE. Useful on boards without EEPROM support (*cough* Massdrop ALT/CTRL *cough*)
Heyo, any updates? Also, I think we can remove the needs-docs tag 😄 |
@drashna anything left before merging this pr? |
Awesome! Great work everyone! Hopefully we'll see some pretty interesting new lighting effects popping up in user-space now 😄 |
* upstream/master: (779 commits) [Keyboard] Signum3.0 remove sortedcontainers (qmk#5679) Simple extended space cadet (qmk#5277) Removed forced in lining for lib8tion functions (qmk#5670) Change lib8tion library to be usable in user keymaps (qmk#5598) [Keyboard] Fixing drag-and-drop (qmk#5728) [Keyboard] Adding ortho_4x12 & planck_mit layouts for KBD4X (qmk#5729) [Keyboard] Minor fixes for Baguette (qmk#5737) Updated rgb_led struct field modifier to flags (qmk#5619) RGB Matrix: Custom effects on a kb/user level (qmk#5338) Fix Planck and Preonic builds (qmk#5658) [Keymap] dz60 keymap w/ hhkb-esque default layer (qmk#5708) [Keymap] Added compatibility for Planck rev6 (qmk#5706) [Keyboard] Satisfaction75 i2c fix and VIA layout (qmk#5726) A better new_project.sh (qmk#5191) Fix sendstring "#" producing "£" instead (qmk#5724) [Keyboard] Added WT69-A PCB (qmk#5721) [Keymap] Fix typo and function layer image for Quefrency (qmk#5719) [Keymap] Initial keyboard layout for KBD67 (qmk#5720) [Keymap] New keymap for Quefrency 65% with split backspace, RGB, media keys, mouse keys (qmk#5717) [Keyboard] Update Gergo to use newer Ergodox Matrix code (qmk#5703) ...
* Revamped custom effects approach See docs for example usage * push-up RGB Matrix default mode Override default effect using RGB_MATRIX_STARTUP_MODE. Useful on boards without EEPROM support (*cough* Massdrop ALT/CTRL *cough*) * update docs
* Revamped custom effects approach See docs for example usage * push-up RGB Matrix default mode Override default effect using RGB_MATRIX_STARTUP_MODE. Useful on boards without EEPROM support (*cough* Massdrop ALT/CTRL *cough*) * update docs
* Revamped custom effects approach See docs for example usage * push-up RGB Matrix default mode Override default effect using RGB_MATRIX_STARTUP_MODE. Useful on boards without EEPROM support (*cough* Massdrop ALT/CTRL *cough*) * update docs
* Revamped custom effects approach See docs for example usage * push-up RGB Matrix default mode Override default effect using RGB_MATRIX_STARTUP_MODE. Useful on boards without EEPROM support (*cough* Massdrop ALT/CTRL *cough*) * update docs
* Revamped custom effects approach See docs for example usage * push-up RGB Matrix default mode Override default effect using RGB_MATRIX_STARTUP_MODE. Useful on boards without EEPROM support (*cough* Massdrop ALT/CTRL *cough*) * update docs
The current method of creating custom RGB Matrix lighting effects from kb/user is by calling
rgb_matrix_set_color
from methods such asprocess_kb/user
,matrix_scan_kb/user
, orrgb_matrix_indicators_kb/user
. While this works fine for overriding a few LEDs here-and-there (to indicate caps-lock, or indicating the current layer), it's quite inefficient when overriding all LEDs, since RGB Matrix is still running it's own effects in the background.This PR introduces a cleaner, more unobtrusive way to extend the RGB Matrix system, adding new effects and having them act just like built in ones (i.e: accessed through RGB_TOG)
Description
See discussion below and updated docs for usage info.
Types of Changes
Issues Fixed or Closed by This PR
Checklist