/* RGB BackLight Service based on RGB backlight FlipperZero driver Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include "rgb_backlight.h" #define COLOR_COUNT (sizeof(colors) / sizeof(RGBBacklightColor)) #define TAG "RGB_BACKLIGHT_SRV" static const RGBBacklightColor colors[] = { {"Orange", 255, 60, 0}, {"Yellow", 255, 144, 0}, {"Spring", 167, 255, 0}, {"Lime", 0, 255, 0}, {"Aqua", 0, 255, 127}, {"Cyan", 0, 210, 210}, {"Azure", 0, 127, 255}, {"Blue", 0, 0, 255}, {"Purple", 127, 0, 255}, {"Magenta", 210, 0, 210}, {"Pink", 255, 0, 127}, {"Red", 255, 0, 0}, {"White", 254, 210, 200}, {"Custom", 0, 0, 0}, }; uint8_t rgb_backlight_get_color_count(void) { return COLOR_COUNT; } const char* rgb_backlight_get_color_text(uint8_t index) { return colors[index].name; } // use RECORD for acces to rgb service instance and update current colors by static void rgb_backlight_set_static_color(uint8_t index) { RGBBacklightApp* app = furi_record_open(RECORD_RGB_BACKLIGHT); //if user select "custom" value then set current colors by custom values if(index == 13) { app->current_red = app->settings->custom_red; app->current_green = app->settings->custom_green; app->current_blue = app->settings->custom_blue; } else { app->current_red = colors[index].red; app->current_green = colors[index].green; app->current_blue = colors[index].blue; } furi_record_close(RECORD_RGB_BACKLIGHT); } // use RECORD for acces to rgb service instance and update current colors by custom void rgb_backlight_set_custom_color(uint8_t red, uint8_t green, uint8_t blue) { RGBBacklightApp* app = furi_record_open(RECORD_RGB_BACKLIGHT); app->current_red = red; app->current_green = green; app->current_blue = blue; furi_record_close(RECORD_RGB_BACKLIGHT); } // use RECORD for acces to rgb service instance, use current_* colors and update backlight void rgb_backlight_update(float brightness) { RGBBacklightApp* app = furi_record_open(RECORD_RGB_BACKLIGHT); for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { uint8_t r = app->current_red * (brightness / 1.0f); uint8_t g = app->current_green * (brightness / 1.0f); uint8_t b = app->current_blue * (brightness / 1.0f); SK6805_set_led_color(i, r, g, b); } SK6805_update(); furi_record_close(RECORD_RGB_BACKLIGHT); } //start furi timer for rainbow void rainbow_timer_start(RGBBacklightApp* app) { furi_timer_start(app->rainbow_timer, furi_ms_to_ticks(app->settings->rainbow_speed_ms)); } //stop furi timer for rainbow void rainbow_timer_stop(RGBBacklightApp* app) { furi_timer_stop(app->rainbow_timer); } // if rgb_mod_installed then apply rainbow colors to backlight and start/restart/stop rainbow_timer void rainbow_timer_starter(RGBBacklightApp* app) { if((app->settings->rainbow_mode > 0) && (app->settings->rgb_mod_installed)) { rainbow_timer_start(app); } else { if(furi_timer_is_running(app->rainbow_timer)) { rainbow_timer_stop(app); } } } static void rainbow_timer_callback(void* context) { furi_assert(context); RGBBacklightApp* app = context; // if rainbow_mode is rainbow do rainbow effect if(app->settings->rainbow_mode == 1) { switch(app->rainbow_stage) { // from red to yellow (255,0,0) - (255,255,0) case 1: app->current_green += app->settings->rainbow_step; if(app->current_green >= 255) { app->current_green = 255; app->rainbow_stage++; } break; // yellow to green (255,255,0) - (0,255,0) case 2: app->current_red -= app->settings->rainbow_step; if(app->current_red <= 0) { app->current_red = 0; app->rainbow_stage++; } break; // from green to light blue (0,255,0) - (0,255,255) case 3: app->current_blue += app->settings->rainbow_step; if(app->current_blue >= 255) { app->current_blue = 255; app->rainbow_stage++; } break; //from light blue to blue (0,255,255) - (0,0,255) case 4: app->current_green -= app->settings->rainbow_step; if(app->current_green <= 0) { app->current_green = 0; app->rainbow_stage++; } break; //from blue to violet (0,0,255) - (255,0,255) case 5: app->current_red += app->settings->rainbow_step; if(app->current_red >= 255) { app->current_red = 255; app->rainbow_stage++; } break; //from violet to red (255,0,255) - (255,0,0) case 6: app->current_blue -= app->settings->rainbow_step; if(app->current_blue <= 0) { app->current_blue = 0; app->rainbow_stage = 1; } break; default: break; } } rgb_backlight_update(app->settings->brightness); // if rainbow_mode is ..... do another effect // if(app->settings.rainbow_mode == ...) { // } } int32_t rgb_backlight_srv(void* p) { UNUSED(p); // Define object app (full app with settings and running variables), // allocate memory and create RECORD for access to app structure from outside RGBBacklightApp* app = malloc(sizeof(RGBBacklightApp)); furi_record_create(RECORD_RGB_BACKLIGHT, app); //define rainbow_timer and they callback app->rainbow_timer = furi_timer_alloc(rainbow_timer_callback, FuriTimerTypePeriodic, app); // settings load or create default app->settings = malloc(sizeof(RGBBacklightSettings)); rgb_backlight_settings_load(app->settings); // Init app variables app->rainbow_stage = 1; // if rgb mod installed - start rainbow or set static color from settings (default index = 0) if(app->settings->rgb_mod_installed) { if(app->settings->rainbow_mode > 0) { rainbow_timer_starter(app); } else { rgb_backlight_set_static_color(app->settings->static_color_index); rgb_backlight_update(app->settings->brightness); } // if rgb mod not installed - set default static orange color (index=0) } else { rgb_backlight_set_static_color(0); rgb_backlight_update(app->settings->brightness); } while(1) { // place for message queue and other future options furi_delay_ms(5000); FURI_LOG_I(TAG, "Service is running"); } return 0; }