diff --git a/applications/services/application.fam b/applications/services/application.fam index 90631408a..8cfb22cdb 100644 --- a/applications/services/application.fam +++ b/applications/services/application.fam @@ -11,5 +11,6 @@ App( "loader", "power", "namechanger_srv", + "rgb_backlight", ], ) diff --git a/applications/services/input/input.c b/applications/services/input/input.c index 41759a1dd..93c5d1867 100644 --- a/applications/services/input/input.c +++ b/applications/services/input/input.c @@ -157,8 +157,10 @@ int32_t input_srv(void* p) { // Send Press/Release event event.type = pin_states[i].state ? InputTypePress : InputTypeRelease; furi_pubsub_publish(event_pubsub, &event); - // do vibro if user setup vibro touch level in Settings-Input. + // vibro signal if user setup vibro touch level in Settings-Input. if(settings->vibro_touch_level) { + //delay 1 ticks for compatibility with rgb_backlight_mod + furi_delay_tick(1); furi_hal_vibro_on(true); furi_delay_tick(settings->vibro_touch_level); furi_hal_vibro_on(false); diff --git a/applications/services/input/input_settings.c b/applications/services/input/input_settings.c index cd3de6d50..f1f18ba3d 100644 --- a/applications/services/input/input_settings.c +++ b/applications/services/input/input_settings.c @@ -30,7 +30,6 @@ void input_settings_load(InputSettings* settings) { sizeof(InputSettings), INPUT_SETTINGS_MAGIC, INPUT_SETTINGS_VER); - // if config previous version - load it and inicialize new settings } // in case of another config version we exit from useless cycle to next step } while(false); diff --git a/applications/services/notification/application.fam b/applications/services/notification/application.fam index 82f94085a..fbfdca848 100644 --- a/applications/services/notification/application.fam +++ b/applications/services/notification/application.fam @@ -4,7 +4,7 @@ App( apptype=FlipperAppType.SERVICE, entry_point="notification_srv", cdefines=["SRV_NOTIFICATION"], - requires=["input"], + requires=["input","rgb_backlight"], provides=["notification_settings"], stack_size=int(1.5 * 1024), order=100, diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 35d2fe675..cf03d4389 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -9,6 +9,7 @@ #include "notification.h" #include "notification_messages.h" #include "notification_app.h" +#include "applications/services/rgb_backlight/rgb_backlight.h" #define TAG "NotificationSrv" @@ -218,12 +219,20 @@ static void notification_process_notification_message( &app->display, notification_message->data.led.value * display_brightness_setting); reset_mask |= reset_display_mask; + + //start rgb_mod_rainbow_timer when display backlight is ON and all corresponding settings is ON too + rainbow_timer_starter(app->rgb_srv); + } else { reset_mask &= ~reset_display_mask; notification_reset_notification_led_layer(&app->display); if(furi_timer_is_running(app->display_timer)) { furi_timer_stop(app->display_timer); } + //stop rgb_mod_rainbow_timer when display backlight is OFF + if(furi_timer_is_running(app->rgb_srv->rainbow_timer)) { + rainbow_timer_stop(app->rgb_srv); + } } break; case NotificationMessageTypeLedDisplayBacklightEnforceOn: @@ -591,7 +600,7 @@ static void notification_init_settings(NotificationApp* app) { int32_t notification_srv(void* p) { UNUSED(p); NotificationApp* app = notification_app_alloc(); - + app->rgb_srv = furi_record_open(RECORD_RGB_BACKLIGHT); notification_init_settings(app); notification_vibro_off(); diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index e19546574..0209ffa0b 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -3,6 +3,7 @@ #include "notification.h" #include "notification_messages.h" #include "notification_settings_filename.h" +#include "applications/services/rgb_backlight/rgb_backlight.h" #define NOTIFICATION_LED_COUNT 3 #define NOTIFICATION_EVENT_COMPLETE 0x00000001U @@ -33,7 +34,7 @@ typedef struct { Light light; } NotificationLedLayer; -#define NOTIFICATION_SETTINGS_VERSION 0x02 +#define NOTIFICATION_SETTINGS_VERSION 0x03 #define NOTIFICATION_SETTINGS_PATH INT_PATH(NOTIFICATION_SETTINGS_FILE_NAME) typedef struct { @@ -56,6 +57,7 @@ struct NotificationApp { uint8_t display_led_lock; NotificationSettings settings; + RGBBacklightApp* rgb_srv; }; -void notification_message_save_settings(NotificationApp* app); +void notification_message_save_settings(NotificationApp* app); \ No newline at end of file diff --git a/applications/services/rgb_backlight/application.fam b/applications/services/rgb_backlight/application.fam new file mode 100644 index 000000000..5e05233db --- /dev/null +++ b/applications/services/rgb_backlight/application.fam @@ -0,0 +1,10 @@ +App( + appid="rgb_backlight", + name="RgbBackLightSrv", + apptype=FlipperAppType.SERVICE, + entry_point="rgb_backlight_srv", + cdefines=["SRV_RGB_BACKLIGHT"], + stack_size=1 * 1024, + order=95, + sdk_headers=["rgb_backlight.h"], +) \ No newline at end of file diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c new file mode 100644 index 000000000..5510ea916 --- /dev/null +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -0,0 +1,221 @@ +/* + 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; +} diff --git a/applications/services/rgb_backlight/rgb_backlight.h b/applications/services/rgb_backlight/rgb_backlight.h new file mode 100644 index 000000000..fd683bf16 --- /dev/null +++ b/applications/services/rgb_backlight/rgb_backlight.h @@ -0,0 +1,61 @@ +/* + 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 . +*/ + +#pragma once +#include +#include "rgb_backlight_settings.h" +#include "SK6805.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + char* name; + uint8_t red; + uint8_t green; + uint8_t blue; +} RGBBacklightColor; + +typedef struct { + FuriTimer* rainbow_timer; + + int16_t current_red; + int16_t current_green; + int16_t current_blue; + uint8_t rainbow_stage; + + RGBBacklightSettings* settings; + +} RGBBacklightApp; + +#define RECORD_RGB_BACKLIGHT "rgb_backlight" + +void rgb_backlight_update(float brightness); +void rgb_backlight_set_custom_color(uint8_t red, uint8_t green, uint8_t blue); +void rgb_backlight_set_static_color(uint8_t index); +void rainbow_timer_stop(RGBBacklightApp* app); +void rainbow_timer_start(RGBBacklightApp* app); +void rainbow_timer_starter(RGBBacklightApp* app); +const char* rgb_backlight_get_color_text(uint8_t index); +uint8_t rgb_backlight_get_color_count(void); + +#ifdef __cplusplus +} +#endif diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.c b/applications/services/rgb_backlight/rgb_backlight_settings.c new file mode 100644 index 000000000..7e69eb0dc --- /dev/null +++ b/applications/services/rgb_backlight/rgb_backlight_settings.c @@ -0,0 +1,101 @@ +#include "rgb_backlight_settings.h" + +#include +#include + +#define TAG "RGBBackligthSettings" + +#define RGB_BACKLIGHT_SETTINGS_FILE_NAME ".rgb_backlight.settings" +#define RGB_BACKLIGHT_SETTINGS_PATH INT_PATH(RGB_BACKLIGHT_SETTINGS_FILE_NAME) + +#define RGB_BACKLIGHT_SETTINGS_MAGIC (0x30) +#define RGB_BACKLIGHT_SETTINGS_VER_PREV (0) // Previous version number +#define RGB_BACKLIGHT_SETTINGS_VER (1) // New version number + +//pervious settings must be copyed from previous rgb_backlight_settings.h file +typedef struct { + uint8_t version; + bool rgb_mod_installed; + + uint8_t static_color_index; + uint8_t custom_r; + uint8_t custom_g; + uint8_t custom_b; + + uint32_t rainbow_mode; + uint32_t rainbow_speed_ms; + uint16_t rainbow_step; +} RGBBacklightSettingsPrevious; + +void rgb_backlight_settings_load(RGBBacklightSettings* settings) { + furi_assert(settings); + + bool success = false; + + //a useless cycle do-while, may will be used in future with anoter condition + do { + // take version from settings file metadata, if cant then break and fill settings with 0 and save to settings file; + uint8_t version; + if(!saved_struct_get_metadata(RGB_BACKLIGHT_SETTINGS_PATH, NULL, &version, NULL)) break; + + // if config actual version - load it directly + if(version == RGB_BACKLIGHT_SETTINGS_VER) { + success = saved_struct_load( + RGB_BACKLIGHT_SETTINGS_PATH, + settings, + sizeof(RGBBacklightSettings), + RGB_BACKLIGHT_SETTINGS_MAGIC, + RGB_BACKLIGHT_SETTINGS_VER); + // if config previous version - load it and inicialize new settings + } else if(version == RGB_BACKLIGHT_SETTINGS_VER_PREV) { + RGBBacklightSettingsPrevious* settings_previous = + malloc(sizeof(RGBBacklightSettingsPrevious)); + + success = saved_struct_load( + RGB_BACKLIGHT_SETTINGS_PATH, + settings_previous, + sizeof(RGBBacklightSettingsPrevious), + RGB_BACKLIGHT_SETTINGS_MAGIC, + RGB_BACKLIGHT_SETTINGS_VER_PREV); + // new settings initialization + if(success) { + // copy loaded old settings as part of new + uint32_t size = sizeof(settings); + memcpy(settings, settings_previous, size); + // set new options to initial value + // settings.something = something; + } + + free(settings_previous); + } + // in case of another config version we exit from useless cycle to next step + } while(false); + + // fill settings with 0 and save to settings file; + // Orange color (index=0) will be default + if(!success) { + FURI_LOG_W(TAG, "Failed to load file, using defaults"); + memset(settings, 0, sizeof(RGBBacklightSettings)); + settings->brightness = 1.0f; + settings->rainbow_speed_ms = 100; + settings->rainbow_step = 1; + rgb_backlight_settings_save(settings); + } +} + +void rgb_backlight_settings_save(const RGBBacklightSettings* settings) { + furi_assert(settings); + + const bool success = saved_struct_save( + RGB_BACKLIGHT_SETTINGS_PATH, + settings, + sizeof(RGBBacklightSettings), + RGB_BACKLIGHT_SETTINGS_MAGIC, + RGB_BACKLIGHT_SETTINGS_VER); + + if(!success) { + FURI_LOG_E(TAG, "Failed to save rgb_backlight_settings file"); + } else { + FURI_LOG_I(TAG, "Settings saved"); + } +} diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.h b/applications/services/rgb_backlight/rgb_backlight_settings.h new file mode 100644 index 000000000..48b0c43b9 --- /dev/null +++ b/applications/services/rgb_backlight/rgb_backlight_settings.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +typedef struct { + uint8_t version; + bool rgb_mod_installed; + + uint8_t static_color_index; + uint8_t custom_red; + uint8_t custom_green; + uint8_t custom_blue; + float brightness; + + uint32_t rainbow_mode; + uint32_t rainbow_speed_ms; + uint16_t rainbow_step; + +} RGBBacklightSettings; + +#ifdef __cplusplus +extern "C" { +#endif + +void rgb_backlight_settings_load(RGBBacklightSettings* settings); +void rgb_backlight_settings_save(const RGBBacklightSettings* settings); + +#ifdef __cplusplus +} +#endif diff --git a/applications/settings/application.fam b/applications/settings/application.fam index 1d6db35a7..2ad4aa030 100644 --- a/applications/settings/application.fam +++ b/applications/settings/application.fam @@ -6,6 +6,7 @@ App( "passport", "system_settings", "clock_settings", + "input_settings", "about", ], ) diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 2462b32bd..ff90e96e7 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -1,8 +1,10 @@ #include +#include #include #include #include #include +#include "applications/services/rgb_backlight/rgb_backlight.h" #define MAX_NOTIFICATION_SETTINGS 4 @@ -11,8 +13,11 @@ typedef struct { Gui* gui; ViewDispatcher* view_dispatcher; VariableItemList* variable_item_list; + VariableItemList* variable_item_list_rgb; } NotificationAppSettings; +static VariableItem* temp_item; + static const NotificationSequence sequence_note_c = { &message_note_c5, &message_delay_100, @@ -104,6 +109,52 @@ const char* const vibro_text[VIBRO_COUNT] = { }; const bool vibro_value[VIBRO_COUNT] = {false, true}; +// --- RGB BACKLIGHT --- +#define RGB_MOD_INSTALLED_COUNT 2 +const char* const rgb_mod_installed_text[RGB_MOD_INSTALLED_COUNT] = { + "OFF", + "ON", +}; +const bool rgb_mod_installed_value[RGB_MOD_INSTALLED_COUNT] = {false, true}; + +#define RGB_MOD_RAINBOW_MODE_COUNT 2 +const char* const rgb_mod_rainbow_mode_text[RGB_MOD_RAINBOW_MODE_COUNT] = { + "OFF", + "Rainbow", +}; +const uint32_t rgb_mod_rainbow_mode_value[RGB_MOD_RAINBOW_MODE_COUNT] = {0, 1}; + +#define RGB_MOD_RAINBOW_SPEED_COUNT 20 +const char* const rgb_mod_rainbow_speed_text[RGB_MOD_RAINBOW_SPEED_COUNT] = { + "0.1s", "0.2s", "0.3s", "0.4s", "0.5s", "0.6s", "0.7", "0.8", "0.9", "1s", + "1.1s", "1.2s", "1.3s", "1.4s", "1.5s", "1.6s", "1.7s", "1.8s", "1.9s", "2s"}; +const uint32_t rgb_mod_rainbow_speed_value[RGB_MOD_RAINBOW_SPEED_COUNT] = { + 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, + 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000}; + +#define RGB_MOD_RAINBOW_STEP_COUNT 10 +const char* const rgb_mod_rainbow_step_text[RGB_MOD_RAINBOW_SPEED_COUNT] = { + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", +}; +const uint32_t rgb_mod_rainbow_step_value[RGB_MOD_RAINBOW_STEP_COUNT] = + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + +typedef enum { + MainViewId, + RGBViewId, +} ViewId; + +// --- RGB BACKLIGHT END --- + static void contrast_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -119,6 +170,13 @@ static void backlight_changed(VariableItem* item) { variable_item_set_current_value_text(item, backlight_text[index]); app->notification->settings.display_brightness = backlight_value[index]; + + //--- RGB BACKLIGHT --- + //set selected brightness to current rgb backlight service settings and save settings + app->notification->rgb_srv->settings->brightness = backlight_value[index]; + rgb_backlight_settings_save(app->notification->rgb_srv->settings); + //--- RGB BACKLIGHT END --- + notification_message(app->notification, &sequence_display_backlight_on); } @@ -168,6 +226,176 @@ static void vibro_changed(VariableItem* item) { notification_message(app->notification, &sequence_single_vibro); } +//--- RGB BACKLIGHT --- + +static void rgb_mod_installed_changed(VariableItem* item) { + NotificationAppSettings* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, rgb_mod_installed_text[index]); + app->notification->rgb_srv->settings->rgb_mod_installed = rgb_mod_installed_value[index]; + rgb_backlight_settings_save(app->notification->rgb_srv->settings); + // Lock/Unlock rgb settings depent from rgb_mod_installed switch + int slide = 0; + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + slide = 1; + } + for(int i = slide; i < (slide + 7); i++) { + VariableItem* t_item = variable_item_list_get(app->variable_item_list_rgb, i); + if(index == 0) { + variable_item_set_locked(t_item, true, "RGB MOD\nOFF!"); + } else { + variable_item_set_locked(t_item, false, "RGB MOD\nOFF!"); + } + } +} + +static void rgb_mod_rainbow_changed(VariableItem* item) { + NotificationAppSettings* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, rgb_mod_rainbow_mode_text[index]); + app->notification->rgb_srv->settings->rainbow_mode = rgb_mod_rainbow_mode_value[index]; + + rainbow_timer_starter(app->notification->rgb_srv); + rgb_backlight_settings_save(app->notification->rgb_srv->settings); + + // Lock/Unlock color settings if rainbow mode Enabled/Disabled (0-3 index if debug off and 1-4 index if debug on) + int slide = 0; + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + slide = 1; + } + for(int i = slide; i < (slide + 4); i++) { + VariableItem* t_item = variable_item_list_get(app->variable_item_list_rgb, i); + if(index > 0) { + variable_item_set_locked(t_item, true, "Rainbow mode\nenabled!"); + } else { + variable_item_set_locked(t_item, false, "Rainbow mode\nenabled!"); + } + } + + // restore saved rgb backlight settings if we switch_off rainbow mode + if(app->notification->rgb_srv->settings->rainbow_mode == 0) { + rgb_backlight_set_static_color(app->notification->rgb_srv->settings->static_color_index); + rgb_backlight_update(app->notification->rgb_srv->settings->brightness); + } +} + +static void rgb_mod_rainbow_speed_changed(VariableItem* item) { + NotificationAppSettings* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, rgb_mod_rainbow_speed_text[index]); + app->notification->rgb_srv->settings->rainbow_speed_ms = rgb_mod_rainbow_speed_value[index]; + + //save settings and restart timer with new speed value + rgb_backlight_settings_save(app->notification->rgb_srv->settings); + rainbow_timer_starter(app->notification->rgb_srv); +} + +static void rgb_mod_rainbow_step_changed(VariableItem* item) { + NotificationAppSettings* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, rgb_mod_rainbow_step_text[index]); + app->notification->rgb_srv->settings->rainbow_step = rgb_mod_rainbow_step_value[index]; + + rgb_backlight_settings_save(app->notification->rgb_srv->settings); +} + +// Set rgb_backlight colors static and custom + +static void color_changed(VariableItem* item) { + NotificationAppSettings* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, rgb_backlight_get_color_text(index)); + app->notification->rgb_srv->settings->static_color_index = index; + + rgb_backlight_set_static_color(index); + rgb_backlight_update(app->notification->rgb_srv->settings->brightness); + rgb_backlight_settings_save(app->notification->rgb_srv->settings); +} + +static void color_set_custom_red(VariableItem* item) { + NotificationAppSettings* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + //Set custom red to settings and current color + app->notification->rgb_srv->settings->custom_red = index; + app->notification->rgb_srv->current_red = index; + app->notification->rgb_srv->settings->static_color_index = 13; + + char valtext[4] = {}; + snprintf(valtext, sizeof(valtext), "%d", index); + variable_item_set_current_value_text(item, valtext); + + // Set to custom color explicitly + variable_item_set_current_value_index(temp_item, 13); + variable_item_set_current_value_text(temp_item, rgb_backlight_get_color_text(13)); + + rgb_backlight_update(app->notification->rgb_srv->settings->brightness); + rgb_backlight_settings_save(app->notification->rgb_srv->settings); +} +static void color_set_custom_green(VariableItem* item) { + NotificationAppSettings* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + //Set custom green to settings and current color + app->notification->rgb_srv->settings->custom_green = index; + app->notification->rgb_srv->current_green = index; + app->notification->rgb_srv->settings->static_color_index = 13; + + char valtext[4] = {}; + snprintf(valtext, sizeof(valtext), "%d", index); + variable_item_set_current_value_text(item, valtext); + + // Set to custom color explicitly + variable_item_set_current_value_index(temp_item, 13); + variable_item_set_current_value_text(temp_item, rgb_backlight_get_color_text(13)); + + rgb_backlight_update(app->notification->rgb_srv->settings->brightness); + rgb_backlight_settings_save(app->notification->rgb_srv->settings); +} +static void color_set_custom_blue(VariableItem* item) { + NotificationAppSettings* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + //Set custom blue to settings and current color + app->notification->rgb_srv->settings->custom_blue = index; + app->notification->rgb_srv->current_blue = index; + app->notification->rgb_srv->settings->static_color_index = 13; + + char valtext[4] = {}; + snprintf(valtext, sizeof(valtext), "%d", index); + variable_item_set_current_value_text(item, valtext); + + // Set to custom color explicitly + variable_item_set_current_value_index(temp_item, 13); + variable_item_set_current_value_text(temp_item, rgb_backlight_get_color_text(13)); + + rgb_backlight_update(app->notification->rgb_srv->settings->brightness); + rgb_backlight_settings_save(app->notification->rgb_srv->settings); +} + +// open rgb_settings_view if user press OK on first (index=0) menu string and (debug mode or rgb_mod_install is true) +void variable_item_list_enter_callback(void* context, uint32_t index) { + UNUSED(context); + NotificationAppSettings* app = context; + + if(((app->notification->rgb_srv->settings->rgb_mod_installed) || + (furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug))) && + (index == 0)) { + view_dispatcher_switch_to_view(app->view_dispatcher, RGBViewId); + } +} + +// switch to main view on exit from rgb_settings_view +static uint32_t notification_app_rgb_settings_exit(void* context) { + UNUSED(context); + return MainViewId; +} +//--- RGB BACKLIGHT END --- + static uint32_t notification_app_settings_exit(void* context) { UNUSED(context); return VIEW_NONE; @@ -180,11 +408,25 @@ static NotificationAppSettings* alloc_settings(void) { app->variable_item_list = variable_item_list_alloc(); View* view = variable_item_list_get_view(app->variable_item_list); - view_set_previous_callback(view, notification_app_settings_exit); VariableItem* item; uint8_t value_index; + //set callback for exit from main view + view_set_previous_callback(view, notification_app_settings_exit); + + //--- RGB BACKLIGHT --- + // set callback for OK pressed in notification settings menu + variable_item_list_set_enter_callback( + app->variable_item_list, variable_item_list_enter_callback, app); + + //Show RGB settings only when debug_mode or rgb_mod_installed is active + if((app->notification->rgb_srv->settings->rgb_mod_installed) || + (furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug))) { + item = variable_item_list_add(app->variable_item_list, "RGB mod settings", 0, NULL, app); + } + //--- RGB BACKLIGHT END --- + item = variable_item_list_add( app->variable_item_list, "LCD Contrast", CONTRAST_COUNT, contrast_changed, app); value_index = @@ -241,17 +483,142 @@ static NotificationAppSettings* alloc_settings(void) { variable_item_set_current_value_text(item, vibro_text[value_index]); } + //--- RGB BACKLIGHT --- + app->variable_item_list_rgb = variable_item_list_alloc(); + View* view_rgb = variable_item_list_get_view(app->variable_item_list_rgb); + + // set callback for OK pressed in rgb_settings_menu + view_set_previous_callback(view_rgb, notification_app_rgb_settings_exit); + + // Show RGB_MOD_Installed_Swith only in Debug mode + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + item = variable_item_list_add( + app->variable_item_list_rgb, + "RGB MOD Installed", + RGB_MOD_INSTALLED_COUNT, + rgb_mod_installed_changed, + app); + value_index = value_index_bool( + app->notification->rgb_srv->settings->rgb_mod_installed, + rgb_mod_installed_value, + RGB_MOD_INSTALLED_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_mod_installed_text[value_index]); + } + + // Static Colors settings + item = variable_item_list_add( + app->variable_item_list_rgb, + "LCD Color", + rgb_backlight_get_color_count(), + color_changed, + app); + value_index = app->notification->rgb_srv->settings->static_color_index; + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_backlight_get_color_text(value_index)); + variable_item_set_locked( + item, (app->notification->rgb_srv->settings->rainbow_mode > 0), "Rainbow mode\nenabled!"); + variable_item_set_locked( + item, (app->notification->rgb_srv->settings->rgb_mod_installed == 0), "RGB MOD \nOFF!"); + + temp_item = item; + + // Custom Color - REFACTOR THIS + item = variable_item_list_add( + app->variable_item_list_rgb, "Custom Red", 255, color_set_custom_red, app); + value_index = app->notification->rgb_srv->settings->custom_red; + variable_item_set_current_value_index(item, value_index); + char valtext[4] = {}; + snprintf(valtext, sizeof(valtext), "%d", value_index); + variable_item_set_current_value_text(item, valtext); + variable_item_set_locked( + item, (app->notification->rgb_srv->settings->rainbow_mode > 0), "Rainbow mode\nenabled!"); + variable_item_set_locked( + item, (app->notification->rgb_srv->settings->rgb_mod_installed == 0), "RGB MOD \nOFF!"); + + item = variable_item_list_add( + app->variable_item_list_rgb, "Custom Green", 255, color_set_custom_green, app); + value_index = app->notification->rgb_srv->settings->custom_green; + variable_item_set_current_value_index(item, value_index); + snprintf(valtext, sizeof(valtext), "%d", value_index); + variable_item_set_current_value_text(item, valtext); + variable_item_set_locked( + item, (app->notification->rgb_srv->settings->rainbow_mode > 0), "Rainbow mode\nenabled!"); + variable_item_set_locked( + item, (app->notification->rgb_srv->settings->rgb_mod_installed == 0), "RGB MOD \nOFF!"); + + item = variable_item_list_add( + app->variable_item_list_rgb, "Custom Blue", 255, color_set_custom_blue, app); + value_index = app->notification->rgb_srv->settings->custom_blue; + variable_item_set_current_value_index(item, value_index); + snprintf(valtext, sizeof(valtext), "%d", value_index); + variable_item_set_current_value_text(item, valtext); + variable_item_set_locked( + item, (app->notification->rgb_srv->settings->rainbow_mode > 0), "Rainbow mode\nenabled!"); + variable_item_set_locked( + item, (app->notification->rgb_srv->settings->rgb_mod_installed == 0), "RGB MOD \nOFF!"); + + // Rainbow (based on Willy-JL idea) settings + item = variable_item_list_add( + app->variable_item_list_rgb, + "Rainbow mode", + RGB_MOD_RAINBOW_MODE_COUNT, + rgb_mod_rainbow_changed, + app); + value_index = value_index_uint32( + app->notification->rgb_srv->settings->rainbow_mode, + rgb_mod_rainbow_mode_value, + RGB_MOD_RAINBOW_MODE_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_mod_rainbow_mode_text[value_index]); + variable_item_set_locked( + item, (app->notification->rgb_srv->settings->rgb_mod_installed == 0), "RGB MOD \nOFF!"); + + item = variable_item_list_add( + app->variable_item_list_rgb, + "Rainbow speed", + RGB_MOD_RAINBOW_SPEED_COUNT, + rgb_mod_rainbow_speed_changed, + app); + value_index = value_index_uint32( + app->notification->rgb_srv->settings->rainbow_speed_ms, + rgb_mod_rainbow_speed_value, + RGB_MOD_RAINBOW_SPEED_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_mod_rainbow_speed_text[value_index]); + variable_item_set_locked( + item, (app->notification->rgb_srv->settings->rgb_mod_installed == 0), "RGB MOD \nOFF!"); + + item = variable_item_list_add( + app->variable_item_list_rgb, + "Rainbow step", + RGB_MOD_RAINBOW_STEP_COUNT, + rgb_mod_rainbow_step_changed, + app); + value_index = value_index_uint32( + app->notification->rgb_srv->settings->rainbow_step, + rgb_mod_rainbow_step_value, + RGB_MOD_RAINBOW_SPEED_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_mod_rainbow_step_text[value_index]); + variable_item_set_locked( + item, (app->notification->rgb_srv->settings->rgb_mod_installed == 0), "RGB MOD \nOFF!"); + + //--- RGB BACKLIGHT END --- + app->view_dispatcher = view_dispatcher_alloc(); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); - view_dispatcher_add_view(app->view_dispatcher, 0, view); - view_dispatcher_switch_to_view(app->view_dispatcher, 0); - + view_dispatcher_add_view(app->view_dispatcher, MainViewId, view); + view_dispatcher_add_view(app->view_dispatcher, RGBViewId, view_rgb); + view_dispatcher_switch_to_view(app->view_dispatcher, MainViewId); return app; } static void free_settings(NotificationAppSettings* app) { - view_dispatcher_remove_view(app->view_dispatcher, 0); + view_dispatcher_remove_view(app->view_dispatcher, MainViewId); + view_dispatcher_remove_view(app->view_dispatcher, RGBViewId); variable_item_list_free(app->variable_item_list); + variable_item_list_free(app->variable_item_list_rgb); view_dispatcher_free(app->view_dispatcher); furi_record_close(RECORD_GUI); @@ -264,6 +631,12 @@ int32_t notification_settings_app(void* p) { NotificationAppSettings* app = alloc_settings(); view_dispatcher_run(app->view_dispatcher); notification_message_save_settings(app->notification); + + // Automaticaly switch_off debug_mode when user exit from settings with enabled rgb_mod_installed + // if(app->notification->settings.rgb_mod_installed) { + // furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); + // } + free_settings(app); return 0; } diff --git a/lib/drivers/SK6805.c b/lib/drivers/SK6805.c new file mode 100644 index 000000000..2ad8e18d3 --- /dev/null +++ b/lib/drivers/SK6805.c @@ -0,0 +1,102 @@ +/* + SK6805 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 "SK6805.h" +#include + +/* Настройки */ +#define SK6805_LED_COUNT 3 //Количество светодиодов на плате подсветки +#define SK6805_LED_PIN &led_pin //Порт подключения светодиодов + +#ifdef FURI_DEBUG +#define DEBUG_PIN &gpio_ext_pa7 +#define DEBUG_INIT() \ + furi_hal_gpio_init(DEBUG_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh) +#define DEBUG_SET_HIGH() furi_hal_gpio_write(DEBUG_PIN, true) +#define DEBUG_SET_LOW() furi_hal_gpio_write(DEBUG_PIN, false) +#else +#define DEBUG_INIT() +#define DEBUG_SET_HIGH() +#define DEBUG_SET_LOW() +#endif + +static const GpioPin led_pin = {.port = GPIOA, .pin = LL_GPIO_PIN_8}; +static uint8_t led_buffer[SK6805_LED_COUNT][3]; + +void SK6805_init(void) { + DEBUG_INIT(); + furi_hal_gpio_write(SK6805_LED_PIN, false); + furi_hal_gpio_init(SK6805_LED_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); +} + +uint8_t SK6805_get_led_count(void) { + return (const uint8_t)SK6805_LED_COUNT; +} +void SK6805_set_led_color(uint8_t led_index, uint8_t r, uint8_t g, uint8_t b) { + furi_check(led_index < SK6805_LED_COUNT); + + led_buffer[led_index][0] = g; + led_buffer[led_index][1] = r; + led_buffer[led_index][2] = b; +} + +void SK6805_update(void) { + SK6805_init(); + FURI_CRITICAL_ENTER(); + furi_delay_us(100); + uint32_t end; + /* Последовательная отправка цветов светодиодов */ + for(uint8_t lednumber = 0; lednumber < SK6805_LED_COUNT; lednumber++) { + //Последовательная отправка цветов светодиода + for(uint8_t color = 0; color < 3; color++) { + //Последовательная отправка битов цвета + uint8_t i = 0b10000000; + while(i != 0) { + if(led_buffer[lednumber][color] & (i)) { + furi_hal_gpio_write(SK6805_LED_PIN, true); + DEBUG_SET_HIGH(); + end = DWT->CYCCNT + 30; + //T1H 600 us (615 us) + while(DWT->CYCCNT < end) { + } + furi_hal_gpio_write(SK6805_LED_PIN, false); + DEBUG_SET_LOW(); + end = DWT->CYCCNT + 26; + //T1L 600 us (587 us) + while(DWT->CYCCNT < end) { + } + } else { + furi_hal_gpio_write(SK6805_LED_PIN, true); + DEBUG_SET_HIGH(); + end = DWT->CYCCNT + 11; + //T0H 300 ns (312 ns) + while(DWT->CYCCNT < end) { + } + furi_hal_gpio_write(SK6805_LED_PIN, false); + DEBUG_SET_LOW(); + end = DWT->CYCCNT + 43; + //T0L 900 ns (890 ns) + while(DWT->CYCCNT < end) { + } + } + i >>= 1; + } + } + } + FURI_CRITICAL_EXIT(); +} diff --git a/lib/drivers/SK6805.h b/lib/drivers/SK6805.h new file mode 100644 index 000000000..733f394ad --- /dev/null +++ b/lib/drivers/SK6805.h @@ -0,0 +1,58 @@ +/* + SK6805 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 . +*/ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef SK6805_H_ +#define SK6805_H_ + +#include + +/** + * @brief Инициализация линии управления подсветкой + */ +void SK6805_init(void); + +/** + * @brief Получить количество светодиодов в подсветке + * + * @return Количество светодиодов + */ +uint8_t SK6805_get_led_count(void); + +/** + * @brief Установить цвет свечения светодиода + * + * @param led_index номер светодиода (от 0 до SK6805_get_led_count()) + * @param r значение красного (0-255) + * @param g значение зелёного (0-255) + * @param b значение синего (0-255) + */ +void SK6805_set_led_color(uint8_t led_index, uint8_t r, uint8_t g, uint8_t b); + +/** + * @brief Обновление состояния подсветки дисплея + */ +void SK6805_update(void); + +#endif /* SK6805_H_ */ + +#ifdef __cplusplus +} +#endif diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv old mode 100644 new mode 100755 index 45f912861..ce3992704 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,83.0,, +Version,+,83.1,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -39,6 +39,7 @@ Header,+,applications/services/locale/locale.h,, Header,+,applications/services/notification/notification.h,, Header,+,applications/services/notification/notification_messages.h,, Header,+,applications/services/power/power_service/power.h,, +Header,+,applications/services/rgb_backlight/rgb_backlight.h,, Header,+,applications/services/rpc/rpc_app.h,, Header,+,applications/services/storage/storage.h,, Header,+,lib/bit_lib/bit_lib.h,, @@ -410,6 +411,10 @@ Function,-,LL_mDelay,void,uint32_t Function,-,Osal_MemCmp,int,"const void*, const void*, unsigned int" Function,-,Osal_MemCpy,void*,"void*, const void*, unsigned int" Function,-,Osal_MemSet,void*,"void*, int, unsigned int" +Function,+,SK6805_get_led_count,uint8_t, +Function,+,SK6805_init,void, +Function,+,SK6805_set_led_color,void,"uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,SK6805_update,void, Function,-,SystemCoreClockUpdate,void, Function,-,SystemInit,void, Function,-,_Exit,void,int @@ -3120,6 +3125,9 @@ Function,-,putw,int,"int, FILE*" Function,-,qsort,void,"void*, size_t, size_t, __compar_fn_t" Function,-,qsort_r,void,"void*, size_t, size_t, int (*)(const void*, const void*, void*), void*" Function,-,quick_exit,void,int +Function,+,rainbow_timer_start,void,RGBBacklightApp* +Function,+,rainbow_timer_starter,void,RGBBacklightApp* +Function,+,rainbow_timer_stop,void,RGBBacklightApp* Function,+,rand,int, Function,-,rand_r,int,unsigned* Function,+,random,long, @@ -3138,6 +3146,13 @@ Function,-,remquol,long double,"long double, long double, int*" Function,-,rename,int,"const char*, const char*" Function,-,renameat,int,"int, const char*, int, const char*" Function,-,rewind,void,FILE* +Function,+,rgb_backlight_get_color_count,uint8_t, +Function,+,rgb_backlight_get_color_text,const char*,uint8_t +Function,+,rgb_backlight_set_custom_color,void,"uint8_t, uint8_t, uint8_t" +Function,+,rgb_backlight_set_static_color,void,uint8_t +Function,+,rgb_backlight_settings_load,void,RGBBacklightSettings* +Function,+,rgb_backlight_settings_save,void,const RGBBacklightSettings* +Function,+,rgb_backlight_update,void,float Function,-,rindex,char*,"const char*, int" Function,-,rint,double,double Function,-,rintf,float,float diff --git a/targets/f7/furi_hal/furi_hal_light.c b/targets/f7/furi_hal/furi_hal_light.c index 621478d14..2d6b4bbfe 100644 --- a/targets/f7/furi_hal/furi_hal_light.c +++ b/targets/f7/furi_hal/furi_hal_light.c @@ -3,6 +3,7 @@ #include #include #include +#include "applications/services/rgb_backlight/rgb_backlight.h" #define LED_CURRENT_RED (50u) #define LED_CURRENT_GREEN (50u) @@ -45,6 +46,9 @@ void furi_hal_light_set(Light light, uint8_t value) { uint8_t prev = lp5562_get_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite); lp5562_execute_ramp( &furi_hal_i2c_handle_power, LP5562Engine1, LP5562ChannelWhite, prev, value, 100); + // --- RGB BACKLIGHT --- + rgb_backlight_update(value / 255.0f); + // --- RGB BACKLIGHT END --- } furi_hal_i2c_release(&furi_hal_i2c_handle_power); }