Raw Firmware Hack: Use QMK to Light Up Layers and Specific Keys on ErgoDox EZ Glow

Florian Didron
The Ergo
Published in
3 min readNov 22, 2018

The configurator is awesome (even if I’m a little biased, being its developer). It lets you do so much! Still, sometimes it’s fun to peek under the hood and get your hands dirty with some direct QMK hacking.

This short tutorial will show you how you can enable specific lighting on your ErgoDox EZ Glow. This comes in two flavors:

  • Layer-specific: Switch to layer 1, your whole board goes yellow; switch to layer 2, the board becomes light blue.
  • Key-specific: Switch to layer 1, and only some keys (such as the ones defined on layer 1) light up.

Needless to say, this is coming to the configurator. But if you enjoy playing with the actual firmware, or are curious to see how the configurator will make this magic happen, read on.

This assumes that your rules.mk and config.h file comes from the configurator set for the Glow -- i.e, the RGB Matrix features are already enabled.

Hack time: keymap.c

In this example, we’re going to be working with a custom keymap based on my layout. This is where the magic happens.

First let’s declare a rgb_matrix_config variable of type rgb_config_t :

rgb_config_t rgb_matrix_config;

Then declare two maps which will serve two purposes:

  • layercolors to illuminate all the LEDs of a layer with the same color;
  • ledcolors to illuminate individual keys on a layer.
const uint8_t PROGMEM layercolors[][2] = {
...
}
const uint8_t PROGMEM ledcolors[][DRIVER_LED_TOTAL][3] = {
...
}

All colors are described using the HSV format.

Note that the layercolors map contains data for the hue and saturation only since its value (or brightness) will be overridden with the value from the EEPROM to take into account the user’s brightness settings. In other words, if the lighting is currently dim, we’re not going to blast the board on full brightness when you switch a layer.

Next step is to read the rgb_matrix config from the EEPROM. We will use the enable boolean to turn off the LEDs if the user toggles them off, as well as use the val value to adjust the LEDs brightness based on user control:

void matrix_init_user(void) {
rgb_matrix_config.raw = eeprom_read_dword(EECONFIG_RGB_MATRIX);
}

Then based on which layer is active, the LED colors gets assigned:

void rgb_matrix_indicators_user(void) {
uint32_t mode = rgblight_get_mode();
// assign colors if the matrix is on and the current mode
// is SOLID COLORS => No animations running
if(rgb_matrix_config.enable == 1 && mode == 1) {
uint8_t layer = biton32(layer_state);
switch (layer) {
case 0:
set_layer_color(0);
break;
case 1:
set_leds_color(1);
break;
}
}
}

The set_layer_color function will set all the color of all the LEDs uniformally by merging the hue and saturation values from the layercolors map with the brightness value from the EEPROM.

void set_layer_color( uint8_t layer ) {
HSV hsv = { .h = pgm_read_byte(&layercolors[layer][0]), .s = pgm_read_byte(&layercolors[layer][1]), .v = rgb_matrix_config.val};
RGB rgb = hsv_to_rgb( hsv );
for (int i = 0; i < DRIVER_LED_TOTAL; i++) {
rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
}
}

The set_leds_color function will set the LEDs color individually by merging the hue, saturation values from the ledcolors map with the brightness value from the EEPROM. If the brightness of the key was set to 0 in the ledcolors map, it will override the brightness value from the EEPROM allowing to have individal LEDs turned off.

void set_leds_color( int layer) {
for (int i = 0; i < DRIVER_LED_TOTAL; i++) {
uint8_t val = pgm_read_byte(&ledcolors[layer][i][2]);
// if the brightness of the led is set to 0 in the map,
// the value is not overriden with global controls, allowing the led
// to appear turned off
HSV hsv = { .h = pgm_read_byte(&ledcolors[layer][i][0]), .s = pgm_read_byte(&ledcolors[layer][i][1]), .v = val == 0 ? 0 : rgb_matrix_config.val};
RGB rgb = hsv_to_rgb( hsv );
rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
}
}

Magic!

And if this seemed a little too magical, wait for a little and you’ll see this come up in a much more graphical way in the configurator. Thank you for reading!

Here is a link to a gist that includes all source files.

--

--