diff --git a/applications/external/esp_flasher/application.fam b/applications/external/esp_flasher/application.fam index c9b04f2ed..2a3085511 100644 --- a/applications/external/esp_flasher/application.fam +++ b/applications/external/esp_flasher/application.fam @@ -7,7 +7,7 @@ App( requires=["gui"], stack_size=4 * 1024, order=90, - fap_icon="wifi_10px.png", + fap_icon="update_10px.png", fap_category="GPIO", fap_private_libs=[ Lib( diff --git a/applications/external/esp_flasher/update_10px.png b/applications/external/esp_flasher/update_10px.png new file mode 100644 index 000000000..5a97651c4 Binary files /dev/null and b/applications/external/esp_flasher/update_10px.png differ diff --git a/applications/external/esp_flasher/wifi_10px.png b/applications/external/esp_flasher/wifi_10px.png deleted file mode 100644 index c13534660..000000000 Binary files a/applications/external/esp_flasher/wifi_10px.png and /dev/null differ diff --git a/applications/external/esubghz_chat/assets/hex_10px.png b/applications/external/esubghz_chat/assets/hex_10px.png new file mode 100644 index 000000000..582e288c6 Binary files /dev/null and b/applications/external/esubghz_chat/assets/hex_10px.png differ diff --git a/applications/external/esubghz_chat/scenes/esubghz_chat_key_menu.c b/applications/external/esubghz_chat/scenes/esubghz_chat_key_menu.c index 4e54e692f..13483bf53 100644 --- a/applications/external/esubghz_chat/scenes/esubghz_chat_key_menu.c +++ b/applications/external/esubghz_chat/scenes/esubghz_chat_key_menu.c @@ -76,20 +76,30 @@ void scene_on_enter_key_menu(void* context) { menu_add_item( state->menu, "No encryption", - NULL, + &I_chat_10px, ESubGhzChatKeyMenuItems_NoEncryption, key_menu_cb, state); menu_add_item( - state->menu, "Password", NULL, ESubGhzChatKeyMenuItems_Password, key_menu_cb, state); + state->menu, + "Password", + &I_keyboard_10px, + ESubGhzChatKeyMenuItems_Password, + key_menu_cb, + state); menu_add_item( - state->menu, "Hex Key", NULL, ESubGhzChatKeyMenuItems_HexKey, key_menu_cb, state); + state->menu, "Hex Key", &I_hex_10px, ESubGhzChatKeyMenuItems_HexKey, key_menu_cb, state); menu_add_item( - state->menu, "Generate Key", NULL, ESubGhzChatKeyMenuItems_GenKey, key_menu_cb, state); + state->menu, + "Generate Key", + &I_u2f_10px, + ESubGhzChatKeyMenuItems_GenKey, + key_menu_cb, + state); menu_add_item( state->menu, "Read Key from NFC", - NULL, + &I_Nfc_10px, ESubGhzChatKeyMenuItems_ReadKeyFromNfc, key_menu_cb, state); diff --git a/applications/external/evil_portal/icons/evil_portal_10px.png b/applications/external/evil_portal/icons/evil_portal_10px.png index c13534660..eed8789a4 100644 Binary files a/applications/external/evil_portal/icons/evil_portal_10px.png and b/applications/external/evil_portal/icons/evil_portal_10px.png differ diff --git a/applications/main/xtreme_app/scenes/xtreme_app_scene_config.h b/applications/main/xtreme_app/scenes/xtreme_app_scene_config.h index 4d9b161ed..16a9436ad 100644 --- a/applications/main/xtreme_app/scenes/xtreme_app_scene_config.h +++ b/applications/main/xtreme_app/scenes/xtreme_app_scene_config.h @@ -16,5 +16,6 @@ ADD_SCENE(xtreme_app, protocols_freqs_add, ProtocolsFreqsAdd) ADD_SCENE(xtreme_app, protocols_gpio, ProtocolsGpio) ADD_SCENE(xtreme_app, misc, Misc) ADD_SCENE(xtreme_app, misc_screen, MiscScreen) +ADD_SCENE(xtreme_app, misc_screen_color, MiscScreenColor) ADD_SCENE(xtreme_app, misc_dolphin, MiscDolphin) ADD_SCENE(xtreme_app, misc_rename, MiscRename) diff --git a/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_graphics.c b/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_graphics.c index d4c8e42fa..c03b2abb3 100644 --- a/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_graphics.c +++ b/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_graphics.c @@ -27,10 +27,34 @@ static void xtreme_app_scene_interface_graphics_asset_pack_changed(VariableItem* app->apply_pack = true; } -const char* const anim_speed_names[] = - {"25%", "50%", "75%", "100%", "125%", "150%", "175%", "200%", "225%", "250%", "275%", "300%"}; -const uint32_t anim_speed_values[COUNT_OF(anim_speed_names)] = - {25, 50, 75, 100, 125, 150, 175, 200, 225, 250, 275, 300}; +const char* const anim_speed_names[] = { + "25%", + "50%", + "75%", + "100%", + "125%", + "150%", + "175%", + "200%", + "225%", + "250%", + "275%", + "300%", +}; +const uint32_t anim_speed_values[COUNT_OF(anim_speed_names)] = { + 25, + 50, + 75, + 100, + 125, + 150, + 175, + 200, + 225, + 250, + 275, + 300, +}; static void xtreme_app_scene_interface_graphics_anim_speed_changed(VariableItem* item) { XtremeApp* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -52,9 +76,23 @@ const char* const cycle_anims_names[] = { "2 H", "6 H", "12 H", - "24 H"}; -const int32_t cycle_anims_values[COUNT_OF(cycle_anims_names)] = - {-1, 0, 30, 60, 300, 600, 900, 1800, 3600, 7200, 21600, 43200, 86400}; + "24 H", +}; +const int32_t cycle_anims_values[COUNT_OF(cycle_anims_names)] = { + -1, + 0, + 30, + 60, + 300, + 600, + 900, + 1800, + 3600, + 7200, + 21600, + 43200, + 86400, +}; static void xtreme_app_scene_interface_graphics_cycle_anims_changed(VariableItem* item) { XtremeApp* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); diff --git a/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_statusbar.c b/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_statusbar.c index 50b3c14ec..953c08c95 100644 --- a/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_statusbar.c +++ b/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_statusbar.c @@ -13,8 +13,15 @@ void xtreme_app_scene_interface_statusbar_var_item_list_callback(void* context, view_dispatcher_send_custom_event(app->view_dispatcher, index); } -const char* const battery_icon_names[BatteryIconCount] = - {"OFF", "Bar", "%", "Inv. %", "Retro 3", "Retro 5", "Bar %"}; +const char* const battery_icon_names[BatteryIconCount] = { + "OFF", + "Bar", + "%", + "Inv. %", + "Retro 3", + "Retro 5", + "Bar %", +}; static void xtreme_app_scene_interface_statusbar_battery_icon_changed(VariableItem* item) { XtremeApp* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); diff --git a/applications/main/xtreme_app/scenes/xtreme_app_scene_misc_dolphin.c b/applications/main/xtreme_app/scenes/xtreme_app_scene_misc_dolphin.c index e6425d20b..e4d344e09 100644 --- a/applications/main/xtreme_app/scenes/xtreme_app_scene_misc_dolphin.c +++ b/applications/main/xtreme_app/scenes/xtreme_app_scene_misc_dolphin.c @@ -29,10 +29,30 @@ static void xtreme_app_scene_misc_dolphin_dolphin_angry_changed(VariableItem* it app->save_angry = true; } -const char* const butthurt_timer_names[] = - {"OFF", "30 M", "1 H", "2 H", "4 H", "6 H", "8 H", "12 H", "24 H", "48 H"}; -const uint32_t butthurt_timer_values[COUNT_OF(butthurt_timer_names)] = - {0, 1800, 3600, 7200, 14400, 21600, 28800, 43200, 86400, 172800}; +const char* const butthurt_timer_names[] = { + "OFF", + "30 M", + "1 H", + "2 H", + "4 H", + "6 H", + "8 H", + "12 H", + "24 H", + "48 H", +}; +const uint32_t butthurt_timer_values[COUNT_OF(butthurt_timer_names)] = { + 0, + 1800, + 3600, + 7200, + 14400, + 21600, + 28800, + 43200, + 86400, + 172800, +}; static void xtreme_app_scene_misc_dolphin_butthurt_timer_changed(VariableItem* item) { XtremeApp* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); diff --git a/applications/main/xtreme_app/scenes/xtreme_app_scene_misc_screen.c b/applications/main/xtreme_app/scenes/xtreme_app_scene_misc_screen.c index b86326aae..92b24daeb 100644 --- a/applications/main/xtreme_app/scenes/xtreme_app_scene_misc_screen.c +++ b/applications/main/xtreme_app/scenes/xtreme_app_scene_misc_screen.c @@ -4,7 +4,13 @@ enum VarItemListIndex { VarItemListIndexDarkMode, VarItemListIndexLeftHanded, VarItemListIndexRgbBacklight, - VarItemListIndexLcdColor, + VarItemListIndexLcdColor0, + VarItemListIndexLcdColor1, + VarItemListIndexLcdColor2, + VarItemListIndexRainbowLcd, + VarItemListIndexRainbowSpeed, + VarItemListIndexRainbowInterval, + VarItemListIndexRainbowSaturation, }; void xtreme_app_scene_misc_screen_var_item_list_callback(void* context, uint32_t index) { @@ -30,13 +36,117 @@ static void xtreme_app_scene_misc_screen_hand_orient_changed(VariableItem* item) } } -static void xtreme_app_scene_misc_screen_lcd_color_changed(VariableItem* item) { +static const struct { + char* name; + RgbColor color; +} lcd_colors[] = { + {"Orange", {255, 69, 0}}, + {"Red", {255, 0, 0}}, + {"Maroon", {128, 0, 0}}, + {"Yellow", {255, 255, 0}}, + {"Olive", {128, 128, 0}}, + {"Lime", {0, 255, 0}}, + {"Green", {0, 128, 0}}, + {"Aqua", {0, 255, 127}}, + {"Cyan", {0, 210, 210}}, + {"Azure", {0, 127, 255}}, + {"Teal", {0, 128, 128}}, + {"Blue", {0, 0, 255}}, + {"Navy", {0, 0, 128}}, + {"Purple", {128, 0, 128}}, + {"Fuchsia", {255, 0, 255}}, + {"Pink", {173, 31, 173}}, + {"Brown", {165, 42, 42}}, + {"White", {255, 192, 203}}, +}; +static void xtreme_app_scene_misc_screen_lcd_color_changed(VariableItem* item, uint8_t led) { XtremeApp* 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)); - rgb_backlight_set_color(index); + variable_item_set_current_value_text(item, lcd_colors[index].name); + rgb_backlight_set_color(led, lcd_colors[index].color); + app->save_backlight = true; +} +static void xtreme_app_scene_misc_screen_lcd_color_0_changed(VariableItem* item) { + xtreme_app_scene_misc_screen_lcd_color_changed(item, 0); +} +static void xtreme_app_scene_misc_screen_lcd_color_1_changed(VariableItem* item) { + xtreme_app_scene_misc_screen_lcd_color_changed(item, 1); +} +static void xtreme_app_scene_misc_screen_lcd_color_2_changed(VariableItem* item) { + xtreme_app_scene_misc_screen_lcd_color_changed(item, 2); +} + +const char* const rainbow_lcd_names[RGBBacklightRainbowModeCount] = { + "OFF", + "Wave", + "Static", +}; +static void xtreme_app_scene_misc_screen_rainbow_lcd_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, rainbow_lcd_names[index]); + rgb_backlight_set_rainbow_mode(index); + app->save_backlight = true; +} + +static void xtreme_app_scene_misc_screen_rainbow_speed_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item) + 1; + char str[4]; + snprintf(str, sizeof(str), "%d", index); + variable_item_set_current_value_text(item, str); + rgb_backlight_set_rainbow_speed(index); + app->save_backlight = true; +} + +const char* const rainbow_interval_names[] = { + "0.1 S", + "0.2 S", + "0.25 S", + "0.5 S", + "0.75 S", + "1 S", + "1.25 S", + "1.5 S", + "1.75 S", + "2 S", + "2.5 S", + "3 S", + "4 S", + "5 S", +}; +const uint32_t rainbow_interval_values[COUNT_OF(rainbow_interval_names)] = { + 100, + 200, + 250, + 500, + 750, + 1000, + 1250, + 1500, + 1750, + 2000, + 2500, + 3000, + 4000, + 5000, +}; +static void xtreme_app_scene_misc_screen_rainbow_interval_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, rainbow_interval_names[index]); + rgb_backlight_set_rainbow_interval(rainbow_interval_values[index]); + app->save_backlight = true; +} + +static void xtreme_app_scene_misc_screen_rainbow_saturation_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item) + 1; + char str[4]; + snprintf(str, sizeof(str), "%d", index); + variable_item_set_current_value_text(item, str); + rgb_backlight_set_rainbow_saturation(index); app->save_backlight = true; - notification_message(app->notification, &sequence_display_backlight_on); } void xtreme_app_scene_misc_screen_on_enter(void* context) { @@ -60,15 +170,87 @@ void xtreme_app_scene_misc_screen_on_enter(void* context) { item = variable_item_list_add(var_item_list, "RGB Backlight", 1, NULL, app); variable_item_set_current_value_text(item, xtreme_settings->rgb_backlight ? "ON" : "OFF"); + struct { + uint8_t led; + const char* str; + VariableItemChangeCallback cb; + } lcd_cols[] = { + {0, "LCD Left", xtreme_app_scene_misc_screen_lcd_color_0_changed}, + {1, "LCD Middle", xtreme_app_scene_misc_screen_lcd_color_1_changed}, + {2, "LCD Right", xtreme_app_scene_misc_screen_lcd_color_2_changed}, + }; + size_t lcd_sz = COUNT_OF(lcd_colors); + + for(size_t i = 0; i < COUNT_OF(lcd_cols); i++) { + item = variable_item_list_add(var_item_list, lcd_cols[i].str, lcd_sz, lcd_cols[i].cb, app); + RgbColor color = rgb_backlight_get_color(lcd_cols[i].led); + bool found = false; + for(size_t i = 0; i < lcd_sz; i++) { + if(rgbcmp(&color, &lcd_colors[i].color) != 0) continue; + value_index = i; + found = true; + break; + } + variable_item_set_current_value_index(item, found ? value_index : lcd_sz); + if(found) { + variable_item_set_current_value_text(item, lcd_colors[value_index].name); + } else { + char str[7]; + snprintf(str, sizeof(str), "%02X%02X%02X", color.r, color.g, color.b); + variable_item_set_current_value_text(item, str); + } + variable_item_set_locked(item, !xtreme_settings->rgb_backlight, "Needs RGB\nBacklight!"); + } + item = variable_item_list_add( var_item_list, - "LCD Color", - rgb_backlight_get_color_count(), - xtreme_app_scene_misc_screen_lcd_color_changed, + "Rainbow LCD", + RGBBacklightRainbowModeCount, + xtreme_app_scene_misc_screen_rainbow_lcd_changed, app); - value_index = rgb_backlight_get_settings()->display_color_index; + value_index = rgb_backlight_get_rainbow_mode(); 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_current_value_text(item, rainbow_lcd_names[value_index]); + variable_item_set_locked(item, !xtreme_settings->rgb_backlight, "Needs RGB\nBacklight!"); + + item = variable_item_list_add( + var_item_list, + "Rainbow Speed", + 25, + xtreme_app_scene_misc_screen_rainbow_speed_changed, + app); + value_index = rgb_backlight_get_rainbow_speed(); + variable_item_set_current_value_index(item, value_index - 1); + char speed_str[4]; + snprintf(speed_str, sizeof(speed_str), "%d", value_index); + variable_item_set_current_value_text(item, speed_str); + variable_item_set_locked(item, !xtreme_settings->rgb_backlight, "Needs RGB\nBacklight!"); + + item = variable_item_list_add( + var_item_list, + "Rainbow Interval", + COUNT_OF(rainbow_interval_values), + xtreme_app_scene_misc_screen_rainbow_interval_changed, + app); + value_index = value_index_uint32( + rgb_backlight_get_rainbow_interval(), + rainbow_interval_values, + COUNT_OF(rainbow_interval_values)); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rainbow_interval_names[value_index]); + variable_item_set_locked(item, !xtreme_settings->rgb_backlight, "Needs RGB\nBacklight!"); + + item = variable_item_list_add( + var_item_list, + "Rainbow Saturation", + 25, + xtreme_app_scene_misc_screen_rainbow_saturation_changed, + app); + value_index = rgb_backlight_get_rainbow_saturation(); + variable_item_set_current_value_index(item, value_index - 1); + char saturation_str[4]; + snprintf(saturation_str, sizeof(saturation_str), "%d", value_index); + variable_item_set_current_value_text(item, saturation_str); variable_item_set_locked(item, !xtreme_settings->rgb_backlight, "Needs RGB\nBacklight!"); variable_item_list_set_enter_callback( @@ -110,12 +292,23 @@ bool xtreme_app_scene_misc_screen_on_event(void* context, SceneManagerEvent even if(change) { XTREME_SETTINGS()->rgb_backlight = !XTREME_SETTINGS()->rgb_backlight; app->save_settings = true; + app->save_backlight = true; notification_message(app->notification, &sequence_display_backlight_on); + rgb_backlight_reconfigure(XTREME_SETTINGS()->rgb_backlight); scene_manager_previous_scene(app->scene_manager); scene_manager_next_scene(app->scene_manager, XtremeAppSceneMiscScreen); } break; } + case VarItemListIndexLcdColor0: + case VarItemListIndexLcdColor1: + case VarItemListIndexLcdColor2: + scene_manager_set_scene_state( + app->scene_manager, + XtremeAppSceneMiscScreenColor, + event.event - VarItemListIndexLcdColor0); + scene_manager_next_scene(app->scene_manager, XtremeAppSceneMiscScreenColor); + break; default: break; } diff --git a/applications/main/xtreme_app/scenes/xtreme_app_scene_misc_screen_color.c b/applications/main/xtreme_app/scenes/xtreme_app_scene_misc_screen_color.c new file mode 100644 index 000000000..a998a1cb3 --- /dev/null +++ b/applications/main/xtreme_app/scenes/xtreme_app_scene_misc_screen_color.c @@ -0,0 +1,59 @@ +#include "../xtreme_app.h" + +enum ByteInputResult { + ByteInputResultOk, +}; + +void xtreme_app_scene_misc_screen_color_byte_input_callback(void* context) { + XtremeApp* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, ByteInputResultOk); +} + +void xtreme_app_scene_misc_screen_color_on_enter(void* context) { + XtremeApp* app = context; + ByteInput* byte_input = app->byte_input; + + byte_input_set_header_text(byte_input, "Set LCD Color (#RRGGBB)"); + + app->lcd_color = rgb_backlight_get_color( + scene_manager_get_scene_state(app->scene_manager, XtremeAppSceneMiscScreenColor)); + + byte_input_set_result_callback( + byte_input, + xtreme_app_scene_misc_screen_color_byte_input_callback, + NULL, + app, + (void*)&app->lcd_color, + sizeof(app->lcd_color)); + + view_dispatcher_switch_to_view(app->view_dispatcher, XtremeAppViewByteInput); +} + +bool xtreme_app_scene_misc_screen_color_on_event(void* context, SceneManagerEvent event) { + XtremeApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + switch(event.event) { + case ByteInputResultOk: + rgb_backlight_set_color( + scene_manager_get_scene_state(app->scene_manager, XtremeAppSceneMiscScreenColor), + app->lcd_color); + app->save_backlight = true; + scene_manager_previous_scene(app->scene_manager); + break; + default: + break; + } + } + + return consumed; +} + +void xtreme_app_scene_misc_screen_color_on_exit(void* context) { + XtremeApp* app = context; + byte_input_set_result_callback(app->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(app->byte_input, ""); +} diff --git a/applications/main/xtreme_app/xtreme_app.c b/applications/main/xtreme_app/xtreme_app.c index f73390e52..ce198a3e4 100644 --- a/applications/main/xtreme_app/xtreme_app.c +++ b/applications/main/xtreme_app/xtreme_app.c @@ -193,6 +193,10 @@ XtremeApp* xtreme_app_alloc() { view_dispatcher_add_view( app->view_dispatcher, XtremeAppViewTextInput, text_input_get_view(app->text_input)); + app->byte_input = byte_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, XtremeAppViewByteInput, byte_input_get_view(app->byte_input)); + app->popup = popup_alloc(); view_dispatcher_add_view(app->view_dispatcher, XtremeAppViewPopup, popup_get_view(app->popup)); @@ -315,6 +319,8 @@ void xtreme_app_free(XtremeApp* app) { submenu_free(app->submenu); view_dispatcher_remove_view(app->view_dispatcher, XtremeAppViewTextInput); text_input_free(app->text_input); + view_dispatcher_remove_view(app->view_dispatcher, XtremeAppViewByteInput); + byte_input_free(app->byte_input); view_dispatcher_remove_view(app->view_dispatcher, XtremeAppViewPopup); popup_free(app->popup); view_dispatcher_remove_view(app->view_dispatcher, XtremeAppViewDialogEx); diff --git a/applications/main/xtreme_app/xtreme_app.h b/applications/main/xtreme_app/xtreme_app.h index 995b00310..7fbee8bcb 100644 --- a/applications/main/xtreme_app/xtreme_app.h +++ b/applications/main/xtreme_app/xtreme_app.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ typedef struct { VariableItemList* var_item_list; Submenu* submenu; TextInput* text_input; + ByteInput* byte_input; Popup* popup; DialogEx* dialog_ex; @@ -57,6 +59,7 @@ typedef struct { uint8_t subghz_hopper_index; char subghz_freq_buffer[XTREME_SUBGHZ_FREQ_BUFFER_SIZE]; bool subghz_extend; + RgbColor lcd_color; char device_name[FURI_HAL_VERSION_ARRAY_NAME_LENGTH]; int32_t dolphin_level; int32_t dolphin_angry; @@ -79,6 +82,7 @@ typedef enum { XtremeAppViewVarItemList, XtremeAppViewSubmenu, XtremeAppViewTextInput, + XtremeAppViewByteInput, XtremeAppViewPopup, XtremeAppViewDialogEx, } XtremeAppView; diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 9a88fe7f7..00bc36fa0 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1171,18 +1171,18 @@ Function,+,furi_hal_cortex_timer_is_expired,_Bool,FuriHalCortexTimer Function,+,furi_hal_cortex_timer_wait,void,FuriHalCortexTimer Function,+,furi_hal_crypto_ctr,_Bool,"const uint8_t*, const uint8_t*, const uint8_t*, uint8_t*, size_t" Function,+,furi_hal_crypto_decrypt,_Bool,"const uint8_t*, uint8_t*, size_t" +Function,+,furi_hal_crypto_enclave_ensure_key,_Bool,uint8_t +Function,+,furi_hal_crypto_enclave_load_key,_Bool,"uint8_t, const uint8_t*" +Function,+,furi_hal_crypto_enclave_store_key,_Bool,"FuriHalCryptoKey*, uint8_t*" +Function,+,furi_hal_crypto_enclave_unload_key,_Bool,uint8_t +Function,+,furi_hal_crypto_enclave_verify,_Bool,"uint8_t*, uint8_t*" Function,+,furi_hal_crypto_encrypt,_Bool,"const uint8_t*, uint8_t*, size_t" Function,+,furi_hal_crypto_gcm,_Bool,"const uint8_t*, const uint8_t*, const uint8_t*, size_t, const uint8_t*, uint8_t*, size_t, uint8_t*, _Bool" Function,+,furi_hal_crypto_gcm_decrypt_and_verify,FuriHalCryptoGCMState,"const uint8_t*, const uint8_t*, const uint8_t*, size_t, const uint8_t*, uint8_t*, size_t, const uint8_t*" Function,+,furi_hal_crypto_gcm_encrypt_and_tag,FuriHalCryptoGCMState,"const uint8_t*, const uint8_t*, const uint8_t*, size_t, const uint8_t*, uint8_t*, size_t, uint8_t*" Function,-,furi_hal_crypto_init,void, Function,+,furi_hal_crypto_load_key,_Bool,"const uint8_t*, const uint8_t*" -Function,+,furi_hal_crypto_enclave_store_key,_Bool,"FuriHalCryptoKey*, uint8_t*" -Function,+,furi_hal_crypto_enclave_load_key,_Bool,"uint8_t, const uint8_t*" -Function,+,furi_hal_crypto_enclave_unload_key,_Bool,uint8_t Function,+,furi_hal_crypto_unload_key,_Bool, -Function,+,furi_hal_crypto_enclave_verify,_Bool,"uint8_t*, uint8_t*" -Function,+,furi_hal_crypto_enclave_ensure_key,_Bool,uint8_t Function,+,furi_hal_debug_disable,void, Function,+,furi_hal_debug_enable,void, Function,+,furi_hal_debug_is_gdb_session_active,_Bool, @@ -1733,6 +1733,8 @@ Function,+,hex_char_to_hex_nibble,_Bool,"char, uint8_t*" Function,+,hex_char_to_uint8,_Bool,"char, char, uint8_t*" Function,+,hex_chars_to_uint64,_Bool,"const char*, uint64_t*" Function,+,hex_chars_to_uint8,_Bool,"const char*, uint8_t*" +Function,+,hsv2rgb,RgbColor,HsvColor +Function,+,hsvcmp,int,"const HsvColor*, const HsvColor*" Function,-,hypot,double,"double, double" Function,-,hypotf,float,"float, float" Function,-,hypotl,long double,"long double, long double" @@ -2555,13 +2557,22 @@ Function,-,rfal_platform_spi_acquire,void, Function,-,rfal_platform_spi_release,void, Function,-,rfal_set_callback_context,void,void* Function,-,rfal_set_state_changed_callback,void,RfalStateChangedCallback -Function,+,rgb_backlight_get_color_count,uint8_t, -Function,+,rgb_backlight_get_color_text,const char*,uint8_t -Function,+,rgb_backlight_get_settings,RGBBacklightSettings*, +Function,+,rgb2hsv,HsvColor,RgbColor +Function,+,rgb_backlight_get_color,RgbColor,uint8_t +Function,+,rgb_backlight_get_rainbow_interval,uint32_t, +Function,+,rgb_backlight_get_rainbow_mode,RGBBacklightRainbowMode, +Function,+,rgb_backlight_get_rainbow_saturation,uint8_t, +Function,+,rgb_backlight_get_rainbow_speed,uint8_t, Function,-,rgb_backlight_load_settings,void, +Function,+,rgb_backlight_reconfigure,void,_Bool Function,+,rgb_backlight_save_settings,void, -Function,+,rgb_backlight_set_color,void,uint8_t -Function,-,rgb_backlight_update,void,uint8_t +Function,+,rgb_backlight_set_color,void,"uint8_t, RgbColor" +Function,+,rgb_backlight_set_rainbow_interval,void,uint32_t +Function,+,rgb_backlight_set_rainbow_mode,void,RGBBacklightRainbowMode +Function,+,rgb_backlight_set_rainbow_saturation,void,uint8_t +Function,+,rgb_backlight_set_rainbow_speed,void,uint8_t +Function,-,rgb_backlight_update,void,"uint8_t, _Bool" +Function,+,rgbcmp,int,"const RgbColor*, const RgbColor*" Function,-,rindex,char*,"const char*, int" Function,-,rint,double,double Function,-,rintf,float,float diff --git a/firmware/targets/f7/furi_hal/furi_hal_light.c b/firmware/targets/f7/furi_hal/furi_hal_light.c index 2673b8a58..df7c23d56 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_light.c +++ b/firmware/targets/f7/furi_hal/furi_hal_light.c @@ -45,7 +45,7 @@ void furi_hal_light_set(Light light, uint8_t value) { } if(light & LightBacklight) { if(XTREME_SETTINGS()->rgb_backlight) { - rgb_backlight_update(value); + rgb_backlight_update(value, false); } else { uint8_t prev = lp5562_get_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite); diff --git a/lib/drivers/SK6805.c b/lib/drivers/SK6805.c index 572e1df97..e64ecba32 100644 --- a/lib/drivers/SK6805.c +++ b/lib/drivers/SK6805.c @@ -19,9 +19,10 @@ #include "SK6805.h" #include +#define TAG "SK6805" + /* Настройки */ -#define SK6805_LED_COUNT 3 //Количество светодиодов на плате подсветки -#define SK6805_LED_PIN &led_pin //Порт подключения светодиодов +#define SK6805_LED_PIN &led_pin // LED connection port #ifdef FURI_DEBUG #define DEBUG_PIN &gpio_ext_pa7 @@ -53,17 +54,18 @@ void SK6805_set_led_color(uint8_t led_index, uint8_t r, uint8_t g, uint8_t b) { led_buffer[led_index][0] = g; led_buffer[led_index][1] = r; led_buffer[led_index][2] = b; + FURI_LOG_T(TAG, "led: %d, r: %d, g: %d, b: %d", led_index, r, g, b); } void SK6805_update(void) { SK6805_init(); furi_kernel_lock(); uint32_t end; - /* Последовательная отправка цветов светодиодов */ + // Sequential sending LEDs for(uint8_t lednumber = 0; lednumber < SK6805_LED_COUNT; lednumber++) { - //Последовательная отправка цветов светодиода + // Sequential sending colors for(uint8_t color = 0; color < 3; color++) { - //Последовательная отправка битов цвета + // Sequentially sending color bits uint8_t i = 0b10000000; while(i != 0) { if(led_buffer[lednumber][color] & (i)) { diff --git a/lib/drivers/SK6805.h b/lib/drivers/SK6805.h index 7c58956fa..ed0dcdb36 100644 --- a/lib/drivers/SK6805.h +++ b/lib/drivers/SK6805.h @@ -21,6 +21,8 @@ #include +#define SK6805_LED_COUNT 3 //Количество светодиодов на плате подсветки + /** * @brief Инициализация линии управления подсветкой */ @@ -48,4 +50,4 @@ void SK6805_set_led_color(uint8_t led_index, uint8_t r, uint8_t g, uint8_t b); */ void SK6805_update(void); -#endif /* SK6805_H_ */ \ No newline at end of file +#endif /* SK6805_H_ */ diff --git a/lib/drivers/rgb_backlight.c b/lib/drivers/rgb_backlight.c index ec39efb0b..5a19ce0ca 100644 --- a/lib/drivers/rgb_backlight.c +++ b/lib/drivers/rgb_backlight.c @@ -1,6 +1,7 @@ /* RGB backlight FlipperZero driver Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) + Heavily modified by Willy-JL and Z3bro 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 @@ -19,156 +20,243 @@ #include "rgb_backlight.h" #include #include +#include -#define RGB_BACKLIGHT_SETTINGS_VERSION 5 +#define RGB_BACKLIGHT_SETTINGS_MAGIC 0x15 +#define RGB_BACKLIGHT_SETTINGS_VERSION 6 #define RGB_BACKLIGHT_SETTINGS_PATH CFG_PATH("rgb_backlight.settings") -#define COLOR_COUNT (sizeof(colors) / sizeof(RGBBacklightColor)) - -#define TAG "RGB Backlight" - -static RGBBacklightSettings rgb_settings = { - .version = RGB_BACKLIGHT_SETTINGS_VERSION, - .display_color_index = 0, - .settings_is_loaded = false}; - -static const RGBBacklightColor colors[] = { - {"Orange", 255, 69, 0}, - {"Red", 255, 0, 0}, - {"Maroon", 128, 0, 0}, - {"Yellow", 255, 255, 0}, - {"Olive", 128, 128, 0}, - {"Lime", 0, 255, 0}, - {"Green", 0, 128, 0}, - {"Aqua", 0, 255, 127}, - {"Cyan", 0, 210, 210}, - {"Azure", 0, 127, 255}, - {"Teal", 0, 128, 128}, - {"Blue", 0, 0, 255}, - {"Navy", 0, 0, 128}, - {"Purple", 128, 0, 128}, - {"Fuchsia", 255, 0, 255}, - {"Pink", 173, 31, 173}, - {"Brown", 165, 42, 42}, - {"White", 255, 192, 203}, +static struct { + RgbColor colors[SK6805_LED_COUNT]; + RGBBacklightRainbowMode rainbow_mode; + uint8_t rainbow_speed; + uint32_t rainbow_interval; + uint32_t rainbow_saturation; +} rgb_settings = { + .colors = + { + {255, 69, 0}, + {255, 69, 0}, + {255, 69, 0}, + }, + .rainbow_mode = RGBBacklightRainbowModeOff, + .rainbow_speed = 5, + .rainbow_interval = 250, + .rainbow_saturation = 255, }; -uint8_t rgb_backlight_get_color_count(void) { - return COLOR_COUNT; +static struct { + bool settings_loaded; + bool enabled; + bool last_rainbow; + uint8_t last_brightness; + RgbColor last_colors[SK6805_LED_COUNT]; + FuriTimer* rainbow_timer; + HsvColor rainbow_hsv; +} rgb_state = { + .settings_loaded = false, + .enabled = false, + .last_rainbow = true, + .last_brightness = 0, + .last_colors = + { + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + }, + .rainbow_timer = NULL, + .rainbow_hsv = {0, 255, 255}, +}; + +static void rainbow_timer(void* ctx) { + UNUSED(ctx); + rgb_backlight_update(rgb_state.last_brightness, true); } -const char* rgb_backlight_get_color_text(uint8_t index) { - return colors[index].name; +void rgb_backlight_reconfigure(bool enabled) { + if(enabled && !rgb_state.settings_loaded) { + rgb_backlight_load_settings(); + } + rgb_state.enabled = enabled; + + if(rgb_state.enabled && rgb_settings.rainbow_mode != RGBBacklightRainbowModeOff) { + if(rgb_state.rainbow_timer == NULL) { + rgb_state.rainbow_timer = furi_timer_alloc(rainbow_timer, FuriTimerTypePeriodic, NULL); + } else { + furi_timer_stop(rgb_state.rainbow_timer); + } + furi_timer_start(rgb_state.rainbow_timer, rgb_settings.rainbow_interval); + } else if(rgb_state.rainbow_timer != NULL) { + furi_timer_stop(rgb_state.rainbow_timer); + furi_timer_free(rgb_state.rainbow_timer); + rgb_state.rainbow_timer = NULL; + } + rgb_state.rainbow_hsv.s = rgb_settings.rainbow_saturation; + + rgb_backlight_update(rgb_state.last_brightness, false); } void rgb_backlight_load_settings(void) { - //Не загружать данные из внутренней памяти при загрузке в режиме DFU - if(!furi_hal_is_normal_boot()) { - rgb_settings.settings_is_loaded = true; + // Do not load data from internal memory when booting in DFU mode + if(!furi_hal_is_normal_boot() || rgb_state.settings_loaded) { + rgb_state.settings_loaded = true; return; } - RGBBacklightSettings settings; - File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - const size_t settings_size = sizeof(RGBBacklightSettings); + saved_struct_load( + RGB_BACKLIGHT_SETTINGS_PATH, + &rgb_settings, + sizeof(rgb_settings), + RGB_BACKLIGHT_SETTINGS_MAGIC, + RGB_BACKLIGHT_SETTINGS_VERSION); - FURI_LOG_I(TAG, "loading settings from \"%s\"", RGB_BACKLIGHT_SETTINGS_PATH); - bool fs_result = - storage_file_open(file, RGB_BACKLIGHT_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING); - - if(fs_result) { - uint16_t bytes_count = storage_file_read(file, &settings, settings_size); - - if(bytes_count != settings_size) { - fs_result = false; - } - } - - if(fs_result) { - FURI_LOG_I(TAG, "load success"); - if(settings.version != RGB_BACKLIGHT_SETTINGS_VERSION) { - FURI_LOG_E( - TAG, - "version(%d != %d) mismatch", - settings.version, - RGB_BACKLIGHT_SETTINGS_VERSION); - } else { - memcpy(&rgb_settings, &settings, settings_size); - } - } else { - FURI_LOG_E(TAG, "load failed, %s", storage_file_get_error_desc(file)); - } - - storage_file_close(file); - storage_file_free(file); - furi_record_close(RECORD_STORAGE); - rgb_settings.settings_is_loaded = true; + rgb_state.settings_loaded = true; + rgb_backlight_reconfigure(rgb_state.enabled); } void rgb_backlight_save_settings(void) { - RGBBacklightSettings settings; - File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - const size_t settings_size = sizeof(RGBBacklightSettings); + saved_struct_save( + RGB_BACKLIGHT_SETTINGS_PATH, + &rgb_settings, + sizeof(rgb_settings), + RGB_BACKLIGHT_SETTINGS_MAGIC, + RGB_BACKLIGHT_SETTINGS_VERSION); +} - FURI_LOG_I(TAG, "saving settings to \"%s\"", RGB_BACKLIGHT_SETTINGS_PATH); +void rgb_backlight_set_color(uint8_t index, RgbColor color) { + if(index >= COUNT_OF(rgb_settings.colors)) return; + if(!rgb_state.settings_loaded) { + rgb_backlight_load_settings(); + } + rgb_settings.colors[index] = color; + rgb_backlight_reconfigure(rgb_state.enabled); +} - memcpy(&settings, &rgb_settings, settings_size); +RgbColor rgb_backlight_get_color(uint8_t index) { + if(index >= COUNT_OF(rgb_settings.colors)) return (RgbColor){0, 0, 0}; + if(!rgb_state.settings_loaded) { + rgb_backlight_load_settings(); + } + return rgb_settings.colors[index]; +} - bool fs_result = - storage_file_open(file, RGB_BACKLIGHT_SETTINGS_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS); +void rgb_backlight_set_rainbow_mode(RGBBacklightRainbowMode rainbow_mode) { + if(rainbow_mode >= RGBBacklightRainbowModeCount) return; + if(!rgb_state.settings_loaded) { + rgb_backlight_load_settings(); + } + rgb_settings.rainbow_mode = rainbow_mode; + rgb_backlight_reconfigure(rgb_state.enabled); +} - if(fs_result) { - uint16_t bytes_count = storage_file_write(file, &settings, settings_size); +RGBBacklightRainbowMode rgb_backlight_get_rainbow_mode() { + if(!rgb_state.settings_loaded) { + rgb_backlight_load_settings(); + } + return rgb_settings.rainbow_mode; +} - if(bytes_count != settings_size) { - fs_result = false; +void rgb_backlight_set_rainbow_speed(uint8_t rainbow_speed) { + if(!rgb_state.settings_loaded) { + rgb_backlight_load_settings(); + } + rgb_settings.rainbow_speed = rainbow_speed; +} + +uint8_t rgb_backlight_get_rainbow_speed() { + if(!rgb_state.settings_loaded) { + rgb_backlight_load_settings(); + } + return rgb_settings.rainbow_speed; +} + +void rgb_backlight_set_rainbow_interval(uint32_t rainbow_interval) { + if(rainbow_interval < 100) return; + if(!rgb_state.settings_loaded) { + rgb_backlight_load_settings(); + } + rgb_settings.rainbow_interval = rainbow_interval; + rgb_backlight_reconfigure(rgb_state.enabled); +} + +uint32_t rgb_backlight_get_rainbow_interval() { + if(!rgb_state.settings_loaded) { + rgb_backlight_load_settings(); + } + return rgb_settings.rainbow_interval; +} + +void rgb_backlight_set_rainbow_saturation(uint8_t rainbow_saturation) { + if(!rgb_state.settings_loaded) { + rgb_backlight_load_settings(); + } + rgb_settings.rainbow_saturation = rainbow_saturation; + rgb_backlight_reconfigure(rgb_state.enabled); +} + +uint8_t rgb_backlight_get_rainbow_saturation() { + if(!rgb_state.settings_loaded) { + rgb_backlight_load_settings(); + } + return rgb_settings.rainbow_saturation; +} + +void rgb_backlight_update(uint8_t brightness, bool tick) { + if(!rgb_state.enabled) return; + if(!rgb_state.settings_loaded) { + rgb_backlight_load_settings(); + } + + switch(rgb_settings.rainbow_mode) { + case RGBBacklightRainbowModeOff: { + if(!rgb_state.last_rainbow && rgb_state.last_brightness == brightness && + memcmp(rgb_state.last_colors, rgb_settings.colors, sizeof(rgb_settings.colors)) == 0) { + return; } + rgb_state.last_rainbow = false; + memcpy(rgb_state.last_colors, rgb_settings.colors, sizeof(rgb_settings.colors)); + + float bright = brightness / 255.0f; + for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { + SK6805_set_led_color( + i, + rgb_settings.colors[i].r * bright, + rgb_settings.colors[i].g * bright, + rgb_settings.colors[i].b * bright); + } + break; } - if(fs_result) { - FURI_LOG_I(TAG, "save success"); - } else { - FURI_LOG_E(TAG, "save failed, %s", storage_file_get_error_desc(file)); + case RGBBacklightRainbowModeWave: + case RGBBacklightRainbowModeSolid: { + rgb_state.last_rainbow = true; + + if(tick && brightness) { + rgb_state.rainbow_hsv.h += rgb_settings.rainbow_speed; + } else { + if(rgb_state.last_brightness == brightness && rgb_state.last_rainbow) { + return; + } + rgb_state.rainbow_hsv.v = brightness; + } + + HsvColor hsv = rgb_state.rainbow_hsv; + RgbColor rgb = hsv2rgb(hsv); + + for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { + if(i && rgb_settings.rainbow_mode == RGBBacklightRainbowModeWave) { + hsv.h += (50 * i); + rgb = hsv2rgb(hsv); + } + SK6805_set_led_color(i, rgb.r, rgb.g, rgb.b); + } + break; } - storage_file_close(file); - storage_file_free(file); - furi_record_close(RECORD_STORAGE); -} - -RGBBacklightSettings* rgb_backlight_get_settings(void) { - if(!rgb_settings.settings_is_loaded) { - rgb_backlight_load_settings(); - } - return &rgb_settings; -} - -void rgb_backlight_set_color(uint8_t color_index) { - if(color_index > (rgb_backlight_get_color_count() - 1)) color_index = 0; - rgb_settings.display_color_index = color_index; -} - -void rgb_backlight_update(uint8_t brightness) { - if(!rgb_settings.settings_is_loaded) { - rgb_backlight_load_settings(); - } - - static uint8_t last_color_index = 255; - static uint8_t last_brightness = 123; - - if(last_brightness == brightness && last_color_index == rgb_settings.display_color_index) + default: return; - - last_brightness = brightness; - last_color_index = rgb_settings.display_color_index; - - for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { - uint8_t r = colors[rgb_settings.display_color_index].red * (brightness / 255.0f); - uint8_t g = colors[rgb_settings.display_color_index].green * (brightness / 255.0f); - uint8_t b = colors[rgb_settings.display_color_index].blue * (brightness / 255.0f); - - SK6805_set_led_color(i, r, g, b); } + rgb_state.last_brightness = brightness; SK6805_update(); } diff --git a/lib/drivers/rgb_backlight.h b/lib/drivers/rgb_backlight.h index c00eb0716..b289520fd 100644 --- a/lib/drivers/rgb_backlight.h +++ b/lib/drivers/rgb_backlight.h @@ -1,6 +1,7 @@ /* RGB backlight FlipperZero driver Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) + Heavily modified by Willy-JL and Z3bro 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 @@ -18,69 +19,89 @@ #include #include "SK6805.h" +#include #ifdef __cplusplus extern "C" { #endif -typedef struct { - char* name; - uint8_t red; - uint8_t green; - uint8_t blue; -} RGBBacklightColor; - -typedef struct { - uint8_t version; - uint8_t display_color_index; - bool settings_is_loaded; -} RGBBacklightSettings; +typedef enum { + RGBBacklightRainbowModeOff, + RGBBacklightRainbowModeWave, + RGBBacklightRainbowModeSolid, + RGBBacklightRainbowModeCount, +} RGBBacklightRainbowMode; /** - * @brief Получить текущие настройки RGB-подсветки + * @brief Reconfigure rgb backlight with new settings * - * @return Указатель на структуру настроек + * @param enabled Whether the rgb backlight is enabled */ -RGBBacklightSettings* rgb_backlight_get_settings(void); +void rgb_backlight_reconfigure(bool enabled); /** - * @brief Загрузить настройки подсветки с SD-карты + * @brief Load backlight settings from SD card */ -void rgb_backlight_load_settings(void); +void rgb_backlight_load_settings(); /** - * @brief Сохранить текущие настройки RGB-подсветки + * @brief Save Current RGB Lighting Settings */ -void rgb_backlight_save_settings(void); +void rgb_backlight_save_settings(); /** - * @brief Применить текущие настройки RGB-подсветки + * @brief Change the color of the backlight * - * @param brightness Яркость свечения (0-255) + * @param index What led to set the color to (0 - SK6805_LED_COUNT-1) + * @param color RGB color to use */ -void rgb_backlight_update(uint8_t brightness); +void rgb_backlight_set_color(uint8_t index, RgbColor color); + +RgbColor rgb_backlight_get_color(uint8_t index); /** - * @brief Установить цвет RGB-подсветки + * @brief Change rainbow mode * - * @param color_index Индекс цвета (0 - rgb_backlight_get_color_count()) + * @param rainbow_mode What mode to use (0 - RGBBacklightRainbowModeCount) */ -void rgb_backlight_set_color(uint8_t color_index); +void rgb_backlight_set_rainbow_mode(RGBBacklightRainbowMode rainbow_mode); + +RGBBacklightRainbowMode rgb_backlight_get_rainbow_mode(); /** - * @brief Получить количество доступных цветов + * @brief Change rainbow speed * - * @return Число доступных вариантов цвета + * @param rainbow_speed What speed to use (0 - 255) */ -uint8_t rgb_backlight_get_color_count(void); +void rgb_backlight_set_rainbow_speed(uint8_t rainbow_speed); + +uint8_t rgb_backlight_get_rainbow_speed(); /** - * @brief Получить текстовое название цвета + * @brief Change rainbow interval * - * @param index Индекс из доступных вариантов цвета - * @return Указатель на строку с названием цвета + * @param rainbow_interval What interval to use */ -const char* rgb_backlight_get_color_text(uint8_t index); +void rgb_backlight_set_rainbow_interval(uint32_t rainbow_interval); + +uint32_t rgb_backlight_get_rainbow_interval(); + +/** + * @brief Change rainbow saturation + * + * @param rainbow_saturation What saturation to use (0 - 255) + */ +void rgb_backlight_set_rainbow_saturation(uint8_t rainbow_saturation); + +uint8_t rgb_backlight_get_rainbow_saturation(); + +/** + * @brief Apply current RGB lighting settings + * + * @param brightness Backlight intensity (0-255) + * @param tick Whether this update was a tick (for rainbow) + */ +void rgb_backlight_update(uint8_t brightness, bool tick); #ifdef __cplusplus } diff --git a/lib/toolbox/colors.c b/lib/toolbox/colors.c new file mode 100644 index 000000000..33ad8152c --- /dev/null +++ b/lib/toolbox/colors.c @@ -0,0 +1,95 @@ +// https://stackoverflow.com/a/14733008 + +#include "colors.h" + +inline int rgbcmp(const RgbColor* a, const RgbColor* b) { + return memcmp(a, b, sizeof(RgbColor)); +} + +inline int hsvcmp(const HsvColor* a, const HsvColor* b) { + return memcmp(a, b, sizeof(HsvColor)); +} + +RgbColor hsv2rgb(HsvColor hsv) { + RgbColor rgb; + uint8_t region, remainder, p, q, t; + + if(hsv.s == 0) { + rgb.r = hsv.v; + rgb.g = hsv.v; + rgb.b = hsv.v; + return rgb; + } + + region = hsv.h / 43; + remainder = (hsv.h - (region * 43)) * 6; + + p = (hsv.v * (255 - hsv.s)) >> 8; + q = (hsv.v * (255 - ((hsv.s * remainder) >> 8))) >> 8; + t = (hsv.v * (255 - ((hsv.s * (255 - remainder)) >> 8))) >> 8; + + switch(region) { + case 0: + rgb.r = hsv.v; + rgb.g = t; + rgb.b = p; + break; + case 1: + rgb.r = q; + rgb.g = hsv.v; + rgb.b = p; + break; + case 2: + rgb.r = p; + rgb.g = hsv.v; + rgb.b = t; + break; + case 3: + rgb.r = p; + rgb.g = q; + rgb.b = hsv.v; + break; + case 4: + rgb.r = t; + rgb.g = p; + rgb.b = hsv.v; + break; + default: + rgb.r = hsv.v; + rgb.g = p; + rgb.b = q; + break; + } + + return rgb; +} + +HsvColor rgb2hsv(RgbColor rgb) { + HsvColor hsv; + uint8_t rgbMin, rgbMax; + + rgbMin = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b); + rgbMax = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b); + + hsv.v = rgbMax; + if(hsv.v == 0) { + hsv.h = 0; + hsv.s = 0; + return hsv; + } + + hsv.s = 255 * ((long)rgbMax - (long)rgbMin) / hsv.v; + if(hsv.s == 0) { + hsv.h = 0; + return hsv; + } + + if(rgbMax == rgb.r) + hsv.h = 0 + 43 * (rgb.g - rgb.b) / (rgbMax - rgbMin); + else if(rgbMax == rgb.g) + hsv.h = 85 + 43 * (rgb.b - rgb.r) / (rgbMax - rgbMin); + else + hsv.h = 171 + 43 * (rgb.r - rgb.g) / (rgbMax - rgbMin); + + return hsv; +} diff --git a/lib/toolbox/colors.h b/lib/toolbox/colors.h new file mode 100644 index 000000000..902b1a5d0 --- /dev/null +++ b/lib/toolbox/colors.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct RgbColor { + uint8_t r; + uint8_t g; + uint8_t b; +} RgbColor; + +typedef struct HsvColor { + uint8_t h; + uint8_t s; + uint8_t v; +} HsvColor; + +int rgbcmp(const RgbColor* a, const RgbColor* b); + +int hsvcmp(const HsvColor* a, const HsvColor* b); + +RgbColor hsv2rgb(HsvColor hsv); + +HsvColor rgb2hsv(RgbColor rgb); + +#ifdef __cplusplus +} +#endif diff --git a/lib/xtreme/settings.c b/lib/xtreme/settings.c index 9198161cb..49bf67d0b 100644 --- a/lib/xtreme/settings.c +++ b/lib/xtreme/settings.c @@ -1,5 +1,6 @@ #include "xtreme.h" #include +#include #include #define TAG "XtremeSettings" @@ -194,6 +195,8 @@ void XTREME_SETTINGS_LOAD() { } flipper_format_free(file); furi_record_close(RECORD_STORAGE); + + rgb_backlight_reconfigure(x->rgb_backlight); } void XTREME_SETTINGS_SAVE() {