Look in HIDTables.h
for the numerical values.
The actual HID standard bytes are in KeyboardioHID/src/HIDTables.h
those are taken from the USB HID protocol standard which is not likely to change soon.
Exactly.
Good point. My macro was defined for lazy users but your idea of generalization makes sense to me.
Yep.
I forgot to mention that I would recommend against using the macros defined in KeyboardioHID/src/HIDTables.h
directly in your code.
Something Iām struggling with a bit in implementing your suggestion is how to call a function from a class within that classās definition. Specifically, in the .h file, in the macro, if I wanted to use my example āisNumber()ā function, or even a dim() function, I get an error that it isnāt declared in this scope.
#define FC_CB_END_COLOR_LIST \
} /*end switch*/ \
/*Handle colors for group members without specific colors here */ \
if(isNumber(k)) {return numberCB;} \
static byte default_cb = (defaultPaletteId << 4) | defaultBrightness; \
return default_cb; \
}
Noob question, I know, but how can I handle this?
Iām getting closerā¦
kaleidoscope::LEDFunctionalColorCB::isNumber(k)
But now I need the object name in order to use the function, so Iāve got to figure out how to reference that.
If you are using the FC_CB_START_COLOR_LIST
/FC_CB_END_COLOR_LIST
macros in the sketch, they are defined at global scope and the function is a global function, where a class member is not available unless a public static member.
You say you do it in the class definition? Something like
class FC {
public:
FC_CB_START_COLOR_LIST
...
FC_CB_END_COLOR_LIST
...
};
This must be
class FC {
public:
static FC_CB_START_COLOR_LIST
...
FC_CB_END_COLOR_LIST
...
static bool isNumber(...) {...}
};
Else you would define a non-static member function. Only static member functions can be used in the same way as pointers to global functions (There are also pointers to member-functions but that is a completely different matter and of no use here).
Of course! Those functions make a lot more sense as static member functions since they donāt need to refer to anything specific about the object. I managed to get that workingā¦ but the way I had intended to implement it was to have member variables for each instance of the class to record the colorbyte associated with each groupā¦ (numberCB in the example I posted earlier).
I suspect this approach wonāt work really well from within the macros, however, since thereās no instance yet, and thus I canāt read it.
Would it make sense to make these variables static as well? I suppose that would prevent you from having multiple instances with distinct settings for the colorgroupsā¦
Otherwise Iād have to define them all through arguments to the macroā¦ which just sounds really complicated for the end user to me. Any ideas?
Not really. Do you want the colors to be fixed or runtime changeable?
// Defined by your plugin. Either static class member or global in plugin namespace
//
template<typename ColorMap>
cRGB specificColorLookup(const Key &k) {
if(someCondition(k)) {
return ColorMap::color1;
}
...
}
...
// In the sketch
// in namespace/global scope
//
struct MyColorMap {
static constexpr cRGB color1 = green;
static constexpr cRGB color2 = red;
...
}
...
// In setup()
//
myPluginInstance.setColorLookup(specificColorLookup<MyColorMap>);
This is a perfect usecase for template functions.
Soā¦ the setColorLookup() function is being passed a reference to the specificColorLookup() function here? Why do it this way, instead of just passing a reference to MyColorMap instead, then using that to override the defaults in a structure within the class?
I presume thereās some kind of efficiency benefit to your approach that Iām not appreciating.
MyColorMap is a type that has only compile time constant members and is never instanciated. Sounds strange, no? The templated function uses it like a user definable palette with named entries. With this approach all colors are compile time constant yet user definable. Any number of specific color lookup functions can be defined by your plugin. The functions define which names must be present in ColorMap. Templates are a bit like duck typing.
Imagine a specific color lookup function template<typename ColorMap> cRGB colorModifiers(const Key &k)
.
ColorMap
would then be required to define e.g. colorShift
, colorAlt
and colorCtrl
.
Iām kind of stuck on how I would create the setColorLookup() function. I think I at least understand how to create a function that accepts another function as a parameter by reference, but after that, what do I do with it?
template<typename ColorMap>
cRGB groupColorLookup(const Key &k) {
if(LEDFunctionalColorCB::isNumber(k)) {return ColorMap::numberColor;}
}
void setColorLookup(cRGB (&gcl)(const Key)) {
gcl(???); //how to specify a key as the parameter?
// What else goes here?
}
It seems I managed to confuse you Just take the existing
LEDFunctionalColorRGB
class and modify it slightly. Remove the now obsolete setKeyColor
method.
class LEDFunctionalColorRGB {
public:
typedef cRGB (*RGBLookup)(const Key &);
void setColorLookup(RGBLookup rgbLookup) {
rgbLookup_ = rgbLookup;
}
// No further changes required
...
};
I would suggest to move functions like isNumber
to an extra header in a suitable namespace and make them inline constexpr
at global scope. That header might then be a candidated to be submitted to the firmware core repo later.
Youāve had me confused for days but it doesnāt take much. Today I spent several hours trying to figure out why I couldnāt compile until I realized that I needed a semicolon after the colormap struct definition. (That should have been a lot more obvious than it was but somehow I thought the problem was in my header file. facepalm)
What Iām currently stuck on now is the call to setColorLookup. Iām getting an error: āerror: expected primary-expression before āgroupColorLookupāā
on this line:
fcRGB.setColorLookup(kaleidoscope::LEDFunctionalColorRGB groupColorLookup<FColorMap>);
Edit:
I might not have specified the scope correctly. After changing it to
fcRGB.setColorLookup(kaleidoscope::LEDFunctionalColorRGB::groupColorLookup<FColorMap>);
I now get the error
error: no matching function for call to 'kaleidoscope::LEDFunctionalColorRGB::setColorLookup(<unresolved overloaded function type>)'
I need the full code to maybe tell you what goes wrong. Can you push it to a branch of your github repo?
Itās actually the master branch of my repo right now. Iāve made a pretty big mess of that.
I have added the busted .ino file to the examples directory alongside the one you submitted in your PR.
Hopefully thereās something simple wrong there that you can quickly point out. Iād say itās far more likely that Iāve just made a giant mess, though. Iām a bit in over my head!
Templates are different in that the whole implementation must be visible at the time of instancitation.
Move the implementation of groupColorLookup
to the plugin header and you should be fine.
Okay, good to knowā¦ but Iām afraid that didnāt get me any farther through compilation. Iām still getting the same error with the implementation in the header.
Kaleidoscope-LEDEffect-FunctionalColor.h:161:36: error: extra qualification 'kaleidoscope::LEDFunctionalColorRGB::' on member 'groupColorLookup' [-fpermissive]
template<typename ColorMap> cRGB LEDFunctionalColorRGB::groupColorLookup(const Key &k) {
^
/Users/jdlien/Dropbox/Keyboards/Keyboardio/Model01-Firmware_noseglasses/Model01-Firmware_noseglasses.ino: In function 'void setup()':
Model01-Firmware_noseglasses:401: error: no matching function for call to 'kaleidoscope::LEDFunctionalColorRGB::setColorLookup(<unresolved overloaded function type>)'
fcRGB.setColorLookup(kaleidoscope::LEDFunctionalColorRGB::groupColorLookup<FColorMap>);
The first error should vanish if you remove theLEDFunctionalColorRGB
in line 161 of the plugin header.
Also modify
typedef cRGB & (*RGBLookup)(const Key &);
to
typedef cRGB (*RGBLookup)(const Key &);
then it might work.
Sorry, Iām currently on a rock climbing trip in Italy and only have my smartphone with me. So I canāt compile your code.
Keep me updated!