#include "ATALights.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" #include #include #include "Animations.h" #include #include "system.h" #include "ColorPalettes.h" #include "global.h" //#include #include "PWM_Output.h" #include "my_device.h" #include "system.h" #include "my_device.h" #define FASTLED_CORE 0 static const char* tag = "strips"; uint32_t whiteTimeout = 0; TaskHandle_t Animation_Task_Handle; TaskHandle_t Ramp_Front_Light_Task_Handle; LEDSTRIP_SETTINGS ledSettings[2]; volatile bool AnimationLooping = false; ANIM_EVENT prevAnimEvent = {0}; QueueHandle_t animationQueue = xQueueCreate( 4, sizeof( ANIM_EVENT ) ); bool fillAnimationActive = false; void RGB_Lights_Set_Animation(int animIndex, uint8_t red, uint8_t grn, uint8_t blu){ // Trigger to exit curring looping animation if(AnimationLooping){ AnimationLooping = false; xTaskNotifyGive( Animation_Task_Handle ); } ANIM_EVENT event; event.AnimationIndex = animIndex; event.data.red = red; event.data.grn = grn; event.data.blu = blu; event.data.wht = 0; xQueueSend( animationQueue, &event, 25 ); } void RGB_Animations_ON(){ RGB_Lights_Set_Animation(prevAnimEvent.AnimationIndex, prevAnimEvent.data.red, prevAnimEvent.data.grn, prevAnimEvent.data.blu); } void RGB_Animations_OFF(){ RGB_Lights_Set_Animation(OFF_INDEX, 0, 0, 0); } void RGB_Lights_Set_Brightness(uint8_t scale){ FastLED.setBrightness(scale); } // Set the white LEDs brightness (0-255) void Lights_Set_White(uint8_t val){ //pwmOut[0]->setOutput(val / 2.5f); } void Init_RGB_Lights_Task(void){ ledSettings[0].leds = new CRGB[ledSettings[0].size]; Init_RGB_Strip(ledSettings[0].leds, ledSettings[0].pin, ledSettings[0].size, ledSettings[0].rgbOrder, ledSettings[0].chip, ledSettings[0].bright); ESP_LOGD(tag, "Initializing Strip1: Pin: %d, size: %d, order: %s, chip: %s", ledSettings[0].pin, ledSettings[0].size, ledSettings[0].rgbOrder, ledSettings[0].chip); ledSettings[1].leds = new CRGB[ledSettings[1].size];; Init_RGB_Strip(ledSettings[1].leds, ledSettings[1].pin, ledSettings[1].size, ledSettings[1].rgbOrder, ledSettings[1].chip, ledSettings[1].bright); ESP_LOGD(tag, "Initializing Strip2: Pin: %d, size: %d, order: %s, chip: %s", ledSettings[1].pin, ledSettings[1].size, ledSettings[1].rgbOrder, ledSettings[1].chip); xTaskCreatePinnedToCore(RGB_Lights_Control_Task, "Lights_Task", 1024*6, NULL, 1, &Animation_Task_Handle, FASTLED_CORE); ESP_LOGI(tag, "Lights Task Created..."); } /* void Init_Ramp_Front_Light_Task(void){ // Check if pwmOutputs[0] is available before creating the task if(pwmOutputs[0] == nullptr) { ESP_LOGE(tag, "Cannot create Ramp Front Light Task: pwmOutputs[0] is not initialized"); return; } // Create task with moderate stack size - 2KB should be sufficient BaseType_t result = xTaskCreatePinnedToCore(Ramp_Front_Light_Control_Task, "Ramp_Front_Light_Task", 1024*2, NULL, 1, &Ramp_Front_Light_Task_Handle, (FASTLED_CORE ? 1 : 0)); if(result != pdPASS) { ESP_LOGE(tag, "Failed to create Ramp Front Light Task, error: %d", result); Ramp_Front_Light_Task_Handle = NULL; } else { ESP_LOGI(tag, "Ramp Front Light Task Created..."); } } */ /* #define RAMP_INTERVAL 25 #define FRONTLIGHT_TIMEOUT 20000 int startDelay = 0; int rampTime = 0; bool rampRestart = false; float FrontLightMin = 0.0; void Ramp_Front_Light_Control_Task(void *parameters) { float currPwmValue = 0.0; float outValue = 0.0; int timeCounter = 0; while(1) { if(rampRestart == false){ vTaskSuspend(NULL); // Wait to be triggered } rampRestart = false; // Clear the flag immediately // Safety check: Ensure pwmOutputs[0] is initialized if(pwmOutputs[0] == nullptr) { ESP_LOGE(tag, "pwmOutputs[0] is null, cannot control front light"); rampRestart = false; continue; } // Wait for start delay to finish while(!rampRestart && fillAnimationActive && startDelay > 0){ vTaskDelay(10 / portTICK_PERIOD_MS); startDelay -= 10; } if(rampRestart){ continue; // Restart if requested during delay } //currPwmValue = pwmOutputs[0]->getDuty(); // Get current PWM value currPwmValue = FrontLightMin; // Always start from min value pwmOutputs[0]->setOutput(currPwmValue); // Ensure starting point is set // Ramp Up the Front Light linearly timeCounter = 0; // Reset timer for ramp up int rampMs = rampTime; while(!rampRestart && fillAnimationActive && rampMs > 0){ timeCounter += RAMP_INTERVAL; outValue = map(timeCounter, 0, rampTime, currPwmValue, 100); pwmOutputs[0]->setOutput(outValue); vTaskDelay(RAMP_INTERVAL / portTICK_PERIOD_MS); rampMs -= RAMP_INTERVAL; } if(rampRestart){ continue; // Restart the ramp up if requested } // Max Wait fill animation to end or timeout int frontLightTimeout = FRONTLIGHT_TIMEOUT; while(!rampRestart && fillAnimationActive && frontLightTimeout > 0){ vTaskDelay(10 / portTICK_PERIOD_MS); frontLightTimeout -= 10; } if(rampRestart){ pwmOutputs[0]->setOutput(0); // Ensure it's fully off continue; // Restart the ramp up if requested } // Ramp Down the Front Light linearly timeCounter = 0; // Reset timer for ramp down rampMs = rampTime; while(!rampRestart && fillAnimationActive && rampMs > 0){ timeCounter += RAMP_INTERVAL; outValue = map(timeCounter, 0, rampTime, 100 , currPwmValue); pwmOutputs[0]->setOutput(outValue); vTaskDelay(RAMP_INTERVAL / portTICK_PERIOD_MS); rampMs -= RAMP_INTERVAL; } // Cycle completed - ensure clean final state if(!rampRestart){ pwmOutputs[0]->setOutput(FrontLightMin); // Ensure final state is minimum fillAnimationActive = false; // Clear animation flag } } } void Start_RampUp_Front_Light(int _rampTime, int _startDelay) { // Check if the task exists before trying to control it if(Ramp_Front_Light_Task_Handle == NULL) { ESP_LOGW(tag, "Cannot start front light ramp: task not created"); return; } rampTime = _rampTime; startDelay = _startDelay; fillAnimationActive = true; rampRestart = true; vTaskResume(Ramp_Front_Light_Task_Handle); } */ void Animation_Loop_Exit(void){ if( Animation_Task_Handle ){ xTaskNotifyGive( Animation_Task_Handle ); } } EOrder GetEOrderByString(const String& rgbStr){ ESP_LOGI(tag, "EOrder is %s", rgbStr.c_str()); if (rgbStr.equalsIgnoreCase("RGB")) return RGB; else if (rgbStr.equalsIgnoreCase("RBG")) return RBG; else if (rgbStr.equalsIgnoreCase("GRB")) return GRB; else if (rgbStr.equalsIgnoreCase("GBR")) return GBR; else if (rgbStr.equalsIgnoreCase("BRG")) return BRG; else if (rgbStr.equalsIgnoreCase("BGR")) return BGR; else return RGB; // Default case } /* void setPixel(LEDSTRIP_SETTINGS& strip, int pixelIndex, CRGB col){ int x = calcPixelIndex(strip, pixelIndex); leds1[x] = col; } inline int calcPixelIndex(LEDSTRIP_SETTINGS& strip, int index) { int x = (index + strip.shift) % strip.effSize; x = (x < 0) ? (x + strip.effSize) : x; return (x +strip.offset) % strip.effSize; } */ inline void setPixel1(LEDSTRIP_SETTINGS& leds, int pixelIndex, const CRGB col) { register uint16_t x = pixelIndex + ledSettings[0].shift; // If strip.effSize is power of 2, use faster bit masking if ((leds.effSize & (leds.effSize - 1)) == 0) { x = (x < 0) ? ((x + leds.effSize) & (leds.effSize - 1)) : (x & (leds.effSize - 1)); leds.leds[(x + leds.offset) & (leds.effSize - 1)] = col; } else { // For non-power-of-2 sizes, still need modulo x = (x < 0) ? ((x + ledSettings[0].effSize) % ledSettings[0].effSize) : (x % ledSettings[0].effSize); ledSettings[0].leds[(x + ledSettings[0].offset) % ledSettings[0].effSize] = col; } } inline void setPixel2(int pixelIndex, const CRGB col) { register uint16_t x = pixelIndex + ledSettings[1].shift; // If strip.effSize is power of 2, use faster bit masking if ((ledSettings[1].effSize & (ledSettings[1].effSize - 1)) == 0) { x = (x < 0) ? ((x + ledSettings[1].effSize) & (ledSettings[1].effSize - 1)) : (x & (ledSettings[1].effSize - 1)); ledSettings[1].leds[(x + ledSettings[1].offset) & (ledSettings[1].effSize - 1)] = col; } else { // For non-power-of-2 sizes, still need modulo x = (x < 0) ? ((x + ledSettings[1].effSize) % ledSettings[1].effSize) : (x % ledSettings[1].effSize); ledSettings[1].leds[(x + ledSettings[1].offset) % ledSettings[1].effSize] = col; } } void Init_RGB_Strip(CRGB* leds, uint8_t pin, int size, const String& colorOrder, const String& chipType, uint8_t bright) { // Validate inputs if (!leds || size <= 0) { ESP_LOGE(tag, "Invalid LED array or size"); return; } // Convert strings to uppercase once String chipUpper = chipType; String orderUpper = colorOrder; chipUpper.toUpperCase(); orderUpper.toUpperCase(); // Validate pin (using AND for correct logic) if (pin != 3 && pin != 9 && pin != 46) { ESP_LOGW(tag, "Invalid pin %d, defaulting to 3", pin); pin = 3; } EOrder rgbOrder = GetEOrderByString(orderUpper); if(pin == 3){ // First level: Chip type selection if (chipUpper == "WS2812B" || chipUpper == "SK6812") { switch(rgbOrder) { case RGB: FastLED.addLeds(leds, size); break; case RBG: FastLED.addLeds(leds, size); break; case GRB: FastLED.addLeds(leds, size); break; case GBR: FastLED.addLeds(leds, size); break; case BRG: FastLED.addLeds(leds, size); break; case BGR: FastLED.addLeds(leds, size); break; default: FastLED.addLeds(leds, size); break; } } else if (chipUpper == "SK6812") { switch(rgbOrder) { case RGB: FastLED.addLeds(leds, size); break; case RBG: FastLED.addLeds(leds, size); break; case GRB: FastLED.addLeds(leds, size); break; case GBR: FastLED.addLeds(leds, size); break; case BRG: FastLED.addLeds(leds, size); break; case BGR: FastLED.addLeds(leds, size); break; default: FastLED.addLeds(leds, size); break; } } else if (chipUpper == "WS2811_400") { switch(rgbOrder) { case RGB: FastLED.addLeds(leds, size); break; case RBG: FastLED.addLeds(leds, size); break; case GRB: FastLED.addLeds(leds, size); break; case GBR: FastLED.addLeds(leds, size); break; case BRG: FastLED.addLeds(leds, size); break; case BGR: FastLED.addLeds(leds, size); break; default: FastLED.addLeds(leds, size); break; } } else if (chipUpper == "WS2815") { switch(rgbOrder) { case RGB: FastLED.addLeds(leds, size); break; case RBG: FastLED.addLeds(leds, size); break; case GRB: FastLED.addLeds(leds, size); break; case GBR: FastLED.addLeds(leds, size); break; case BRG: FastLED.addLeds(leds, size); break; case BGR: FastLED.addLeds(leds, size); break; default: FastLED.addLeds(leds, size); break; } } else { // Default to WS2812B if unknown chip type ESP_LOGW(tag, "Unknown LED chip type: %s, defaulting to WS2812B", chipType.c_str()); FastLED.addLeds(leds, size); } ESP_LOGI(tag, "Initialized %s LED strip with %d LEDs on pin %d", chipType.c_str(), size, pin); } else if(pin == 9){ // First level: Chip type selection if (chipUpper == "WS2812B") { switch(rgbOrder) { case RGB: FastLED.addLeds(leds, size); break; case RBG: FastLED.addLeds(leds, size); break; case GRB: FastLED.addLeds(leds, size); break; case GBR: FastLED.addLeds(leds, size); break; case BRG: FastLED.addLeds(leds, size); break; case BGR: FastLED.addLeds(leds, size); break; default: FastLED.addLeds(leds, size); break; } } else if (chipUpper == "SK6812") { switch(rgbOrder) { case RGB: FastLED.addLeds(leds, size); break; case RBG: FastLED.addLeds(leds, size); break; case GRB: FastLED.addLeds(leds, size); break; case GBR: FastLED.addLeds(leds, size); break; case BRG: FastLED.addLeds(leds, size); break; case BGR: FastLED.addLeds(leds, size); break; default: FastLED.addLeds(leds, size); break; } } else if (chipUpper == "WS2811_400") { switch(rgbOrder) { case RGB: FastLED.addLeds(leds, size); break; case RBG: FastLED.addLeds(leds, size); break; case GRB: FastLED.addLeds(leds, size); break; case GBR: FastLED.addLeds(leds, size); break; case BRG: FastLED.addLeds(leds, size); break; case BGR: FastLED.addLeds(leds, size); break; default: FastLED.addLeds(leds, size); break; } } else if (chipUpper == "WS2815") { switch(rgbOrder) { case RGB: FastLED.addLeds(leds, size); break; case RBG: FastLED.addLeds(leds, size); break; case GRB: FastLED.addLeds(leds, size); break; case GBR: FastLED.addLeds(leds, size); break; case BRG: FastLED.addLeds(leds, size); break; case BGR: FastLED.addLeds(leds, size); break; default: FastLED.addLeds(leds, size); break; } } else { // Default to WS2812B if unknown chip type ESP_LOGW(tag, "Unknown LED chip type: %s, defaulting to WS2812B", chipType.c_str()); FastLED.addLeds(leds, size); } ESP_LOGI(tag, "Initialized %s LED strip with %d LEDs on pin %d", chipType.c_str(), size, pin); } else if(pin == 46){ // First level: Chip type selection if (chipUpper == "WS2812B" || chipUpper == "SK6812") { switch(rgbOrder) { case RGB: FastLED.addLeds(leds, size); break; case RBG: FastLED.addLeds(leds, size); break; case GRB: FastLED.addLeds(leds, size); break; case GBR: FastLED.addLeds(leds, size); break; case BRG: FastLED.addLeds(leds, size); break; case BGR: FastLED.addLeds(leds, size); break; default: FastLED.addLeds(leds, size); break; } } else if (chipUpper == "SK6812") { switch(rgbOrder) { case RGB: FastLED.addLeds(leds, size); break; case RBG: FastLED.addLeds(leds, size); break; case GRB: FastLED.addLeds(leds, size); break; case GBR: FastLED.addLeds(leds, size); break; case BRG: FastLED.addLeds(leds, size); break; case BGR: FastLED.addLeds(leds, size); break; default: FastLED.addLeds(leds, size); break; } } else if (chipUpper == "WS2811_400") { switch(rgbOrder) { case RGB: FastLED.addLeds(leds, size); break; case RBG: FastLED.addLeds(leds, size); break; case GRB: FastLED.addLeds(leds, size); break; case GBR: FastLED.addLeds(leds, size); break; case BRG: FastLED.addLeds(leds, size); break; case BGR: FastLED.addLeds(leds, size); break; default: FastLED.addLeds(leds, size); break; } } else if (chipUpper == "WS2815") { switch(rgbOrder) { case RGB: FastLED.addLeds(leds, size); break; case RBG: FastLED.addLeds(leds, size); break; case GRB: FastLED.addLeds(leds, size); break; case GBR: FastLED.addLeds(leds, size); break; case BRG: FastLED.addLeds(leds, size); break; case BGR: FastLED.addLeds(leds, size); break; default: FastLED.addLeds(leds, size); break; } } else { // Default to WS2812B if unknown chip type ESP_LOGW(tag, "Unknown LED chip type: %s, defaulting to WS2812B", chipType.c_str()); FastLED.addLeds(leds, size); } ESP_LOGI(tag, "Initialized %s LED strip with %d LEDs on pin %d", chipType.c_str(), size, pin); } FastLED.setBrightness(bright); } void RGB_Lights_Control_Task(void *parameters){ ANIM_EVENT AnimEvent; CRGB col; COLOR_PACK colorPack; CRGBPalette16 firePalette; // Wait for other tasks to initialize (including front light task) vTaskDelay(pdMS_TO_TICKS(500)); // wait for everything to settle RGB_Lights_Set_Brightness(48); RGB_Lights_Set_Animation(23, 0, 0, 0); // set comet rainbow animation while (true) { if (xQueueReceive(animationQueue, &AnimEvent, portMAX_DELAY) == pdTRUE) { ESP_LOGI(tag, "New Animation Event: Index: %d", AnimEvent.AnimationIndex); switch (AnimEvent.AnimationIndex) { case -3: // Set Pixel by index if (AnimEvent.data.data[7] >= 0 && AnimEvent.data.data[7] < ledSettings[0].size) { ledSettings[0].leds[AnimEvent.data.data[7]] = CRGB(AnimEvent.data.red, AnimEvent.data.grn, AnimEvent.data.blu); FastLED.show(); } else { ESP_LOGW(tag, "Pixel index out of range: %d", AnimEvent.data.data[7]); } break; case -2: // Fill Static Color col = CRGB(AnimEvent.data.red, AnimEvent.data.grn, AnimEvent.data.blu); fill_solid(ledSettings[0].leds, ledSettings[0].size, col); FastLED.show(); ESP_LOGD(tag, "Static Color"); break; case -1: FastLED.clear(); FastLED.show(); ESP_LOGD(tag, "LEDs Off"); break; case 0: fill_solid(ledSettings[0].leds, ledSettings[0].size, CRGB::Black); FastLED.show(); break; case 1: case 2: case 3: case 4: case 5:{ // Timed Fill Animations int timeDuration = AnimEvent.AnimationIndex * 1000; int whiteDelay = timeDuration - 1000; Anim_TimedFill_Flash(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, pwmOutputs[0], &sys_settings.pwmOutSettings[0], whiteDelay, 10000, CRGB::Black, CRGB::White, timeDuration, ledSettings[0].shift); break; } case 6: // RGB White and Dedicated White all on with timeout and brightness reduction if (pwmOutputs[0] != nullptr) { Anim_SolidWhite(AnimationLooping, ledSettings[0].leds, pwmOutputs[0], ledSettings[0].size, 240, 30000); } break; case 7: Anim_Rainbow(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, 60); break; case 8: case 9: case 10: case 11: case 12: Anim_GradientRotate(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, gradient_colorPack[AnimEvent.AnimationIndex - 8], 80); break; case 13: case 14: case 15: case 16: case 17: { // Fire Animations COLOR_PACK fp = fireColorPacks[AnimEvent.AnimationIndex - 13]; // copy const pack to mutable createFirePalette(firePalette, fp); Anim_Fire(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, 60, firePalette, ledSettings[0].shift); break; } case 18: case 19: case 20:// Sparkle/Twinkle Anim_Sparkle(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[0], 40, 20); break; case 21: //Anim_ColorBreath(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 7000, 90); Anim_Morph(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 20, 40); break; case 22: // Rain Animation break; // Comets case 23: Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 40, 85, RANDOM_DECAY, 1); break; case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 24], 40, 85, RANDOM_DECAY, 6); break; case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 32], 40, 85, RANDOM_DECAY, 3); break; case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 41], 40, 85, RANDOM_DECAY, 2); break; // Snakes case 50: Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 50); break; case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 51], 60, 6); break; case 59: case 60: case 61: case 62: case 63: case 64: case 65: case 66: case 67: Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 59], 60, 3); break; case 68: case 69: case 70: case 71: case 72: case 73: case 74: case 75: case 76: Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 68], 60, 2); break; // Sectors case 77: Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, NO_GAPS, 1, 40, 90); break; case 78: case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 78], NO_GAPS, 3, 40, 90); break; case 87: case 88: case 89: case 90: case 91: case 92: case 93: case 94: case 95: Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 87], NO_GAPS, 2, 40, 90); break; // Dashes case 96: Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, WITH_GAPS, 1, 40, 90); break; case 97:case 98:case 99: case 100: case 101: case 102: case 103: case 104: Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 97], WITH_GAPS, 6, 40, 90); break; case 105: case 106: case 107: case 108: case 109: case 110: case 111: case 112: case 113: Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 105], WITH_GAPS, 3, 40, 90); break; case 114: case 115: case 116: case 117: case 118: case 119: case 120: case 121: case 122: Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 114], WITH_GAPS, 2, 40, 90); break; default: ESP_LOGW(tag, "Loop default"); break; } AnimationLooping = false; prevAnimEvent = AnimEvent; ESP_LOGD(tag, "Going to Queue to Wait"); } } } void createFirePalette(CRGBPalette16& palette, const COLOR_PACK& colorPack) { for (uint8_t i = 0; i < 16; i++) { if (i < 3) palette[i] = CRGB::Black; else if (i < 7) palette[i] = colorPack.col[0]; else if (i < 10) palette[i] = colorPack.col[1]; else if (i < 15) palette[i] = colorPack.col[2]; else palette[i] = CRGB::White; } } void loadColorPack(COLOR_PACK& dest, const COLOR_PACK& src) { memcpy_P(&dest, &src, sizeof(COLOR_PACK)); }