Skip to content
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

Add focus command for retreiving a list of installed LED effects #1387

Merged
merged 51 commits into from
Mar 13, 2024

Conversation

EvyBongers
Copy link
Contributor

No description provided.

Copy link
Contributor Author

@EvyBongers EvyBongers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a side note, I noticed that there are several plugins that don't implement onNameQuery. Is that something to be fixed sometime, or is there a specific use case where that's needed for certain plugins?

@EvyBongers EvyBongers force-pushed the feat/LedEffectNames branch 2 times, most recently from c23d593 to d70a15b Compare February 13, 2024 20:16
@obra
Copy link
Member

obra commented Feb 13, 2024

On a side note, I noticed that there are several plugins that don't implement onNameQuery. Is that something to be fixed sometime, or is there a specific use case where that's needed for certain plugins?

I wanted the answer to be "check event-handler-hooks.md". So I made that true: https://github.com/keyboardio/Kaleidoscope/blob/master/docs/api-reference/event-handler-hooks.md#onnamequery

@EvyBongers
Copy link
Contributor Author

On a side note, I noticed that there are several plugins that don't implement onNameQuery. Is that something to be fixed sometime, or is there a specific use case where that's needed for certain plugins?

I wanted the answer to be "check event-handler-hooks.md". So I made that true: https://github.com/keyboardio/Kaleidoscope/blob/master/docs/api-reference/event-handler-hooks.md#onnamequery

I had that change ready to be committed 😅 Doesn't change that I can't tell in what scenarios it is or isn't important for the know to know about it. I'll leave that up to you

@EvyBongers
Copy link
Contributor Author

The basics are implemented in all LED mode plugins.

Example output using the M100 example sketch:

$ ../_firmware/kaleidoscope/bin/focus-send led_effects
LEDRainbowEffect
LEDChaseEffect
SolidColor
SolidColor
SolidColor
SolidColor
SolidColor
SolidColor
SolidColor
LEDBreatheEffect
AlphaSquareEffect
StalkerEffect
ColormapEffect

For the plugin to be useful for displaying LED effect names in Chrysalis, some configuration options might need to be included, for the SolidColor plugin for example.

@obra
Copy link
Member

obra commented Feb 13, 2024

Nice! It does seem like it makes sense to be able to (optionally) specify an additional string for at least the SolidColor LED effect. I wonder if it's worth implementing something in the base class to let the user pass in a descriptive string in the constructor or with another method call and then having the base class able to respond with that in preference to the hardcoded name.

Given that, it might make sense to refactor onNameQuery into the base class and to pull the name from a string baked into the plugin so we can reuse it for this

@EvyBongers
Copy link
Contributor Author

Nice! It does seem like it makes sense to be able to (optionally) specify an additional string for at least the SolidColor LED effect. I wonder if it's worth implementing something in the base class to let the user pass in a descriptive string in the constructor or with another method call and then having the base class able to respond with that in preference to the hardcoded name.

Given that, it might make sense to refactor onNameQuery into the base class and to pull the name from a string baked into the plugin so we can reuse it for this

I like the idea of implementing it in the base class. Right now every plugin has a few nearly identical lines, just to make this work. Moving the LED effect name to a variable allows for deduplicating lines as well as adds flexibility for including parameters, like for SolidColor, so it's win/win.

Will look into that soon.

@EvyBongers
Copy link
Contributor Author

EvyBongers commented Feb 18, 2024

There's something I have yet to figure out about the constuctor arguments, but this new design seems to be working great.

$ ../_firmware/kaleidoscope/bin/focus-send led_effects
LEDOff
LEDRainbowEffect
LEDRainbowWaveEffect
LEDActiveLayerKeysEffect
LEDChaseEffect
SolidColorEffect: /* TODO */
SolidColorEffect: /* TODO */
SolidColorEffect: /* TODO */
SolidColorEffect: /* TODO */
SolidColorEffect: /* TODO */
SolidColorEffect: /* TODO */
SolidColorEffect: /* TODO */
LEDBreatheEffect
AlphaSquareEffect
StalkerEffect
ColormapEffect
HeatmapEffect
LEDActiveLayerColorEffect
WavepoolEffect
DigitalRainEffect

One question: should led modes that haven't got a name specified return a default (empty?) string? With this new design, that can be easily achieved in LEDModeInterface.h

@obra
Copy link
Member

obra commented Feb 18, 2024

Since the goal is to match up these names to the LED effect list in a desktop app like Chrysalis, I think we want a straight one to one mapping between effects and names ordered the same as they are on the device

Copy link
Contributor Author

@EvyBongers EvyBongers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented and tested the led mode name in just about all the relevant plugins now. The only exceptions are Jukebox and Miami plugins, because with my limited understanding of C++, I failed to figure out how to implement it in those.
On a side note: when I tried getting Tricolor to work, I got errors that I failed to resolve and at this point I'm not even sure if Tricolor is even meant to be used as a plugin.

src/kaleidoscope/plugin/LEDModeInterface.h Outdated Show resolved Hide resolved
src/kaleidoscope/plugin/LEDControl/LED-Off.h Outdated Show resolved Hide resolved
@EvyBongers
Copy link
Contributor Author

I'm not sure what I need to change in order to get those failing checks to pass. I would appreciate some help :)

@obra
Copy link
Member

obra commented Feb 19, 2024

I'm not sure what I need to change in order to get those failing checks to pass. I would appreciate some help :)

Oh. I think the issue here is that you're essentially introducing a focus dependency in the core that has not previously existed. I think you probably want to have onLedEffectQuery return a pointer
and have the code inside focus do the output.

@EvyBongers
Copy link
Contributor Author

EvyBongers commented Feb 21, 2024

Oh. I think the issue here is that you're essentially introducing a focus dependency in the core that has not previously existed. I think you probably want to have onLedEffectQuery return a pointer and have the code inside focus do the output.

The api expects hooks to return an EventHandlerResult, so it can't return a pointer. I tried to solve it by passing a pointer as reference and read it after the LED mode plugin set the value:

if (inputMatchesCommand(input, cmd_led_modes)) {
  const char *ledModeName;
  kaleidoscope::Hooks::onLedEffectQuery(ledModeName);
  ::Focus.send(ledModeName, '\n');
  return EventHandlerResult::EVENT_CONSUMED;
}

This resulted in only a single LED mode being sent back. After hours of debugging, the simplicity of the problem struck me: kaleidoscope::Hooks::onLedEffectQuery(ledModeName); only returns once the hook has been called on all plugins.

I could try to make it a list of strings that gets updated, but that seems far from efficient. It also doesn't solve the other problem that is reported in CI, that the sketch becomes too large for the Model01.

An alternative solution might be to update the hooks API to support callback functions and supply a callback that calls ::Focus.send() every time the hook is called on a plugin.

@obra
Copy link
Member

obra commented Feb 21, 2024

I think this patch gets us what we want in terms of flow, using the callback. Before it can land, I need to make sure we cut down the code size for AVR a bit. I've got a potential refactor I just need to test out.
for-evy.patch

Comment on lines 80 to 82
void ledModeHandler_(const __FlashStringHelper *name) {
Runtime.serialPort().println(name);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this return EventHandlerResult::OK, similar to ::Focus.sendName?
Even if it doesn't, with the current signature of onLedEffectQuery we might as well rename ::Focus.sendName to ::Focus.sendLine and use that, rather than having a handler method that does almost exactly the same :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EventHandlerResult::OK is something that gets returned by the actual EventHandler, which, in this case, is onLedEffectQuery

This is made more confusing than it should be by me misnaming the callback that prints out the LED mode ledModeHandler_ rather than sendLedModeCallback_ or something like that.

And I think I agree more with your comment down-conversation about moving the 'unnamed mode' guard into the callback than about reusing sendName as the callback.

I didn't realize that with the signature const __FlashStringHelper *name we could also pass in regular in-memory strings and that everything would work.)

(I do think sendName should get refactored, but let's tackle that outside this PR)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is made more confusing than it should be by me misnaming the callback that prints out the LED mode ledModeHandler_ rather than sendLedModeCallback_ or something like that.

I agree. I'll rename the method

src/kaleidoscope/plugin/LEDModeInterface.h Outdated Show resolved Hide resolved
Signed-off-by: Evy Bongers <[email protected]>
@EvyBongers
Copy link
Contributor Author

All of them are implemented now. Only thing is that the Tricolor effects (Jukebox and Miami) don't yet support setting a custom name.

$ ../_firmware/kaleidoscope/bin/focus-send led.modes
Off
Rainbow
RainbowWave
Wavepool
ActiveLayerKeys
Chase
solidRed
solidOrange
solidYellow
solidGreen
solidBlue
solidIndigo
solidViolet
Breathe
AlphaSquare
Stalker
Colormap
Heatmap
ActiveLayerColor
DigitalRain
Jukebox
JukeboxAlternate
Miami

@EvyBongers EvyBongers marked this pull request as ready for review February 26, 2024 13:27
@obra
Copy link
Member

obra commented Feb 26, 2024

Reading through the code, it's weird to me that we're ending up with an underscore prefixed lowerCamelCase _ledModeName pointer as an argument to the constructor, when all the other constructor params are snake_case and that we're ending up with a lowerCamelCase protected const __FlashStringHelper *ledModeName; in our LEDModeInterface class.

The style guide isn't super helpful for the constructor args, but for members, it says we do want 'em snake cased and that if they're not public, they should have trailing _s. AccessTransientLEDMode.his the first example in the core I can find with an actual member variable that's protected:

protected: uint8_t led_mode_id_ = 255; /* 255 means uninitialized */ };

I think I'd have expected the constructors to look more like:

TriColor::TriColor(const __FlashStringHelper *led_mode_name, cRGB base_color, cRGB mod_color, cRGB esc_color) { led_mode_name_ = led_mode_name;

and that we should end up with the member looking like this:
protected: const __FlashStringHelper *led_mode_name_;

@EvyBongers
Copy link
Contributor Author

Reading through the code, it's weird to me that we're ending up with an underscore prefixed lowerCamelCase _ledModeName pointer as an argument to the constructor, when all the other constructor params are snake_case and that we're ending up with a lowerCamelCase protected const __FlashStringHelper *ledModeName; in our LEDModeInterface class.

I'll update that. I mostly focussed on getting code to work and for the parts of the style guide I was already aware of, I've tried to stick to it, but I certainly haven't read the full style guide. Thank you for pointing that out.

The style guide isn't super helpful for the constructor args, but for members, it says we do want 'em snake cased and that if they're not public, they should have trailing _s. AccessTransientLEDMode.his the first example in the core I can find with an actual member variable that's protected:

protected: uint8_t led_mode_id_ = 255; /* 255 means uninitialized */ };

I think I'd have expected the constructors to look more like:

TriColor::TriColor(const __FlashStringHelper *led_mode_name, cRGB base_color, cRGB mod_color, cRGB esc_color) { led_mode_name_ = led_mode_name;

and that we should end up with the member looking like this: protected: const __FlashStringHelper *led_mode_name_;

👍🏻

@obra
Copy link
Member

obra commented Mar 8, 2024

@EvyBongers - just that one question from this last review. Other than that, I just want to run it on hardware, then I'm happy to merge. Thanks so much for your work on this!

Signed-off-by: Evy Bongers <[email protected]>
@obra obra merged commit d617890 into keyboardio:master Mar 13, 2024
8 checks passed
@EvyBongers EvyBongers deleted the feat/LedEffectNames branch March 13, 2024 21:11
EvyBongers added a commit to EvyBongers/Kaleidoscope that referenced this pull request May 7, 2024
…boardio#1387)

* Implement focus command `led.modes` for querying LED modes

Signed-off-by: Evy Bongers <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants