From 763b26cdb98c2702f7b2f8de239d4edba0fa4065 Mon Sep 17 00:00:00 2001 From: Daniel Prilik Date: Wed, 3 Apr 2019 18:30:47 -0700 Subject: RGB Matrix support for Massdrop CTRL/ALT (#5328) * port Massdrop CTRL/ALT to use RGB Matrix Co-authored-by: Matt Schneeberger * Massdrop lighting support working This commit is to get the Massdrop lighting code working again through use of the compilation define USE_MASSDROP_CONFIGURATOR added to a keymap's rules.mk. Added keymaps for both CTRL and ALT named default_md and mac_md. These should be used if the Massdrop style lighting is desired. * Updating config based on testing results with patrickmt & compile errors * Updates for PR5328 For CTRL and ALT: Moved location of new RGB Matrix macros from config_led.h to config.h. Added RGB_MATRIX_LED_FLUSH_LIMIT (time between flushes) to config.h for correct LED driver update timing. Re-added missing breathing code for when Massdrop configurator mode is defined. * remove prilik keymap form PR --- tmk_core/protocol/arm_atsam/led_matrix.c | 554 +++++++++++++++---------------- 1 file changed, 259 insertions(+), 295 deletions(-) (limited to 'tmk_core/protocol/arm_atsam/led_matrix.c') diff --git a/tmk_core/protocol/arm_atsam/led_matrix.c b/tmk_core/protocol/arm_atsam/led_matrix.c index 04d05af6d..e29fb6587 100644 --- a/tmk_core/protocol/arm_atsam/led_matrix.c +++ b/tmk_core/protocol/arm_atsam/led_matrix.c @@ -17,9 +17,19 @@ along with this program. If not, see . #include "arm_atsam_protocol.h" #include "tmk_core/common/led.h" +#include "rgb_matrix.h" #include #include +#ifdef USE_MASSDROP_CONFIGURATOR +__attribute__((weak)) +led_instruction_t led_instructions[] = { { .end = 1 } }; +static void led_matrix_massdrop_config_override(int i); +#endif // USE_MASSDROP_CONFIGURATOR + +extern rgb_config_t rgb_matrix_config; +extern rgb_counters_t g_rgb_counters; + void SERCOM1_0_Handler( void ) { if (SERCOM1->I2CM.INTFLAG.bit.ERROR) @@ -51,14 +61,17 @@ void DMAC_0_Handler( void ) issi3733_driver_t issidrv[ISSI3733_DRIVER_COUNT]; -issi3733_led_t led_map[ISSI3733_LED_COUNT+1] = ISSI3733_LED_MAP; -issi3733_led_t *lede = led_map + ISSI3733_LED_COUNT; //End pointer of mapping +issi3733_led_t led_map[ISSI3733_LED_COUNT] = ISSI3733_LED_MAP; +RGB led_buffer[ISSI3733_LED_COUNT]; uint8_t gcr_desired; -uint8_t gcr_breathe; -uint8_t gcr_use; uint8_t gcr_actual; uint8_t gcr_actual_last; +#ifdef USE_MASSDROP_CONFIGURATOR +uint8_t gcr_breathe; +float breathe_mult; +float pomod; +#endif #define ACT_GCR_NONE 0 #define ACT_GCR_INC 1 @@ -73,11 +86,14 @@ static uint8_t v_5v_cat_hit; void gcr_compute(void) { uint8_t action = ACT_GCR_NONE; + uint8_t gcr_use = gcr_desired; +#ifdef USE_MASSDROP_CONFIGURATOR if (led_animation_breathing) + { gcr_use = gcr_breathe; - else - gcr_use = gcr_desired; + } +#endif //If the 5v takes a catastrophic hit, disable the LED drivers briefly, assert auto gcr mode, min gcr and let the auto take over if (v_5v < V5_CAT) @@ -151,6 +167,7 @@ void gcr_compute(void) gcr_actual -= LED_GCR_STEP_AUTO; gcr_min_counter = 0; +#ifdef USE_MASSDROP_CONFIGURATOR //If breathe mode is active, the top end can fluctuate if the host can not supply enough current //So set the breathe GCR to where it becomes stable if (led_animation_breathing == 1) @@ -160,12 +177,11 @@ void gcr_compute(void) // and the same would happen maybe one or two more times. Therefore I'm favoring // powering through one full breathe and letting gcr settle completely } +#endif } } } -led_disp_t disp; - void issi3733_prepare_arrays(void) { memset(issidrv,0,sizeof(issi3733_driver_t) * ISSI3733_DRIVER_COUNT); @@ -178,361 +194,309 @@ void issi3733_prepare_arrays(void) issidrv[i].addr = addrs[i]; } - issi3733_led_t *cur = led_map; - - while (cur < lede) + for (uint8_t i = 0; i < ISSI3733_LED_COUNT; i++) { //BYTE: 1 + (SW-1)*16 + (CS-1) - cur->rgb.g = issidrv[cur->adr.drv-1].pwm + 1 + ((cur->adr.swg-1)*16 + (cur->adr.cs-1)); - cur->rgb.r = issidrv[cur->adr.drv-1].pwm + 1 + ((cur->adr.swr-1)*16 + (cur->adr.cs-1)); - cur->rgb.b = issidrv[cur->adr.drv-1].pwm + 1 + ((cur->adr.swb-1)*16 + (cur->adr.cs-1)); + led_map[i].rgb.g = issidrv[led_map[i].adr.drv-1].pwm + 1 + ((led_map[i].adr.swg-1)*16 + (led_map[i].adr.cs-1)); + led_map[i].rgb.r = issidrv[led_map[i].adr.drv-1].pwm + 1 + ((led_map[i].adr.swr-1)*16 + (led_map[i].adr.cs-1)); + led_map[i].rgb.b = issidrv[led_map[i].adr.drv-1].pwm + 1 + ((led_map[i].adr.swb-1)*16 + (led_map[i].adr.cs-1)); //BYTE: 1 + (SW-1)*2 + (CS-1)/8 //BIT: (CS-1)%8 - *(issidrv[cur->adr.drv-1].onoff + 1 + (cur->adr.swg-1)*2+(cur->adr.cs-1)/8) |= (1<<((cur->adr.cs-1)%8)); - *(issidrv[cur->adr.drv-1].onoff + 1 + (cur->adr.swr-1)*2+(cur->adr.cs-1)/8) |= (1<<((cur->adr.cs-1)%8)); - *(issidrv[cur->adr.drv-1].onoff + 1 + (cur->adr.swb-1)*2+(cur->adr.cs-1)/8) |= (1<<((cur->adr.cs-1)%8)); - - cur++; + *(issidrv[led_map[i].adr.drv-1].onoff + 1 + (led_map[i].adr.swg-1)*2+(led_map[i].adr.cs-1)/8) |= (1<<((led_map[i].adr.cs-1)%8)); + *(issidrv[led_map[i].adr.drv-1].onoff + 1 + (led_map[i].adr.swr-1)*2+(led_map[i].adr.cs-1)/8) |= (1<<((led_map[i].adr.cs-1)%8)); + *(issidrv[led_map[i].adr.drv-1].onoff + 1 + (led_map[i].adr.swb-1)*2+(led_map[i].adr.cs-1)/8) |= (1<<((led_map[i].adr.cs-1)%8)); } } -void disp_calc_extents(void) +void led_matrix_prepare(void) { - issi3733_led_t *cur = led_map; - - disp.left = 1e10; - disp.right = -1e10; - disp.top = -1e10; - disp.bottom = 1e10; - - while (cur < lede) + for (uint8_t i = 0; i < ISSI3733_LED_COUNT; i++) { - if (cur->x < disp.left) disp.left = cur->x; - if (cur->x > disp.right) disp.right = cur->x; - if (cur->y < disp.bottom) disp.bottom = cur->y; - if (cur->y > disp.top) disp.top = cur->y; - - cur++; + *led_map[i].rgb.r = 0; + *led_map[i].rgb.g = 0; + *led_map[i].rgb.b = 0; } - - disp.width = disp.right - disp.left; - disp.height = disp.top - disp.bottom; - disp.max_distance = sqrtf(powf(disp.width, 2) + powf(disp.height, 2)); } -void disp_pixel_setup(void) +void led_set_one(int i, uint8_t r, uint8_t g, uint8_t b) { - issi3733_led_t *cur = led_map; - - while (cur < lede) + if (i < ISSI3733_LED_COUNT) { - cur->px = (cur->x - disp.left) / disp.width * 100; - cur->py = (cur->y - disp.bottom) / disp.height * 100; - *cur->rgb.r = 0; - *cur->rgb.g = 0; - *cur->rgb.b = 0; - - cur++; +#ifdef USE_MASSDROP_CONFIGURATOR + led_matrix_massdrop_config_override(i); +#else + led_buffer[i].r = r; + led_buffer[i].g = g; + led_buffer[i].b = b; +#endif } } -void led_matrix_prepare(void) +void led_set_all(uint8_t r, uint8_t g, uint8_t b) { - disp_calc_extents(); - disp_pixel_setup(); + for (uint8_t i = 0; i < ISSI3733_LED_COUNT; i++) + { + led_set_one(i, r, g, b); + } } -uint8_t led_enabled; -float led_animation_speed; -uint8_t led_animation_direction; -uint8_t led_animation_orientation; -uint8_t led_animation_breathing; -uint8_t led_animation_breathe_cur; -uint8_t breathe_step; -uint8_t breathe_dir; -uint8_t led_animation_circular; -uint64_t led_next_run; - -uint8_t led_animation_id; -uint8_t led_lighting_mode; - -issi3733_led_t *led_cur; -uint8_t led_per_run = 15; -float breathe_mult; - -__attribute__ ((weak)) -void led_matrix_run(void) +void init(void) { - float ro; - float go; - float bo; - float po; - - uint8_t led_this_run = 0; - led_setup_t *f = (led_setup_t*)led_setups[led_animation_id]; - - if (led_cur == 0) //Denotes start of new processing cycle in the case of chunked processing - { - led_cur = led_map; + DBGC(DC_LED_MATRIX_INIT_BEGIN); - disp.frame += 1; + issi3733_prepare_arrays(); - breathe_mult = 1; + led_matrix_prepare(); - if (led_animation_breathing) - { - led_animation_breathe_cur += breathe_step * breathe_dir; + gcr_min_counter = 0; + v_5v_cat_hit = 0; - if (led_animation_breathe_cur >= BREATHE_MAX_STEP) - breathe_dir = -1; - else if (led_animation_breathe_cur <= BREATHE_MIN_STEP) - breathe_dir = 1; + DBGC(DC_LED_MATRIX_INIT_COMPLETE); +} - //Brightness curve created for 256 steps, 0 - ~98% - breathe_mult = 0.000015 * led_animation_breathe_cur * led_animation_breathe_cur; - if (breathe_mult > 1) breathe_mult = 1; - else if (breathe_mult < 0) breathe_mult = 0; - } - } +void flush(void) +{ +#ifdef USE_MASSDROP_CONFIGURATOR + if (!led_enabled) { return; } //Prevent calculations and I2C traffic if LED drivers are not enabled +#else + if (!sr_exp_data.bit.SDB_N) { return; } //Prevent calculations and I2C traffic if LED drivers are not enabled +#endif - uint8_t fcur = 0; - uint8_t fmax = 0; + // Wait for previous transfer to complete + while (i2c_led_q_running) {} - //Frames setup - while (f[fcur].end != 1) + // Copy buffer to live DMA region + for (uint8_t i = 0; i < ISSI3733_LED_COUNT; i++) { - fcur++; //Count frames + *led_map[i].rgb.r = led_buffer[i].r; + *led_map[i].rgb.g = led_buffer[i].g; + *led_map[i].rgb.b = led_buffer[i].b; } - fmax = fcur; //Store total frames count +#ifdef USE_MASSDROP_CONFIGURATOR + breathe_mult = 1; - while (led_cur < lede && led_this_run < led_per_run) + if (led_animation_breathing) { - ro = 0; - go = 0; - bo = 0; - - if (led_lighting_mode == LED_MODE_KEYS_ONLY && led_cur->scan == 255) - { - //Do not act on this LED - } - else if (led_lighting_mode == LED_MODE_NON_KEYS_ONLY && led_cur->scan != 255) - { - //Do not act on this LED - } - else if (led_lighting_mode == LED_MODE_INDICATORS_ONLY) - { - //Do not act on this LED (Only show indicators) - } - else - { - //Act on LED - for (fcur = 0; fcur < fmax; fcur++) - { - - if (led_animation_circular) { - po = sqrtf((powf(fabsf((disp.width / 2) - (led_cur->x - disp.left)), 2) + powf(fabsf((disp.height / 2) - (led_cur->y - disp.bottom)), 2))) / disp.max_distance * 100; - } - else { - if (led_animation_orientation) - { - po = led_cur->py; - } - else - { - po = led_cur->px; - } - } - - float pomod; - pomod = (float)(disp.frame % (uint32_t)(1000.0f / led_animation_speed)) / 10.0f * led_animation_speed; - - //Add in any moving effects - if ((!led_animation_direction && f[fcur].ef & EF_SCR_R) || (led_animation_direction && (f[fcur].ef & EF_SCR_L))) - { - pomod *= 100.0f; - pomod = (uint32_t)pomod % 10000; - pomod /= 100.0f; - - po -= pomod; - - if (po > 100) po -= 100; - else if (po < 0) po += 100; - } - else if ((!led_animation_direction && f[fcur].ef & EF_SCR_L) || (led_animation_direction && (f[fcur].ef & EF_SCR_R))) - { - pomod *= 100.0f; - pomod = (uint32_t)pomod % 10000; - pomod /= 100.0f; - po += pomod; - - if (po > 100) po -= 100; - else if (po < 0) po += 100; - } + //+60us 119 LED + led_animation_breathe_cur += BREATHE_STEP * breathe_dir; + + if (led_animation_breathe_cur >= BREATHE_MAX_STEP) + breathe_dir = -1; + else if (led_animation_breathe_cur <= BREATHE_MIN_STEP) + breathe_dir = 1; + + //Brightness curve created for 256 steps, 0 - ~98% + breathe_mult = 0.000015 * led_animation_breathe_cur * led_animation_breathe_cur; + if (breathe_mult > 1) breathe_mult = 1; + else if (breathe_mult < 0) breathe_mult = 0; + } - //Check if LED's po is in current frame - if (po < f[fcur].hs) continue; - if (po > f[fcur].he) continue; - //note: < 0 or > 100 continue + //This should only be performed once per frame + pomod = (float)((g_rgb_counters.tick / 10) % (uint32_t)(1000.0f / led_animation_speed)) / 10.0f * led_animation_speed; + pomod *= 100.0f; + pomod = (uint32_t)pomod % 10000; + pomod /= 100.0f; - //Calculate the po within the start-stop percentage for color blending - po = (po - f[fcur].hs) / (f[fcur].he - f[fcur].hs); +#endif // USE_MASSDROP_CONFIGURATOR - //Add in any color effects - if (f[fcur].ef & EF_OVER) - { - ro = (po * (f[fcur].re - f[fcur].rs)) + f[fcur].rs;// + 0.5; - go = (po * (f[fcur].ge - f[fcur].gs)) + f[fcur].gs;// + 0.5; - bo = (po * (f[fcur].be - f[fcur].bs)) + f[fcur].bs;// + 0.5; - } - else if (f[fcur].ef & EF_SUBTRACT) - { - ro -= (po * (f[fcur].re - f[fcur].rs)) + f[fcur].rs;// + 0.5; - go -= (po * (f[fcur].ge - f[fcur].gs)) + f[fcur].gs;// + 0.5; - bo -= (po * (f[fcur].be - f[fcur].bs)) + f[fcur].bs;// + 0.5; - } - else - { - ro += (po * (f[fcur].re - f[fcur].rs)) + f[fcur].rs;// + 0.5; - go += (po * (f[fcur].ge - f[fcur].gs)) + f[fcur].gs;// + 0.5; - bo += (po * (f[fcur].be - f[fcur].bs)) + f[fcur].bs;// + 0.5; - } - } - } + uint8_t drvid; - //Clamp values 0-255 - if (ro > 255) ro = 255; else if (ro < 0) ro = 0; - if (go > 255) go = 255; else if (go < 0) go = 0; - if (bo > 255) bo = 255; else if (bo < 0) bo = 0; + //NOTE: GCR does not need to be timed with LED processing, but there is really no harm + if (gcr_actual != gcr_actual_last) + { + for (drvid=0;drvidrgb.r = (uint8_t)ro; - *led_cur->rgb.g = (uint8_t)go; - *led_cur->rgb.b = (uint8_t)bo; + i2c_led_q_run(); +} -#ifdef USB_LED_INDICATOR_ENABLE - if (keyboard_leds()) +void led_matrix_indicators(void) +{ + uint8_t kbled = keyboard_leds(); + if (kbled && rgb_matrix_config.enable) + { + for (uint8_t i = 0; i < ISSI3733_LED_COUNT; i++) { - uint8_t kbled = keyboard_leds(); if ( - #if USB_LED_NUM_LOCK_SCANCODE != 255 - (led_cur->scan == USB_LED_NUM_LOCK_SCANCODE && kbled & (1<scan == USB_LED_CAPS_LOCK_SCANCODE && kbled & (1<scan == USB_LED_SCROLL_LOCK_SCANCODE && kbled & (1<scan == USB_LED_COMPOSE_SCANCODE && kbled & (1<scan == USB_LED_KANA_SCANCODE && kbled & (1<rgb.r > 127) *led_cur->rgb.r = 0; - else *led_cur->rgb.r = 255; - if (*led_cur->rgb.g > 127) *led_cur->rgb.g = 0; - else *led_cur->rgb.g = 255; - if (*led_cur->rgb.b > 127) *led_cur->rgb.b = 0; - else *led_cur->rgb.b = 255; + led_buffer[i].r = 255 - led_buffer[i].r; + led_buffer[i].g = 255 - led_buffer[i].g; + led_buffer[i].b = 255 - led_buffer[i].b; } } -#endif //USB_LED_INDICATOR_ENABLE - - led_cur++; - led_this_run++; } -} -uint8_t led_matrix_init(void) -{ - DBGC(DC_LED_MATRIX_INIT_BEGIN); +} - issi3733_prepare_arrays(); +const rgb_matrix_driver_t rgb_matrix_driver = { + .init = init, + .flush = flush, + .set_color = led_set_one, + .set_color_all = led_set_all +}; + +/*============================================================================== += Legacy Lighting Support = +==============================================================================*/ + +#ifdef USE_MASSDROP_CONFIGURATOR +// Ported from Massdrop QMK Github Repo + +// TODO?: wire these up to keymap.c +uint8_t led_animation_orientation = 0; +uint8_t led_animation_direction = 0; +uint8_t led_animation_breathing = 0; +uint8_t led_animation_id = 0; +float led_animation_speed = 4.0f; +uint8_t led_lighting_mode = LED_MODE_NORMAL; +uint8_t led_enabled = 1; +uint8_t led_animation_breathe_cur = BREATHE_MIN_STEP; +uint8_t breathe_dir = 1; + +static void led_run_pattern(led_setup_t *f, float* ro, float* go, float* bo, float pos) { + float po; - led_matrix_prepare(); + while (f->end != 1) + { + po = pos; //Reset po for new frame - disp.frame = 0; - led_next_run = 0; - - led_enabled = 1; - led_animation_id = 0; - led_lighting_mode = LED_MODE_NORMAL; - led_animation_speed = 4.0f; - led_animation_direction = 0; - led_animation_orientation = 0; - led_animation_breathing = 0; - led_animation_breathe_cur = BREATHE_MIN_STEP; - breathe_step = 1; - breathe_dir = 1; - led_animation_circular = 0; + //Add in any moving effects + if ((!led_animation_direction && f->ef & EF_SCR_R) || (led_animation_direction && (f->ef & EF_SCR_L))) + { + po -= pomod; - gcr_min_counter = 0; - v_5v_cat_hit = 0; + if (po > 100) po -= 100; + else if (po < 0) po += 100; + } + else if ((!led_animation_direction && f->ef & EF_SCR_L) || (led_animation_direction && (f->ef & EF_SCR_R))) + { + po += pomod; - //Run led matrix code once for initial LED coloring - led_cur = 0; - rgb_matrix_init_user(); - led_matrix_run(); + if (po > 100) po -= 100; + else if (po < 0) po += 100; + } - DBGC(DC_LED_MATRIX_INIT_COMPLETE); + //Check if LED's po is in current frame + if (po < f->hs) { f++; continue; } + if (po > f->he) { f++; continue; } + //note: < 0 or > 100 continue - return 0; -} + //Calculate the po within the start-stop percentage for color blending + po = (po - f->hs) / (f->he - f->hs); -__attribute__ ((weak)) -void rgb_matrix_init_user(void) { + //Add in any color effects + if (f->ef & EF_OVER) + { + *ro = (po * (f->re - f->rs)) + f->rs;// + 0.5; + *go = (po * (f->ge - f->gs)) + f->gs;// + 0.5; + *bo = (po * (f->be - f->bs)) + f->bs;// + 0.5; + } + else if (f->ef & EF_SUBTRACT) + { + *ro -= (po * (f->re - f->rs)) + f->rs;// + 0.5; + *go -= (po * (f->ge - f->gs)) + f->gs;// + 0.5; + *bo -= (po * (f->be - f->bs)) + f->bs;// + 0.5; + } + else + { + *ro += (po * (f->re - f->rs)) + f->rs;// + 0.5; + *go += (po * (f->ge - f->gs)) + f->gs;// + 0.5; + *bo += (po * (f->be - f->bs)) + f->bs;// + 0.5; + } + f++; + } } -#define LED_UPDATE_RATE 10 //ms - -//led data processing can take time, so process data in chunks to free up the processor -//this is done through led_cur and lede -void led_matrix_task(void) +static void led_matrix_massdrop_config_override(int i) { - if (led_enabled) - { - //If an update may run and frame processing has completed - if (timer_read64() >= led_next_run && led_cur == lede) - { - uint8_t drvid; + float ro = 0; + float go = 0; + float bo = 0; + + float po = (led_animation_orientation) + ? (float)g_rgb_leds[i].point.y / 64.f * 100 + : (float)g_rgb_leds[i].point.x / 224.f * 100; + + uint8_t highest_active_layer = biton32(layer_state); + + if (led_lighting_mode == LED_MODE_KEYS_ONLY && g_rgb_leds[i].matrix_co.raw == 0xff) { + //Do not act on this LED + } else if (led_lighting_mode == LED_MODE_NON_KEYS_ONLY && g_rgb_leds[i].matrix_co.raw != 0xff) { + //Do not act on this LED + } else if (led_lighting_mode == LED_MODE_INDICATORS_ONLY) { + //Do not act on this LED (Only show indicators) + } else { + led_instruction_t* led_cur_instruction = led_instructions; + while (!led_cur_instruction->end) { + // Check if this applies to current layer + if ((led_cur_instruction->flags & LED_FLAG_MATCH_LAYER) && + (led_cur_instruction->layer != highest_active_layer)) { + goto next_iter; + } - led_next_run = timer_read64() + LED_UPDATE_RATE; //Set next frame update time + // Check if this applies to current index + if (led_cur_instruction->flags & LED_FLAG_MATCH_ID) { + uint8_t modid = i / 32; //Calculate which id# contains the led bit + uint32_t modidbit = 1 << (i % 32); //Calculate the bit within the id# + uint32_t *bitfield = &led_cur_instruction->id0 + modid; //Add modid as offset to id0 address. *bitfield is now idX of the led id + if (~(*bitfield) & modidbit) { //Check if led bit is not set in idX + goto next_iter; + } + } - //NOTE: GCR does not need to be timed with LED processing, but there is really no harm - if (gcr_actual != gcr_actual_last) - { - for (drvid=0;drvidflags & LED_FLAG_USE_RGB) { + ro = led_cur_instruction->r; + go = led_cur_instruction->g; + bo = led_cur_instruction->b; + } else if (led_cur_instruction->flags & LED_FLAG_USE_PATTERN) { + led_run_pattern(led_setups[led_cur_instruction->pattern_id], &ro, &go, &bo, po); + } else if (led_cur_instruction->flags & LED_FLAG_USE_ROTATE_PATTERN) { + led_run_pattern(led_setups[led_animation_id], &ro, &go, &bo, po); } - for (drvid=0;drvid 255) ro = 255; else if (ro < 0) ro = 0; + if (go > 255) go = 255; else if (go < 0) go = 0; + if (bo > 255) bo = 255; else if (bo < 0) bo = 0; - led_cur = 0; //Signal next frame calculations may begin + if (led_animation_breathing) + { + ro *= breathe_mult; + go *= breathe_mult; + bo *= breathe_mult; } } - //Process more data if not finished - if (led_cur != lede) - { - //DBG_1_OFF; //debug profiling - led_matrix_run(); - //DBG_1_ON; //debug profiling - } + led_buffer[i].r = (uint8_t)ro; + led_buffer[i].g = (uint8_t)go; + led_buffer[i].b = (uint8_t)bo; } +#endif // USE_MASSDROP_CONFIGURATOR -- cgit v1.2.3-24-g4f1b