New Plugin: Kaleidoscope-LED-Fire

Plugin name: Kaleidoscope-LED-Fire
Author: kevinriggle
Source URL: https://github.com/kevinr/Kaleidoscope-LED-Fire

Description:

The FireEffect plugin makes flames that roar from the bottom of your keyboard and every keypress.

fire-effect

fire-effect-keypress

3 Likes

Really cool LED effect!

@kevinriggle, Kaleidoscope.use(...) is gone for a while now. You might want to update README.md and example sketch of Kaleidoscope-LED-Fire to use KALEIDOSCOPE_INIT_PLUGINS(...). Otherwise it will not work with current versions of the firmware.

1 Like

Oh that’s a very good catch @noseglasses, thank you! The code is actually up to date with the current plugin API, or should be (based on https://github.com/ToyKeeper/Kaleidoscope-LED-Wavepool/pull/7), it’s just the documentation which is out of date. I’ll see about fixing that. Let me know if you have any trouble using it with the current firmware.

Update: Ported it to the yet more current plugin API and updated the docs.

I gave it a try and it looks really gorgeous.

On my Ubuntu system with Arduino 1.8.8 I encountered something strange. When building the example sketch that comes with Kaleidoscope-LED-Fire based on a fresh clone of the bundle and the fire plugin I get a linker error.

.../keyboardio/avr/libraries/Kaleidoscope-LED-Fire/src/Kaleidoscope/LED-Fire.cpp:135: undefined reference to `hsvToRgb(unsigned int, unsigned int, unsigned int)'

This is something that I never encountered before.

By adding VERBOSE=1 to the build command line, it becomes visible that the linker sees Kaleidoscope.a before Kaleidoscope-LED-Fire.a. This is the reason for the error as the linker throws away the function hsvToRgb that is unused at the point where it is read from Kaleidoscope.a. Only when it encounters Kaleidoscope-LED-Fire.a later on, it notices that it actually needs that function and throws the error.

It seems that Arduino is having trouble generating a correct linker line. This can be fixed by changing the include order in Kaleidoscope-LED-Fire/examples/LED-Fire/LED-Fire.ino to

#include <Kaleidoscope-LED-Fire.h>
#include <Kaleidoscope.h>
#include <Kaleidoscope-LEDControl.h>

which reverses the order in which the libraries are passed to the linker.

I would be really curious if other people also experience this.

It had slipped my mind that a younger me had already documented the library link order problem here.

Thanks for trying it out!

I also observe this issue when compiling with the example sketch, but not when adding #include <Kaleidoscope-LED-Fire.h> to the default Model01-Firmware.ino following the #include <Kaleidoscope-LEDControl.h line. I wonder why.

Yeah, I can reproduce that.

As I am really interested in understanding this, I did a thorough investigation of the matter and found the following explanation (which is unfortunately a bit complicated). @algernon, this might be interesting to you as well.

Arduino always adds the sketch object at the start of the linker command line, before any other library archives. Because of this, if the sketch directly or indirectly references a function from Kaleidoscope.a, that function will will never be removed during garbage collection.

Unfortunately, this only works with non-virtual function functions because the virtual function that is actually called is only known at runtime. Kaleidoscope-LED-Fire, however calls hsvToRgb(...) in the plugin’s update() method which is a virtual function of the LEDMode interface. That’s why hsvToRgb(...), being called ‘virtually’, is garbage collected in the case of the example sketch.

The default sketch on the other hand uses the BootGreetingEffect which has a non-virtual event handler method afterEachCycle() that indirectly calls hsvToRgb(...) as

kaleidoscope::plugin::BootGreetingEffect::afterEachCycle()
-> breath_compute(...)
   -> hsvToRgb(...)

Thus, when the linker encounters Kaleidoscope.a in the case of the default sketch, it knows that it is not allowed to garbage collect hsvToRgb(...) and everything works as expected.

There is a solution for this problem but it is not at zero cost: We can force the sketch to access hsvToRgb(...) directly and only if the Kaleidoscope-LED-Fire plugin is actually used. This can be achieved by adding an inlined onSetup() event handler to Kaleidoscope-LED-Fire that does a dummy call to hsvToRgb(...). As this call is inlined when the sketch is compiled, the linker will see the sketch calling hsvToRgb(...) which is thus protected from being garbage collected.

Here’s the PR:

It turns out that this problem does not only happen with virtual functions but in any occasions where a library (plugin) A calls a function of another library (plugin) B that ends up in the linker command line before A and the function called is neither directly nor indirectly called from the sketch.

I think I’ve seen this, too, but I lacked the expertise to debug the linker, so I just tried a bunch of things until I got it to compile. I’ll have to keep this in mind next time I get an inexplicable linker error…

I found a fix for this problem and submitted a PR against the bundle repo. It fixes the build system in a way that should hopefully do away with any future link/include order problems.

3 Likes

Thank you. That PR has now been merged.

2 Likes