From 3c7d9e63fb30d1e7ab3d4469faafd9239470eef0 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Fri, 28 Feb 2025 23:14:18 +0700 Subject: [PATCH 001/125] Start working on combining rgb_backlight and original_backlight. --- .../services/notification/notification_app.c | 2 + .../notification_settings_app.c | 90 +++++++- .../notification_settings/rgb_backlight.c | 217 ++++++++++++++++++ .../notification_settings/rgb_backlight.h | 91 ++++++++ lib/drivers/SK6805.c | 103 +++++++++ lib/drivers/SK6805.h | 51 ++++ targets/f7/furi_hal/furi_hal_light.c | 34 +-- 7 files changed, 571 insertions(+), 17 deletions(-) create mode 100644 applications/settings/notification_settings/rgb_backlight.c create mode 100644 applications/settings/notification_settings/rgb_backlight.h create mode 100644 lib/drivers/SK6805.c create mode 100644 lib/drivers/SK6805.h diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 35d2fe675..1af97e2f4 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/settings/notification_settings/rgb_backlight.h" #define TAG "NotificationSrv" @@ -616,6 +617,7 @@ int32_t notification_srv(void* p) { break; case SaveSettingsMessage: notification_save_settings(app); + rgb_backlight_save_settings(); break; case LoadSettingsMessage: notification_load_settings(app); diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 2462b32bd..8e045cebf 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -3,6 +3,7 @@ #include #include #include +#include #define MAX_NOTIFICATION_SETTINGS 4 @@ -13,6 +14,8 @@ typedef struct { VariableItemList* variable_item_list; } NotificationAppSettings; +static VariableItem* temp_item; + static const NotificationSequence sequence_note_c = { &message_note_c5, &message_delay_100, @@ -168,6 +171,59 @@ static void vibro_changed(VariableItem* item) { notification_message(app->notification, &sequence_single_vibro); } +// Set RGB backlight color +static void color_changed(VariableItem* item) { + NotificationAppSettings* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + rgb_backlight_set_color(index); + variable_item_set_current_value_text(item, rgb_backlight_get_color_text(index)); + notification_message(app->notification, &sequence_display_backlight_on); +} + +// TODO: refactor and fix this +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); + rgb_backlight_set_custom_color(index, 0); + char valtext[4] = {}; + snprintf(valtext, sizeof(valtext), "%d", index); + variable_item_set_current_value_text(item, valtext); + rgb_backlight_set_color(13); + rgb_backlight_update(app->notification->settings.display_brightness * 0xFF, true); + // 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)); + notification_message(app->notification, &sequence_display_backlight_on); +} +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); + rgb_backlight_set_custom_color(index, 1); + char valtext[4] = {}; + snprintf(valtext, sizeof(valtext), "%d", index); + variable_item_set_current_value_text(item, valtext); + rgb_backlight_set_color(13); + rgb_backlight_update(app->notification->settings.display_brightness * 0xFF, true); + // 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)); + notification_message(app->notification, &sequence_display_backlight_on); +} +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); + rgb_backlight_set_custom_color(index, 2); + char valtext[4] = {}; + snprintf(valtext, sizeof(valtext), "%d", index); + variable_item_set_current_value_text(item, valtext); + rgb_backlight_set_color(13); + rgb_backlight_update(app->notification->settings.display_brightness * 0xFF, true); + // 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)); + notification_message(app->notification, &sequence_display_backlight_on); +} + static uint32_t notification_app_settings_exit(void* context) { UNUSED(context); return VIEW_NONE; @@ -192,8 +248,40 @@ static NotificationAppSettings* alloc_settings(void) { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, contrast_text[value_index]); + // RGB Colors item = variable_item_list_add( - app->variable_item_list, "LCD Backlight", BACKLIGHT_COUNT, backlight_changed, app); + app->variable_item_list, "LCD Color", rgb_backlight_get_color_count(), color_changed, app); + value_index = rgb_backlight_get_settings()->display_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)); + temp_item = item; + + // Custom Color - REFACTOR THIS + item = variable_item_list_add( + app->variable_item_list, "Custom Red", 255, color_set_custom_red, app); + value_index = rgb_backlight_get_settings()->custom_r; + 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); + + item = variable_item_list_add( + app->variable_item_list, "Custom Green", 255, color_set_custom_green, app); + value_index = rgb_backlight_get_settings()->custom_g; + variable_item_set_current_value_index(item, value_index); + snprintf(valtext, sizeof(valtext), "%d", value_index); + variable_item_set_current_value_text(item, valtext); + + item = variable_item_list_add( + app->variable_item_list, "Custom Blue", 255, color_set_custom_blue, app); + value_index = rgb_backlight_get_settings()->custom_b; + variable_item_set_current_value_index(item, value_index); + snprintf(valtext, sizeof(valtext), "%d", value_index); + variable_item_set_current_value_text(item, valtext); + // End of RGB + + item = variable_item_list_add( + app->variable_item_list, "LCD Brightness", BACKLIGHT_COUNT, backlight_changed, app); value_index = value_index_float( app->notification->settings.display_brightness, backlight_value, BACKLIGHT_COUNT); variable_item_set_current_value_index(item, value_index); diff --git a/applications/settings/notification_settings/rgb_backlight.c b/applications/settings/notification_settings/rgb_backlight.c new file mode 100644 index 000000000..4edd77568 --- /dev/null +++ b/applications/settings/notification_settings/rgb_backlight.c @@ -0,0 +1,217 @@ +/* + 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 "rgb_backlight.h" +#include +#include + +#define RGB_BACKLIGHT_SETTINGS_VERSION 6 +#define RGB_BACKLIGHT_SETTINGS_FILE_NAME ".rgb_backlight.settings" +#define RGB_BACKLIGHT_SETTINGS_PATH INT_PATH(RGB_BACKLIGHT_SETTINGS_FILE_NAME) + +#define COLOR_COUNT (sizeof(colors) / sizeof(RGBBacklightColor)) + +#define TAG "RGB Backlight" + +static RGBBacklightSettings rgb_settings = { + .version = RGB_BACKLIGHT_SETTINGS_VERSION, + .display_color_index = 0, + .custom_r = 254, + .custom_g = 254, + .custom_b = 254, + .settings_is_loaded = false}; + +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; +} + +void rgb_backlight_load_settings(void) { + // Do not load settings if we are in other boot modes than normal + if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { + rgb_settings.settings_is_loaded = true; + return; + } + + // Wait for all required services to start and create their records + uint8_t timeout = 0; + while(!furi_record_exists(RECORD_STORAGE)) { + timeout++; + if(timeout > 150) { + rgb_settings.settings_is_loaded = true; + return; + } + furi_delay_ms(5); + } + + RGBBacklightSettings settings; + File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); + const size_t settings_size = sizeof(RGBBacklightSettings); + + FURI_LOG_D(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_D(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; +} + +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); + + FURI_LOG_D(TAG, "saving settings to \"%s\"", RGB_BACKLIGHT_SETTINGS_PATH); + + memcpy(&settings, &rgb_settings, settings_size); + + bool fs_result = + storage_file_open(file, RGB_BACKLIGHT_SETTINGS_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS); + + if(fs_result) { + uint16_t bytes_count = storage_file_write(file, &settings, settings_size); + + if(bytes_count != settings_size) { + fs_result = false; + } + } + + if(fs_result) { + FURI_LOG_D(TAG, "save success"); + } else { + FURI_LOG_E(TAG, "save failed, %s", storage_file_get_error_desc(file)); + } + + 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_set_custom_color(uint8_t color, uint8_t index) { + if(index > 2) return; + if(index == 0) { + rgb_settings.custom_r = color; + } else if(index == 1) { + rgb_settings.custom_g = color; + } else if(index == 2) { + rgb_settings.custom_b = color; + } +} + +void rgb_backlight_update(uint8_t brightness, bool bypass) { + if(!rgb_settings.settings_is_loaded) { + rgb_backlight_load_settings(); + } + + if(!bypass) { + 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) { + return; + } + + last_brightness = brightness; + last_color_index = rgb_settings.display_color_index; + } + + for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { + if(rgb_settings.display_color_index == 13) { + uint8_t r = rgb_settings.custom_r * (brightness / 255.0f); + uint8_t g = rgb_settings.custom_g * (brightness / 255.0f); + uint8_t b = rgb_settings.custom_b * (brightness / 255.0f); + + SK6805_set_led_color(i, r, g, b); + } else { + if((colors[rgb_settings.display_color_index].red == 0) && + (colors[rgb_settings.display_color_index].green == 0) && + (colors[rgb_settings.display_color_index].blue == 0)) { + uint8_t r = colors[0].red * (brightness / 255.0f); + uint8_t g = colors[0].green * (brightness / 255.0f); + uint8_t b = colors[0].blue * (brightness / 255.0f); + + SK6805_set_led_color(i, r, g, b); + } else { + 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); + } + } + } + + SK6805_update(); +} diff --git a/applications/settings/notification_settings/rgb_backlight.h b/applications/settings/notification_settings/rgb_backlight.h new file mode 100644 index 000000000..f215ed312 --- /dev/null +++ b/applications/settings/notification_settings/rgb_backlight.h @@ -0,0 +1,91 @@ +/* + 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 "SK6805.h" + +typedef struct { + char* name; + uint8_t red; + uint8_t green; + uint8_t blue; +} RGBBacklightColor; + +typedef struct { + uint8_t version; + uint8_t display_color_index; + uint8_t custom_r; + uint8_t custom_g; + uint8_t custom_b; + bool settings_is_loaded; +} RGBBacklightSettings; + +/** + * @brief Получить текущие настройки RGB-подсветки + * + * @return Указатель на структуру настроек + */ +RGBBacklightSettings* rgb_backlight_get_settings(void); + +/** + * @brief Загрузить настройки подсветки с SD-карты + */ +void rgb_backlight_load_settings(void); + +/** + * @brief Сохранить текущие настройки RGB-подсветки + */ +void rgb_backlight_save_settings(void); + +/** + * @brief Применить текущие настройки RGB-подсветки + * + * @param brightness Яркость свечения (0-255) + * @param bypass Применить настройки принудительно + */ +void rgb_backlight_update(uint8_t brightness, bool bypass); + +/** + * @brief Установить цвет RGB-подсветки + * + * @param color_index Индекс цвета (0 - rgb_backlight_get_color_count()) + */ +void rgb_backlight_set_color(uint8_t color_index); + +/** + * @brief Set custom color values by index - 0=R 1=G 2=B + * + * @param color - color value (0-255) + * @param index - color index (0-2) 0=R 1=G 2=B + */ +void rgb_backlight_set_custom_color(uint8_t color, uint8_t index); + +/** + * @brief Получить количество доступных цветов + * + * @return Число доступных вариантов цвета + */ +uint8_t rgb_backlight_get_color_count(void); + +/** + * @brief Получить текстовое название цвета + * + * @param index Индекс из доступных вариантов цвета + * @return Указатель на строку с названием цвета + */ +const char* rgb_backlight_get_color_text(uint8_t index); diff --git a/lib/drivers/SK6805.c b/lib/drivers/SK6805.c new file mode 100644 index 000000000..8158c55a4 --- /dev/null +++ b/lib/drivers/SK6805.c @@ -0,0 +1,103 @@ +/* + 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(150); + 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_delay_us(150); + FURI_CRITICAL_EXIT(); +} diff --git a/lib/drivers/SK6805.h b/lib/drivers/SK6805.h new file mode 100644 index 000000000..c97054f6d --- /dev/null +++ b/lib/drivers/SK6805.h @@ -0,0 +1,51 @@ +/* + 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 . +*/ + +#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_ */ diff --git a/targets/f7/furi_hal/furi_hal_light.c b/targets/f7/furi_hal/furi_hal_light.c index 621478d14..9ee542034 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 #define LED_CURRENT_RED (50u) #define LED_CURRENT_GREEN (50u) @@ -31,22 +32,23 @@ void furi_hal_light_init(void) { } void furi_hal_light_set(Light light, uint8_t value) { - furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); - if(light & LightRed) { - lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value); - } - if(light & LightGreen) { - lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value); - } - if(light & LightBlue) { - lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value); - } - if(light & LightBacklight) { - 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); - } - furi_hal_i2c_release(&furi_hal_i2c_handle_power); + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + if(light & LightRed) { + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value); + } + if(light & LightGreen) { + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value); + } + if(light & LightBlue) { + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value); + } + if(light & LightBacklight) { + 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_update(value, false); + } + furi_hal_i2c_release(&furi_hal_i2c_handle_power); } void furi_hal_light_blink_start(Light light, uint8_t brightness, uint16_t on_time, uint16_t period) { From bb170140e2e9dcd9e3aa7e681280adb620daaf3b Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Sat, 1 Mar 2025 22:55:25 +0700 Subject: [PATCH 002/125] =?UTF-8?q?=D0=A1ombining=20rgb=5Fbacklight=20and?= =?UTF-8?q?=20original=5Fbacklight=20finished.=20-=20RGB=20Colors=20settin?= =?UTF-8?q?gs=20available=20only=20when=20Settings-Notification-RGB=5FMOD?= =?UTF-8?q?=5FInstalled=20swithed=20ON=20-=20RGB=5FMOD=5FInstalled=20switc?= =?UTF-8?q?h=20(ON|OFF)=20available=20in=20Notification=20only=20with=20De?= =?UTF-8?q?bug=20mode=20swithed=20ON.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../services/notification/notification_app.c | 1 + .../services/notification/notification_app.h | 3 +- .../notification_settings_app.c | 92 +++++++++++++------ 3 files changed, 67 insertions(+), 29 deletions(-) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 1af97e2f4..e02a16a1d 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -523,6 +523,7 @@ static NotificationApp* notification_app_alloc(void) { app->settings.led_brightness = 1.0f; app->settings.display_off_delay_ms = 30000; app->settings.vibro_on = true; + app->settings.rgb_mod_installed = false; app->display.value[LayerInternal] = 0x00; app->display.value[LayerNotification] = 0x00; diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index e19546574..056a762df 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -33,7 +33,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 { @@ -44,6 +44,7 @@ typedef struct { uint32_t display_off_delay_ms; int8_t contrast; bool vibro_on; + bool rgb_mod_installed; } NotificationSettings; struct NotificationApp { diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 8e045cebf..527e0ba22 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -107,6 +108,13 @@ const char* const vibro_text[VIBRO_COUNT] = { }; const bool vibro_value[VIBRO_COUNT] = {false, true}; +#define RGB_MOD_COUNT 2 +const char* const rgb_mod_text[RGB_MOD_COUNT] = { + "OFF", + "ON", +}; +const bool rgb_mod_value[RGB_MOD_COUNT] = {false, true}; + static void contrast_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -171,6 +179,13 @@ static void vibro_changed(VariableItem* item) { notification_message(app->notification, &sequence_single_vibro); } +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_text[index]); + app->notification->settings.rgb_mod_installed = rgb_mod_value[index]; +} + // Set RGB backlight color static void color_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); @@ -248,38 +263,59 @@ static NotificationAppSettings* alloc_settings(void) { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, contrast_text[value_index]); - // RGB Colors - item = variable_item_list_add( - app->variable_item_list, "LCD Color", rgb_backlight_get_color_count(), color_changed, app); - value_index = rgb_backlight_get_settings()->display_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)); - temp_item = item; + // 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 MOD Installed", + RGB_MOD_COUNT, + rgb_mod_installed_changed, + app); + value_index = value_index_bool( + app->notification->settings.rgb_mod_installed, rgb_mod_value, RGB_MOD_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_mod_text[value_index]); + } - // Custom Color - REFACTOR THIS - item = variable_item_list_add( - app->variable_item_list, "Custom Red", 255, color_set_custom_red, app); - value_index = rgb_backlight_get_settings()->custom_r; - 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); + //Show RGB settings only when debug mode enabled or rgb_mod_installed is true + if((furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) || + (app->notification->settings.rgb_mod_installed)) { + // RGB Colors + item = variable_item_list_add( + app->variable_item_list, + "LCD Color", + rgb_backlight_get_color_count(), + color_changed, + app); + value_index = rgb_backlight_get_settings()->display_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)); + temp_item = item; - item = variable_item_list_add( - app->variable_item_list, "Custom Green", 255, color_set_custom_green, app); - value_index = rgb_backlight_get_settings()->custom_g; - variable_item_set_current_value_index(item, value_index); - snprintf(valtext, sizeof(valtext), "%d", value_index); - variable_item_set_current_value_text(item, valtext); + // Custom Color - REFACTOR THIS + item = variable_item_list_add( + app->variable_item_list, "Custom Red", 255, color_set_custom_red, app); + value_index = rgb_backlight_get_settings()->custom_r; + 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); - item = variable_item_list_add( - app->variable_item_list, "Custom Blue", 255, color_set_custom_blue, app); - value_index = rgb_backlight_get_settings()->custom_b; - variable_item_set_current_value_index(item, value_index); - snprintf(valtext, sizeof(valtext), "%d", value_index); - variable_item_set_current_value_text(item, valtext); - // End of RGB + item = variable_item_list_add( + app->variable_item_list, "Custom Green", 255, color_set_custom_green, app); + value_index = rgb_backlight_get_settings()->custom_g; + variable_item_set_current_value_index(item, value_index); + snprintf(valtext, sizeof(valtext), "%d", value_index); + variable_item_set_current_value_text(item, valtext); + item = variable_item_list_add( + app->variable_item_list, "Custom Blue", 255, color_set_custom_blue, app); + value_index = rgb_backlight_get_settings()->custom_b; + variable_item_set_current_value_index(item, value_index); + snprintf(valtext, sizeof(valtext), "%d", value_index); + variable_item_set_current_value_text(item, valtext); + // End of RGB + } item = variable_item_list_add( app->variable_item_list, "LCD Brightness", BACKLIGHT_COUNT, backlight_changed, app); value_index = value_index_float( From 08304ccff5a881f05578d8904dfc192bb5b5511e Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Sat, 1 Mar 2025 23:58:07 +0700 Subject: [PATCH 003/125] Small usability changes --- .../notification_settings/notification_settings_app.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 527e0ba22..a34ac5b4a 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -277,9 +277,8 @@ static NotificationAppSettings* alloc_settings(void) { variable_item_set_current_value_text(item, rgb_mod_text[value_index]); } - //Show RGB settings only when debug mode enabled or rgb_mod_installed is true - if((furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) || - (app->notification->settings.rgb_mod_installed)) { + //Show RGB settings only when rgb_mod_installed is true + if(app->notification->settings.rgb_mod_installed) { // RGB Colors item = variable_item_list_add( app->variable_item_list, From 7ac1452618e2c0774cdb03776dea28b21ad6ff42 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Tue, 4 Mar 2025 22:13:59 +0700 Subject: [PATCH 004/125] Start working on RGB mod Rainbow effect (inspired by Willy-JL idea). --- .../services/notification/notification_app.c | 57 +++- .../services/notification/notification_app.h | 12 + .../notification_settings_app.c | 267 ++++++++++++++---- 3 files changed, 277 insertions(+), 59 deletions(-) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index e02a16a1d..229f7c5ea 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -512,18 +512,49 @@ static void input_event_callback(const void* value, void* context) { notification_message(app, &sequence_display_backlight_on); } +// RGB MOD RAINBOW SECTION + +//start furi timer for rgb_mod_rainbow +static void rgb_mod_rainbow_timer_start(NotificationApp* app) { + furi_timer_start( + app->rgb_mod_rainbow_timer, furi_ms_to_ticks(app->settings.rgb_mod_rainbow_speed_ms)); +} + +//stop furi timer for rgb_mod_rainbow +static void rgb_mod_rainbow_timer_stop(NotificationApp* app) { + furi_timer_stop(app->rgb_mod_rainbow_timer); +} + +// start/stop rgb_mod_rainbow_timer only if rgb_mod_installed +static void rgb_mod_rainbow_timer_control(NotificationApp* app) { + if(app->settings.rgb_mod_installed) { + if(app->settings.rgb_mod_rainbow) { + rgb_mod_rainbow_timer_start(app); + } else { + rgb_mod_rainbow_timer_stop(app); + } + } +} + +// callback for rgb_mod_rainbow_timer (what we do when timer end) +static void rgb_mod_rainbow_timer_callback(void* context) { + furi_assert(context); + FURI_LOG_I("RAINBOW", "Rainbow timer callback - change color"); +} + +// END OF RGB MOD RAINBOW SECTION + // App alloc static NotificationApp* notification_app_alloc(void) { NotificationApp* app = malloc(sizeof(NotificationApp)); app->queue = furi_message_queue_alloc(8, sizeof(NotificationAppMessage)); - app->display_timer = furi_timer_alloc(notification_display_timer, FuriTimerTypeOnce, app); + app->display_timer = furi_timer_alloc(notification_display_timer, FuriTimerTypePeriodic, app); app->settings.speaker_volume = 1.0f; app->settings.display_brightness = 1.0f; app->settings.led_brightness = 1.0f; app->settings.display_off_delay_ms = 30000; app->settings.vibro_on = true; - app->settings.rgb_mod_installed = false; app->display.value[LayerInternal] = 0x00; app->display.value[LayerNotification] = 0x00; @@ -552,7 +583,25 @@ static NotificationApp* notification_app_alloc(void) { furi_pubsub_subscribe(app->event_record, input_event_callback, app); notification_message(app, &sequence_display_backlight_on); + //RGB MOD SECTION + + //rgb mod + app->settings.rgb_mod_installed = false; + + //rgb mod rainbow init settings + app->settings.rgb_mod_rainbow = false; + app->settings.rgb_mod_rainbow_speed_ms = 1000; + app->settings.rgb_mod_rainbow_step = 1; + app->rgb_mod_rainbow_color1 = 1; + app->rgb_mod_rainbow_color2 = 1; + app->rgb_mod_rainbow_color3 = 1; + + //define rgb_mod_rainbow_timer and they callback + app->rgb_mod_rainbow_timer = + furi_timer_alloc(rgb_mod_rainbow_timer_callback, FuriTimerTypePeriodic, app); return app; + + // END OF RGB SECTION } static void notification_storage_callback(const void* message, void* context) { @@ -575,6 +624,8 @@ static void notification_apply_settings(NotificationApp* app) { } notification_apply_lcd_contrast(app); + // on system init start rgb_mod_rainbow_timer if they ON in config + rgb_mod_rainbow_timer_control(app); } static void notification_init_settings(NotificationApp* app) { @@ -619,6 +670,8 @@ int32_t notification_srv(void* p) { case SaveSettingsMessage: notification_save_settings(app); rgb_backlight_save_settings(); + //call rgb_mod_timer_control when we save settings + rgb_mod_rainbow_timer_control(app); break; case LoadSettingsMessage: notification_load_settings(app); diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 056a762df..098ef5ee7 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -44,7 +44,12 @@ typedef struct { uint32_t display_off_delay_ms; int8_t contrast; bool vibro_on; + bool rgb_mod_installed; + bool rgb_mod_rainbow; + uint32_t rgb_mod_rainbow_speed_ms; + uint32_t rgb_mod_rainbow_step; + } NotificationSettings; struct NotificationApp { @@ -56,6 +61,13 @@ struct NotificationApp { NotificationLedLayer led[NOTIFICATION_LED_COUNT]; uint8_t display_led_lock; + // rainbow mode section + FuriTimer* rgb_mod_rainbow_timer; + int8_t rgb_mod_rainbow_color1; + int8_t rgb_mod_rainbow_color2; + int8_t rgb_mod_rainbow_color3; + + NotificationSettings settings; }; diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index a34ac5b4a..941284c89 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -13,6 +13,7 @@ typedef struct { Gui* gui; ViewDispatcher* view_dispatcher; VariableItemList* variable_item_list; + VariableItemList* variable_item_list_rgb; } NotificationAppSettings; static VariableItem* temp_item; @@ -115,6 +116,50 @@ const char* const rgb_mod_text[RGB_MOD_COUNT] = { }; const bool rgb_mod_value[RGB_MOD_COUNT] = {false, true}; +#define RGB_MOD_RAINBOW_COUNT 2 +const char* const rgb_mod_rainbow_text[RGB_MOD_RAINBOW_COUNT] = { + "OFF", + "ON", +}; +const bool rgb_mod_rainbow_value[RGB_MOD_RAINBOW_COUNT] = {false, true}; + +#define RGB_MOD_RAINBOW_SPEED_COUNT 14 +const char* const rgb_mod_rainbow_speed_text[RGB_MOD_RAINBOW_SPEED_COUNT] = { + "0.1s", + "0.2s", + "0.3s", + "0.4s", + "0.6s", + "0.8s", + "1s", + "1.2s", + "1.4s", + "1.6s", + "1.8s", + "2s", + "2.5s", + "3s"}; +const uint32_t rgb_mod_rainbow_speed_value[RGB_MOD_RAINBOW_SPEED_COUNT] = + {100, 200, 400, 600, 800, 1000, 1200, 1400, 1600, 1800, 2000, 2500, 3000}; + +#define RGB_MOD_RAINBOW_STEP_COUNT 7 +const char* const rgb_mod_rainbow_step_text[RGB_MOD_RAINBOW_SPEED_COUNT] = { + "1", + "2", + "5", + "7", + "10", + "15", + "20", + }; +const uint32_t rgb_mod_rainbow_step_value[RGB_MOD_RAINBOW_STEP_COUNT] = + {1, 2, 5, 7, 10, 15, 20}; + +typedef enum { + MainViewId, + RGBViewId, +} ViewId; + static void contrast_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -186,6 +231,27 @@ static void rgb_mod_installed_changed(VariableItem* item) { app->notification->settings.rgb_mod_installed = rgb_mod_value[index]; } +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_text[index]); + app->notification->settings.rgb_mod_rainbow = rgb_mod_rainbow_value[index]; +} + +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->settings.rgb_mod_rainbow_speed_ms = rgb_mod_rainbow_speed_value[index]; +} + +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->settings.rgb_mod_rainbow_step = rgb_mod_rainbow_step_value[index]; +} + // Set RGB backlight color static void color_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); @@ -244,6 +310,23 @@ static uint32_t notification_app_settings_exit(void* context) { return VIEW_NONE; } +// 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->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; +} + static NotificationAppSettings* alloc_settings(void) { NotificationAppSettings* app = malloc(sizeof(NotificationAppSettings)); app->notification = furi_record_open(RECORD_NOTIFICATION); @@ -251,11 +334,21 @@ static NotificationAppSettings* alloc_settings(void) { app->variable_item_list = variable_item_list_alloc(); View* view = variable_item_list_get_view(app->variable_item_list); + //set callback for exit from view view_set_previous_callback(view, notification_app_settings_exit); + // set callback for OK pressed in menu + variable_item_list_set_enter_callback( + app->variable_item_list, variable_item_list_enter_callback, app); VariableItem* item; uint8_t value_index; + //Show RGB settings only when debug_mode or rgb_mod_installed is active + if((app->notification->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); + } + item = variable_item_list_add( app->variable_item_list, "LCD Contrast", CONTRAST_COUNT, contrast_changed, app); value_index = @@ -263,58 +356,6 @@ static NotificationAppSettings* alloc_settings(void) { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, contrast_text[value_index]); - // 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 MOD Installed", - RGB_MOD_COUNT, - rgb_mod_installed_changed, - app); - value_index = value_index_bool( - app->notification->settings.rgb_mod_installed, rgb_mod_value, RGB_MOD_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, rgb_mod_text[value_index]); - } - - //Show RGB settings only when rgb_mod_installed is true - if(app->notification->settings.rgb_mod_installed) { - // RGB Colors - item = variable_item_list_add( - app->variable_item_list, - "LCD Color", - rgb_backlight_get_color_count(), - color_changed, - app); - value_index = rgb_backlight_get_settings()->display_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)); - temp_item = item; - - // Custom Color - REFACTOR THIS - item = variable_item_list_add( - app->variable_item_list, "Custom Red", 255, color_set_custom_red, app); - value_index = rgb_backlight_get_settings()->custom_r; - 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); - - item = variable_item_list_add( - app->variable_item_list, "Custom Green", 255, color_set_custom_green, app); - value_index = rgb_backlight_get_settings()->custom_g; - variable_item_set_current_value_index(item, value_index); - snprintf(valtext, sizeof(valtext), "%d", value_index); - variable_item_set_current_value_text(item, valtext); - - item = variable_item_list_add( - app->variable_item_list, "Custom Blue", 255, color_set_custom_blue, app); - value_index = rgb_backlight_get_settings()->custom_b; - variable_item_set_current_value_index(item, value_index); - snprintf(valtext, sizeof(valtext), "%d", value_index); - variable_item_set_current_value_text(item, valtext); - // End of RGB - } item = variable_item_list_add( app->variable_item_list, "LCD Brightness", BACKLIGHT_COUNT, backlight_changed, app); value_index = value_index_float( @@ -364,17 +405,123 @@ static NotificationAppSettings* alloc_settings(void) { variable_item_set_current_value_text(item, vibro_text[value_index]); } + // RGB settings view + 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_COUNT, + rgb_mod_installed_changed, + app); + value_index = value_index_bool( + app->notification->settings.rgb_mod_installed, rgb_mod_value, RGB_MOD_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_mod_text[value_index]); + } + + // RGB Colors settings + item = variable_item_list_add( + app->variable_item_list_rgb, + "LCD Color", + rgb_backlight_get_color_count(), + color_changed, + app); + value_index = rgb_backlight_get_settings()->display_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->settings.rgb_mod_rainbow, "Rainbow mode\nenabled!"); + 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 = rgb_backlight_get_settings()->custom_r; + 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->settings.rgb_mod_rainbow, "Rainbow mode\nenabled!"); + + item = variable_item_list_add( + app->variable_item_list_rgb, "Custom Green", 255, color_set_custom_green, app); + value_index = rgb_backlight_get_settings()->custom_g; + 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->settings.rgb_mod_rainbow, "Rainbow mode\nenabled!"); + + item = variable_item_list_add( + app->variable_item_list_rgb, "Custom Blue", 255, color_set_custom_blue, app); + value_index = rgb_backlight_get_settings()->custom_b; + 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->settings.rgb_mod_rainbow, "Rainbow mode\nenabled!"); + // End of RGB + + // Rainbow (based on Willy-JL idea) settings + item = variable_item_list_add( + app->variable_item_list_rgb, + "Rainbow mode", + RGB_MOD_RAINBOW_COUNT, + rgb_mod_rainbow_changed, + app); + value_index = value_index_bool( + app->notification->settings.rgb_mod_rainbow, rgb_mod_rainbow_value, RGB_MOD_RAINBOW_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_mod_rainbow_text[value_index]); + + 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->settings.rgb_mod_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]); + + 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->settings.rgb_mod_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]); + + // End of Rainbow settings + 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); @@ -387,6 +534,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; -} + } From 82fd6b213093226e232d0534396c62f74b3c29fe Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Tue, 4 Mar 2025 23:34:11 +0700 Subject: [PATCH 005/125] RGB Rainbow still in development. --- .../services/notification/notification_app.c | 93 ++++++++++++------- .../services/notification/notification_app.h | 6 +- 2 files changed, 64 insertions(+), 35 deletions(-) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 229f7c5ea..3811c2fde 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -189,6 +189,61 @@ static void notification_display_timer(void* ctx) { notification_message(app, &sequence_display_backlight_off); } +// RGB MOD RAINBOW SECTION + +//start furi timer for rgb_mod_rainbow +static void rgb_mod_rainbow_timer_start(NotificationApp* app) { + furi_timer_start( + app->rgb_mod_rainbow_timer, furi_ms_to_ticks(app->settings.rgb_mod_rainbow_speed_ms)); +} + +//stop furi timer for rgb_mod_rainbow +static void rgb_mod_rainbow_timer_stop(NotificationApp* app) { + furi_timer_stop(app->rgb_mod_rainbow_timer); +} + +// start/stop rgb_mod_rainbow_timer only if rgb_mod_installed +static void rgb_mod_rainbow_timer_control(NotificationApp* app) { + if(app->settings.rgb_mod_installed) { + if(app->settings.rgb_mod_rainbow) { + rgb_mod_rainbow_timer_start(app); + } else { + if(furi_timer_is_running(app->rgb_mod_rainbow_timer)) { + rgb_mod_rainbow_timer_stop(app); + } + } + } +} + +// callback for rgb_mod_rainbow_timer (what we do when timer end) +static void rgb_mod_rainbow_timer_callback(void* context) { + furi_assert(context); + NotificationApp* app = context; + +// УЧЕСТЬ СТЕП и его вероятность превысить 255 +// При выключении радуги активировать настроенный в меню цвет + + app->rgb_mod_rainbow_color3++; + + if(app->rgb_mod_rainbow_color3 == 255) { + app->rgb_mod_rainbow_color2++; + app->rgb_mod_rainbow_color3 = 1; + } + + if(app->rgb_mod_rainbow_color2 == 255) { + app->rgb_mod_rainbow_color1++; + app->rgb_mod_rainbow_color2 = 1; + } + if(app->rgb_mod_rainbow_color1 == 255) { + app->rgb_mod_rainbow_color1 = 1; + } + FURI_LOG_I("RAINBOW", "Color3 %u", app->rgb_mod_rainbow_color3); + FURI_LOG_I("RAINBOW", "Color2 %u", app->rgb_mod_rainbow_color2); + FURI_LOG_I("RAINBOW", "Color1 %u", app->rgb_mod_rainbow_color1); +} + +// END OF RGB MOD RAINBOW SECTION + // message processing static void notification_process_notification_message( NotificationApp* app, @@ -219,12 +274,18 @@ 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 + rgb_mod_rainbow_timer_control(app); } 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_mod_rainbow_timer)) { + rgb_mod_rainbow_timer_stop(app); + } } break; case NotificationMessageTypeLedDisplayBacklightEnforceOn: @@ -512,38 +573,6 @@ static void input_event_callback(const void* value, void* context) { notification_message(app, &sequence_display_backlight_on); } -// RGB MOD RAINBOW SECTION - -//start furi timer for rgb_mod_rainbow -static void rgb_mod_rainbow_timer_start(NotificationApp* app) { - furi_timer_start( - app->rgb_mod_rainbow_timer, furi_ms_to_ticks(app->settings.rgb_mod_rainbow_speed_ms)); -} - -//stop furi timer for rgb_mod_rainbow -static void rgb_mod_rainbow_timer_stop(NotificationApp* app) { - furi_timer_stop(app->rgb_mod_rainbow_timer); -} - -// start/stop rgb_mod_rainbow_timer only if rgb_mod_installed -static void rgb_mod_rainbow_timer_control(NotificationApp* app) { - if(app->settings.rgb_mod_installed) { - if(app->settings.rgb_mod_rainbow) { - rgb_mod_rainbow_timer_start(app); - } else { - rgb_mod_rainbow_timer_stop(app); - } - } -} - -// callback for rgb_mod_rainbow_timer (what we do when timer end) -static void rgb_mod_rainbow_timer_callback(void* context) { - furi_assert(context); - FURI_LOG_I("RAINBOW", "Rainbow timer callback - change color"); -} - -// END OF RGB MOD RAINBOW SECTION - // App alloc static NotificationApp* notification_app_alloc(void) { NotificationApp* app = malloc(sizeof(NotificationApp)); diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 098ef5ee7..13cfb7aac 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -63,9 +63,9 @@ struct NotificationApp { // rainbow mode section FuriTimer* rgb_mod_rainbow_timer; - int8_t rgb_mod_rainbow_color1; - int8_t rgb_mod_rainbow_color2; - int8_t rgb_mod_rainbow_color3; + uint8_t rgb_mod_rainbow_color1; + uint8_t rgb_mod_rainbow_color2; + uint8_t rgb_mod_rainbow_color3; NotificationSettings settings; From bf50f0cd2099f6023e38e0f2865610a80ffea2be Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Wed, 5 Mar 2025 22:47:28 +0700 Subject: [PATCH 006/125] Cosmetic changes. --- .../services/notification/notification_app.c | 43 +++++++++++-------- .../services/notification/notification_app.h | 9 ++-- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 3811c2fde..c9c1faa3b 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -220,26 +220,31 @@ static void rgb_mod_rainbow_timer_callback(void* context) { furi_assert(context); NotificationApp* app = context; -// УЧЕСТЬ СТЕП и его вероятность превысить 255 // При выключении радуги активировать настроенный в меню цвет - app->rgb_mod_rainbow_color3++; - - if(app->rgb_mod_rainbow_color3 == 255) { - app->rgb_mod_rainbow_color2++; - app->rgb_mod_rainbow_color3 = 1; + if(app->rgb_mod_rainbow_red >= 255) { + app->rgb_mod_rainbow_red = 1; + app->rgb_mod_rainbow_green += app->settings.rgb_mod_rainbow_step; } - if(app->rgb_mod_rainbow_color2 == 255) { - app->rgb_mod_rainbow_color1++; - app->rgb_mod_rainbow_color2 = 1; + if(app->rgb_mod_rainbow_green >= 255) { + app->rgb_mod_rainbow_green = 1; + app->rgb_mod_rainbow_blue += app->settings.rgb_mod_rainbow_step; } - if(app->rgb_mod_rainbow_color1 == 255) { - app->rgb_mod_rainbow_color1 = 1; + + if(app->rgb_mod_rainbow_blue >= 255) { + app->rgb_mod_rainbow_blue = 1; } - FURI_LOG_I("RAINBOW", "Color3 %u", app->rgb_mod_rainbow_color3); - FURI_LOG_I("RAINBOW", "Color2 %u", app->rgb_mod_rainbow_color2); - FURI_LOG_I("RAINBOW", "Color1 %u", app->rgb_mod_rainbow_color1); + + rgb_backlight_set_custom_color(app->rgb_mod_rainbow_red, 0); + rgb_backlight_set_custom_color(app->rgb_mod_rainbow_green, 1); + rgb_backlight_set_custom_color(app->rgb_mod_rainbow_blue, 2); + + FURI_LOG_I("RAINBOW", "RED %u", app->rgb_mod_rainbow_red); + FURI_LOG_I("RAINBOW", "GREEN %u", app->rgb_mod_rainbow_green); + FURI_LOG_I("RAINBOW", "BLUE %u", app->rgb_mod_rainbow_blue); + + app->rgb_mod_rainbow_red += app->settings.rgb_mod_rainbow_step; } // END OF RGB MOD RAINBOW SECTION @@ -274,7 +279,7 @@ 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 + //start rgb_mod_rainbow_timer when display backlight is ON and all corresponding settings is ON too rgb_mod_rainbow_timer_control(app); } else { reset_mask &= ~reset_display_mask; @@ -621,9 +626,9 @@ static NotificationApp* notification_app_alloc(void) { app->settings.rgb_mod_rainbow = false; app->settings.rgb_mod_rainbow_speed_ms = 1000; app->settings.rgb_mod_rainbow_step = 1; - app->rgb_mod_rainbow_color1 = 1; - app->rgb_mod_rainbow_color2 = 1; - app->rgb_mod_rainbow_color3 = 1; + app->rgb_mod_rainbow_red = 1; + app->rgb_mod_rainbow_green = 1; + app->rgb_mod_rainbow_blue = 1; //define rgb_mod_rainbow_timer and they callback app->rgb_mod_rainbow_timer = @@ -699,7 +704,7 @@ int32_t notification_srv(void* p) { case SaveSettingsMessage: notification_save_settings(app); rgb_backlight_save_settings(); - //call rgb_mod_timer_control when we save settings + //call rgb_mod_timer_control (start or stop) when we save settings rgb_mod_rainbow_timer_control(app); break; case LoadSettingsMessage: diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 13cfb7aac..5220abcd9 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -48,7 +48,7 @@ typedef struct { bool rgb_mod_installed; bool rgb_mod_rainbow; uint32_t rgb_mod_rainbow_speed_ms; - uint32_t rgb_mod_rainbow_step; + uint16_t rgb_mod_rainbow_step; } NotificationSettings; @@ -63,11 +63,10 @@ struct NotificationApp { // rainbow mode section FuriTimer* rgb_mod_rainbow_timer; - uint8_t rgb_mod_rainbow_color1; - uint8_t rgb_mod_rainbow_color2; - uint8_t rgb_mod_rainbow_color3; + uint16_t rgb_mod_rainbow_red; + uint16_t rgb_mod_rainbow_green; + uint16_t rgb_mod_rainbow_blue; - NotificationSettings settings; }; From 5e6c2383895d40244a746c51689daa6ff0299431 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Mon, 10 Mar 2025 20:51:09 +0700 Subject: [PATCH 007/125] RGB mod rainbow effect done. --- .../services/notification/notification_app.c | 133 ++++++++++++------ .../services/notification/notification_app.h | 19 +-- .../notification_settings_app.c | 95 +++++++------ .../notification_settings/rgb_backlight.c | 12 ++ .../notification_settings/rgb_backlight.h | 3 + 5 files changed, 169 insertions(+), 93 deletions(-) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index c9c1faa3b..8096c2cc3 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -189,7 +189,7 @@ static void notification_display_timer(void* ctx) { notification_message(app, &sequence_display_backlight_off); } -// RGB MOD RAINBOW SECTION +// --- RGB MOD RAINBOW SECTION --- //start furi timer for rgb_mod_rainbow static void rgb_mod_rainbow_timer_start(NotificationApp* app) { @@ -202,10 +202,15 @@ static void rgb_mod_rainbow_timer_stop(NotificationApp* app) { furi_timer_stop(app->rgb_mod_rainbow_timer); } -// start/stop rgb_mod_rainbow_timer only if rgb_mod_installed -static void rgb_mod_rainbow_timer_control(NotificationApp* app) { +// start/restart/stop rgb_mod_rainbow_timer only if rgb_mod_installed and apply rainbow colors to backlight +static void rgb_mod_rainbow_timer_starter(NotificationApp* app) { if(app->settings.rgb_mod_installed) { - if(app->settings.rgb_mod_rainbow) { + if(app->settings.rgb_mod_rainbow_mode > 0) { + rgb_mod_rainbow_update( + app->rgb_mod_rainbow_red, + app->rgb_mod_rainbow_green, + app->rgb_mod_rainbow_blue, + app->settings.display_brightness); rgb_mod_rainbow_timer_start(app); } else { if(furi_timer_is_running(app->rgb_mod_rainbow_timer)) { @@ -220,34 +225,74 @@ static void rgb_mod_rainbow_timer_callback(void* context) { furi_assert(context); NotificationApp* app = context; -// При выключении радуги активировать настроенный в меню цвет + // if rgb_mode_rainbow_mode is rainbow do rainbow effect + if(app->settings.rgb_mod_rainbow_mode == 1) { + switch(app->rgb_mod_rainbow_stage) { + // from red to yellow + case 1: + app->rgb_mod_rainbow_green += app->settings.rgb_mod_rainbow_step; + if(app->rgb_mod_rainbow_green >= 255) { + app->rgb_mod_rainbow_green = 255; + app->rgb_mod_rainbow_stage++; + } + break; + // yellow red to green + case 2: + app->rgb_mod_rainbow_red -= app->settings.rgb_mod_rainbow_step; + if(app->rgb_mod_rainbow_red <= 0) { + app->rgb_mod_rainbow_red = 0; + app->rgb_mod_rainbow_stage++; + } + break; + // from green to light blue + case 3: + app->rgb_mod_rainbow_blue += app->settings.rgb_mod_rainbow_step; + if(app->rgb_mod_rainbow_blue >= 255) { + app->rgb_mod_rainbow_blue = 255; + app->rgb_mod_rainbow_stage++; + } + break; + //from light blue to blue + case 4: + app->rgb_mod_rainbow_green -= app->settings.rgb_mod_rainbow_step; + if(app->rgb_mod_rainbow_green <= 0) { + app->rgb_mod_rainbow_green = 0; + app->rgb_mod_rainbow_stage++; + } + break; + //from blue to violet + case 5: + app->rgb_mod_rainbow_red += app->settings.rgb_mod_rainbow_step; + if(app->rgb_mod_rainbow_red >= 255) { + app->rgb_mod_rainbow_red = 255; + app->rgb_mod_rainbow_stage++; + } + break; + //from violet to red + case 6: + app->rgb_mod_rainbow_blue -= app->settings.rgb_mod_rainbow_step; + if(app->rgb_mod_rainbow_blue <= 0) { + app->rgb_mod_rainbow_blue = 0; + app->rgb_mod_rainbow_stage = 1; + } + break; + default: + break; + } - if(app->rgb_mod_rainbow_red >= 255) { - app->rgb_mod_rainbow_red = 1; - app->rgb_mod_rainbow_green += app->settings.rgb_mod_rainbow_step; + rgb_mod_rainbow_update( + app->rgb_mod_rainbow_red, + app->rgb_mod_rainbow_green, + app->rgb_mod_rainbow_blue, + app->settings.display_brightness); } - if(app->rgb_mod_rainbow_green >= 255) { - app->rgb_mod_rainbow_green = 1; - app->rgb_mod_rainbow_blue += app->settings.rgb_mod_rainbow_step; - } - - if(app->rgb_mod_rainbow_blue >= 255) { - app->rgb_mod_rainbow_blue = 1; - } - - rgb_backlight_set_custom_color(app->rgb_mod_rainbow_red, 0); - rgb_backlight_set_custom_color(app->rgb_mod_rainbow_green, 1); - rgb_backlight_set_custom_color(app->rgb_mod_rainbow_blue, 2); - - FURI_LOG_I("RAINBOW", "RED %u", app->rgb_mod_rainbow_red); - FURI_LOG_I("RAINBOW", "GREEN %u", app->rgb_mod_rainbow_green); - FURI_LOG_I("RAINBOW", "BLUE %u", app->rgb_mod_rainbow_blue); - - app->rgb_mod_rainbow_red += app->settings.rgb_mod_rainbow_step; + // if rgb_mode_rainbow_mode is ..... do another effect + // if(app->settings.rgb_mod_rainbow_mode == 2) { + // } } -// END OF RGB MOD RAINBOW SECTION +// --- END OF RGB MOD RAINBOW SECTION --- // message processing static void notification_process_notification_message( @@ -279,8 +324,10 @@ 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 - rgb_mod_rainbow_timer_control(app); + rgb_mod_rainbow_timer_starter(app); + } else { reset_mask &= ~reset_display_mask; notification_reset_notification_led_layer(&app->display); @@ -617,25 +664,23 @@ static NotificationApp* notification_app_alloc(void) { furi_pubsub_subscribe(app->event_record, input_event_callback, app); notification_message(app, &sequence_display_backlight_on); - //RGB MOD SECTION + // --- RGB MOD INIT SETTINGS SECTION --- - //rgb mod app->settings.rgb_mod_installed = false; - - //rgb mod rainbow init settings - app->settings.rgb_mod_rainbow = false; - app->settings.rgb_mod_rainbow_speed_ms = 1000; - app->settings.rgb_mod_rainbow_step = 1; - app->rgb_mod_rainbow_red = 1; - app->rgb_mod_rainbow_green = 1; - app->rgb_mod_rainbow_blue = 1; + app->settings.rgb_mod_rainbow_mode = 0; + app->settings.rgb_mod_rainbow_speed_ms = 100; + app->settings.rgb_mod_rainbow_step = 5; + app->rgb_mod_rainbow_red = 255; + app->rgb_mod_rainbow_green = 0; + app->rgb_mod_rainbow_blue = 0; + app->rgb_mod_rainbow_stage = 1; //define rgb_mod_rainbow_timer and they callback app->rgb_mod_rainbow_timer = furi_timer_alloc(rgb_mod_rainbow_timer_callback, FuriTimerTypePeriodic, app); return app; - // END OF RGB SECTION + // --- END OF RGB MOD INIT SETTINGS SECTION --- } static void notification_storage_callback(const void* message, void* context) { @@ -658,8 +703,8 @@ static void notification_apply_settings(NotificationApp* app) { } notification_apply_lcd_contrast(app); - // on system init start rgb_mod_rainbow_timer if they ON in config - rgb_mod_rainbow_timer_control(app); + //start rgb_mod_rainbow_timer on system init if they ON in config + rgb_mod_rainbow_timer_starter(app); } static void notification_init_settings(NotificationApp* app) { @@ -702,10 +747,10 @@ int32_t notification_srv(void* p) { notification_process_internal_message(app, &message); break; case SaveSettingsMessage: - notification_save_settings(app); - rgb_backlight_save_settings(); //call rgb_mod_timer_control (start or stop) when we save settings - rgb_mod_rainbow_timer_control(app); + rgb_mod_rainbow_timer_starter(app); + rgb_backlight_save_settings(); + notification_save_settings(app); break; case LoadSettingsMessage: notification_load_settings(app); diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 5220abcd9..54b3ab7a9 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -44,11 +44,12 @@ typedef struct { uint32_t display_off_delay_ms; int8_t contrast; bool vibro_on; - + /// --- RGB MOD SETTINGS SECTION --- bool rgb_mod_installed; - bool rgb_mod_rainbow; + uint32_t rgb_mod_rainbow_mode; uint32_t rgb_mod_rainbow_speed_ms; uint16_t rgb_mod_rainbow_step; + /// --- END OF RGB MOD SETTINGS SECTION --- } NotificationSettings; @@ -61,13 +62,15 @@ struct NotificationApp { NotificationLedLayer led[NOTIFICATION_LED_COUNT]; uint8_t display_led_lock; - // rainbow mode section + // --- RGB RAINBOW MODE VARIABLES SECTION --- FuriTimer* rgb_mod_rainbow_timer; - uint16_t rgb_mod_rainbow_red; - uint16_t rgb_mod_rainbow_green; - uint16_t rgb_mod_rainbow_blue; - + int16_t rgb_mod_rainbow_red; + int16_t rgb_mod_rainbow_green; + int16_t rgb_mod_rainbow_blue; + uint8_t rgb_mod_rainbow_stage; + // --- ENd OF RGB RAINBOW MODE VARIABLES SECTION --- + NotificationSettings settings; }; -void notification_message_save_settings(NotificationApp* app); +void notification_message_save_settings(NotificationApp* app); \ No newline at end of file diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 941284c89..0def6769b 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -116,44 +116,36 @@ const char* const rgb_mod_text[RGB_MOD_COUNT] = { }; const bool rgb_mod_value[RGB_MOD_COUNT] = {false, true}; -#define RGB_MOD_RAINBOW_COUNT 2 -const char* const rgb_mod_rainbow_text[RGB_MOD_RAINBOW_COUNT] = { +#define RGB_MOD_RAINBOW_MODE_COUNT 2 +const char* const rgb_mod_rainbow_mode_text[RGB_MOD_RAINBOW_MODE_COUNT] = { "OFF", - "ON", + "Rainbow", }; -const bool rgb_mod_rainbow_value[RGB_MOD_RAINBOW_COUNT] = {false, true}; +const uint32_t rgb_mod_rainbow_mode_value[RGB_MOD_RAINBOW_MODE_COUNT] = {0, 1}; -#define RGB_MOD_RAINBOW_SPEED_COUNT 14 +#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.6s", - "0.8s", - "1s", - "1.2s", - "1.4s", - "1.6s", - "1.8s", - "2s", - "2.5s", - "3s"}; -const uint32_t rgb_mod_rainbow_speed_value[RGB_MOD_RAINBOW_SPEED_COUNT] = - {100, 200, 400, 600, 800, 1000, 1200, 1400, 1600, 1800, 2000, 2500, 3000}; + "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 7 +#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", - "15", - "20", - }; +}; const uint32_t rgb_mod_rainbow_step_value[RGB_MOD_RAINBOW_STEP_COUNT] = - {1, 2, 5, 7, 10, 15, 20}; + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; typedef enum { MainViewId, @@ -234,8 +226,25 @@ static void rgb_mod_installed_changed(VariableItem* item) { 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_text[index]); - app->notification->settings.rgb_mod_rainbow = rgb_mod_rainbow_value[index]; + variable_item_set_current_value_text(item, rgb_mod_rainbow_mode_text[index]); + app->notification->settings.rgb_mod_rainbow_mode = rgb_mod_rainbow_mode_value[index]; + + // Lock/Unlock color settings if rainbow mode Enabled/Disabled + for(int i = 0; i < 4; i++) { + VariableItem* t_item = variable_item_list_get(app->variable_item_list_rgb, i); + if(app->notification->settings.rgb_mod_rainbow_mode > 0) { + variable_item_set_locked(t_item, true, "Rainbow mode\nenabled!"); + } else { + variable_item_set_locked(t_item, false, "Rainbow mode\nenabled!"); + } + } + //save settings and start/stop rgb_mod_rainbow_timer + notification_message_save_settings(app->notification); + + // restore saved rgb backlight settings if we switch_off rainbow mode + if(app->notification->settings.rgb_mod_rainbow_mode == 0) { + rgb_backlight_update(app->notification->settings.display_brightness * 255, true); + } } static void rgb_mod_rainbow_speed_changed(VariableItem* item) { @@ -243,6 +252,8 @@ static void rgb_mod_rainbow_speed_changed(VariableItem* 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->settings.rgb_mod_rainbow_speed_ms = rgb_mod_rainbow_speed_value[index]; + //use message for restart rgb_mod_rainbow_timer with new delay + notification_message_save_settings(app->notification); } static void rgb_mod_rainbow_step_changed(VariableItem* item) { @@ -316,7 +327,8 @@ void variable_item_list_enter_callback(void* context, uint32_t index) { NotificationAppSettings* app = context; if(((app->notification->settings.rgb_mod_installed) || - (furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug))) && (index == 0)) { + (furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug))) && + (index == 0)) { view_dispatcher_switch_to_view(app->view_dispatcher, RGBViewId); } } @@ -405,7 +417,7 @@ static NotificationAppSettings* alloc_settings(void) { variable_item_set_current_value_text(item, vibro_text[value_index]); } - // RGB settings view + // --- RGB SETTINGS VIEW --- 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 @@ -436,7 +448,7 @@ static NotificationAppSettings* alloc_settings(void) { 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->settings.rgb_mod_rainbow, "Rainbow mode\nenabled!"); + item, (app->notification->settings.rgb_mod_rainbow_mode > 0), "Rainbow mode\nenabled!"); temp_item = item; // Custom Color - REFACTOR THIS @@ -448,7 +460,7 @@ static NotificationAppSettings* alloc_settings(void) { snprintf(valtext, sizeof(valtext), "%d", value_index); variable_item_set_current_value_text(item, valtext); variable_item_set_locked( - item, app->notification->settings.rgb_mod_rainbow, "Rainbow mode\nenabled!"); + item, (app->notification->settings.rgb_mod_rainbow_mode > 0), "Rainbow mode\nenabled!"); item = variable_item_list_add( app->variable_item_list_rgb, "Custom Green", 255, color_set_custom_green, app); @@ -457,7 +469,7 @@ static NotificationAppSettings* alloc_settings(void) { snprintf(valtext, sizeof(valtext), "%d", value_index); variable_item_set_current_value_text(item, valtext); variable_item_set_locked( - item, app->notification->settings.rgb_mod_rainbow, "Rainbow mode\nenabled!"); + item, (app->notification->settings.rgb_mod_rainbow_mode > 0), "Rainbow mode\nenabled!"); item = variable_item_list_add( app->variable_item_list_rgb, "Custom Blue", 255, color_set_custom_blue, app); @@ -466,20 +478,21 @@ static NotificationAppSettings* alloc_settings(void) { snprintf(valtext, sizeof(valtext), "%d", value_index); variable_item_set_current_value_text(item, valtext); variable_item_set_locked( - item, app->notification->settings.rgb_mod_rainbow, "Rainbow mode\nenabled!"); - // End of RGB + item, (app->notification->settings.rgb_mod_rainbow_mode > 0), "Rainbow mode\nenabled!"); // Rainbow (based on Willy-JL idea) settings item = variable_item_list_add( app->variable_item_list_rgb, "Rainbow mode", - RGB_MOD_RAINBOW_COUNT, + RGB_MOD_RAINBOW_MODE_COUNT, rgb_mod_rainbow_changed, app); - value_index = value_index_bool( - app->notification->settings.rgb_mod_rainbow, rgb_mod_rainbow_value, RGB_MOD_RAINBOW_COUNT); + value_index = value_index_uint32( + app->notification->settings.rgb_mod_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_text[value_index]); + variable_item_set_current_value_text(item, rgb_mod_rainbow_mode_text[value_index]); item = variable_item_list_add( app->variable_item_list_rgb, @@ -507,7 +520,7 @@ static NotificationAppSettings* alloc_settings(void) { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, rgb_mod_rainbow_step_text[value_index]); - // End of Rainbow settings + // --- End of RGB SETTING VIEW --- app->view_dispatcher = view_dispatcher_alloc(); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); @@ -542,4 +555,4 @@ int32_t notification_settings_app(void* p) { free_settings(app); return 0; - } +} diff --git a/applications/settings/notification_settings/rgb_backlight.c b/applications/settings/notification_settings/rgb_backlight.c index 4edd77568..4fcb898f7 100644 --- a/applications/settings/notification_settings/rgb_backlight.c +++ b/applications/settings/notification_settings/rgb_backlight.c @@ -215,3 +215,15 @@ void rgb_backlight_update(uint8_t brightness, bool bypass) { SK6805_update(); } + +// --- RGB MOD RAINBOW --- +void rgb_mod_rainbow_update(uint8_t red, uint8_t green, uint8_t blue, float brightness) { + for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { + uint8_t r = red * (brightness); + uint8_t g = green * (brightness); + uint8_t b = blue * (brightness); + SK6805_set_led_color(i, r, g, b); + } + SK6805_update(); +} +// --- END OF RGB MOD RAINBOW --- diff --git a/applications/settings/notification_settings/rgb_backlight.h b/applications/settings/notification_settings/rgb_backlight.h index f215ed312..66e0e26a1 100644 --- a/applications/settings/notification_settings/rgb_backlight.h +++ b/applications/settings/notification_settings/rgb_backlight.h @@ -89,3 +89,6 @@ uint8_t rgb_backlight_get_color_count(void); * @return Указатель на строку с названием цвета */ const char* rgb_backlight_get_color_text(uint8_t index); + +// set custom color to display; +void rgb_mod_rainbow_update(uint8_t red, uint8_t green, uint8_t blue, float brightness); From 82d3f452cd8093fff0d30f6dc4b94bb46c625b68 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Mon, 10 Mar 2025 21:02:37 +0700 Subject: [PATCH 008/125] Code cosmetic changes. --- .../notification_settings_app.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 0def6769b..da54ea8f2 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -109,6 +109,7 @@ const char* const vibro_text[VIBRO_COUNT] = { }; const bool vibro_value[VIBRO_COUNT] = {false, true}; +// --- RGB MOD RAINBOW --- #define RGB_MOD_COUNT 2 const char* const rgb_mod_text[RGB_MOD_COUNT] = { "OFF", @@ -152,6 +153,8 @@ typedef enum { RGBViewId, } ViewId; +// --- END OF RGB MOD RAINBOW --- + static void contrast_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -216,6 +219,8 @@ static void vibro_changed(VariableItem* item) { notification_message(app->notification, &sequence_single_vibro); } +// --- RGB MOD AND RAINBOW --- + 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); @@ -316,11 +321,6 @@ static void color_set_custom_blue(VariableItem* item) { notification_message(app->notification, &sequence_display_backlight_on); } -static uint32_t notification_app_settings_exit(void* context) { - UNUSED(context); - return VIEW_NONE; -} - // 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); @@ -338,6 +338,12 @@ static uint32_t notification_app_rgb_settings_exit(void* context) { UNUSED(context); return MainViewId; } +// --- END OF RGB MOD AND RAINBOW --- + +static uint32_t notification_app_settings_exit(void* context) { + UNUSED(context); + return VIEW_NONE; +} static NotificationAppSettings* alloc_settings(void) { NotificationAppSettings* app = malloc(sizeof(NotificationAppSettings)); @@ -346,8 +352,10 @@ static NotificationAppSettings* alloc_settings(void) { app->variable_item_list = variable_item_list_alloc(); View* view = variable_item_list_get_view(app->variable_item_list); + //set callback for exit from view view_set_previous_callback(view, notification_app_settings_exit); + // set callback for OK pressed in menu variable_item_list_set_enter_callback( app->variable_item_list, variable_item_list_enter_callback, app); From 687a6fd630c2f401897f7484c2796a12088d8375 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Tue, 11 Mar 2025 15:11:01 +0700 Subject: [PATCH 009/125] User Interface bug removed. --- .../notification_settings/notification_settings_app.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index da54ea8f2..8c6871acd 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -234,8 +234,10 @@ static void rgb_mod_rainbow_changed(VariableItem* item) { variable_item_set_current_value_text(item, rgb_mod_rainbow_mode_text[index]); app->notification->settings.rgb_mod_rainbow_mode = rgb_mod_rainbow_mode_value[index]; - // Lock/Unlock color settings if rainbow mode Enabled/Disabled - for(int i = 0; i < 4; i++) { + // 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(app->notification->settings.rgb_mod_rainbow_mode > 0) { variable_item_set_locked(t_item, true, "Rainbow mode\nenabled!"); From 9e6593c09e7c57745b1546892fb5f090df78b06a Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Tue, 11 Mar 2025 18:54:12 +0700 Subject: [PATCH 010/125] Start moving RGB MOD from Notification to RGB MOD service. --- applications/services/application.fam | 1 + .../services/rgb_backlight/application.fam | 11 +++++++++++ .../services/rgb_backlight/rgb_backlight.c | 15 +++++++++++++++ .../services/rgb_backlight/rgb_backlight.h | 0 applications/settings/application.fam | 2 ++ .../rgb_backlight_settings/application.fam | 9 +++++++++ .../rgb_backlight_settings.c | 13 +++++++++++++ .../rgb_backlight_settings.h | 0 lib/drivers/SK6805.c | 4 ++-- targets/f7/api_symbols.csv | 1 + 10 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 applications/services/rgb_backlight/application.fam create mode 100644 applications/services/rgb_backlight/rgb_backlight.c create mode 100644 applications/services/rgb_backlight/rgb_backlight.h create mode 100644 applications/settings/rgb_backlight_settings/application.fam create mode 100644 applications/settings/rgb_backlight_settings/rgb_backlight_settings.c create mode 100644 applications/settings/rgb_backlight_settings/rgb_backlight_settings.h 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/rgb_backlight/application.fam b/applications/services/rgb_backlight/application.fam new file mode 100644 index 000000000..168a7bbd0 --- /dev/null +++ b/applications/services/rgb_backlight/application.fam @@ -0,0 +1,11 @@ +App( + appid="rgb_backlight", + name="RgbBackLightSrv", + apptype=FlipperAppType.SERVICE, + entry_point="rgb_backlight_srv", + cdefines=["SRV_RGB_BACKLIGHT"], + stack_size=1 * 1024, + order=99, + sdk_headers=["rgb_backlight.h"], + provides=["rgb_backlight_settings"], +) \ 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..046cd4771 --- /dev/null +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -0,0 +1,15 @@ +#include +#include +#include +#include "rgb_backlight.h" + +#define TAG "RGB_BACKLIGHT_SRV" + +int32_t rgb_backlight_srv (void* p){ +UNUSED (p); +while (1){ + FURI_LOG_I (TAG,"working"); + furi_delay_ms (2000); +} +return 0; +} \ No newline at end of file diff --git a/applications/services/rgb_backlight/rgb_backlight.h b/applications/services/rgb_backlight/rgb_backlight.h new file mode 100644 index 000000000..e69de29bb diff --git a/applications/settings/application.fam b/applications/settings/application.fam index 1d6db35a7..8e184a706 100644 --- a/applications/settings/application.fam +++ b/applications/settings/application.fam @@ -6,6 +6,8 @@ App( "passport", "system_settings", "clock_settings", + "input_settings", + "rgb_backlight_settings", "about", ], ) diff --git a/applications/settings/rgb_backlight_settings/application.fam b/applications/settings/rgb_backlight_settings/application.fam new file mode 100644 index 000000000..50621228a --- /dev/null +++ b/applications/settings/rgb_backlight_settings/application.fam @@ -0,0 +1,9 @@ +App( + appid="rgb_backlight_settings", + name="RGB backlight", + apptype=FlipperAppType.SETTINGS, + entry_point="rgb_backlight_settings", + requires=["rgb_backlight"], + stack_size=1 * 1024, + order=110, +) \ No newline at end of file diff --git a/applications/settings/rgb_backlight_settings/rgb_backlight_settings.c b/applications/settings/rgb_backlight_settings/rgb_backlight_settings.c new file mode 100644 index 000000000..096852063 --- /dev/null +++ b/applications/settings/rgb_backlight_settings/rgb_backlight_settings.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include "rgb_backlight_settings.h" + +#define TAG "RGB_BACKLIGHT_SETTINGS" + +int32_t rgb_backlight_settings (void* p){ +UNUSED (p); +FURI_LOG_I (TAG,"Settings"); +furi_delay_ms (2000); +return 0; +} \ No newline at end of file diff --git a/applications/settings/rgb_backlight_settings/rgb_backlight_settings.h b/applications/settings/rgb_backlight_settings/rgb_backlight_settings.h new file mode 100644 index 000000000..e69de29bb diff --git a/lib/drivers/SK6805.c b/lib/drivers/SK6805.c index 8158c55a4..b6f525eb8 100644 --- a/lib/drivers/SK6805.c +++ b/lib/drivers/SK6805.c @@ -58,7 +58,7 @@ void SK6805_set_led_color(uint8_t led_index, uint8_t r, uint8_t g, uint8_t b) { void SK6805_update(void) { SK6805_init(); FURI_CRITICAL_ENTER(); - furi_delay_us(150); + furi_delay_us(100); uint32_t end; /* Последовательная отправка цветов светодиодов */ for(uint8_t lednumber = 0; lednumber < SK6805_LED_COUNT; lednumber++) { @@ -98,6 +98,6 @@ void SK6805_update(void) { } } } - furi_delay_us(150); + furi_delay_us(100); FURI_CRITICAL_EXIT(); } diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 7ad21efb5..f78775215 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -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,, From 4045628ac6552d4631376d90d417c295fda70d71 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Wed, 12 Mar 2025 02:19:17 +0700 Subject: [PATCH 011/125] Working on moving RGB routines from Notification to RGB service --- applications/services/input/input_settings.c | 1 - .../services/rgb_backlight/application.fam | 1 - .../services/rgb_backlight/rgb_backlight.c | 153 +++++++++++++++++- .../services/rgb_backlight/rgb_backlight.h | 44 +++++ .../rgb_backlight/rgb_backlight_settings.c | 95 +++++++++++ .../rgb_backlight/rgb_backlight_settings.h | 31 ++++ applications/settings/application.fam | 1 - .../rgb_backlight_settings/application.fam | 9 -- .../rgb_backlight_settings.c | 13 -- .../rgb_backlight_settings.h | 0 targets/f7/api_symbols.csv | 8 +- 11 files changed, 324 insertions(+), 32 deletions(-) create mode 100644 applications/services/rgb_backlight/rgb_backlight_settings.c create mode 100644 applications/services/rgb_backlight/rgb_backlight_settings.h delete mode 100644 applications/settings/rgb_backlight_settings/application.fam delete mode 100644 applications/settings/rgb_backlight_settings/rgb_backlight_settings.c delete mode 100644 applications/settings/rgb_backlight_settings/rgb_backlight_settings.h 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/rgb_backlight/application.fam b/applications/services/rgb_backlight/application.fam index 168a7bbd0..bb42d7b83 100644 --- a/applications/services/rgb_backlight/application.fam +++ b/applications/services/rgb_backlight/application.fam @@ -7,5 +7,4 @@ App( stack_size=1 * 1024, order=99, sdk_headers=["rgb_backlight.h"], - provides=["rgb_backlight_settings"], ) \ No newline at end of file diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index 046cd4771..f198ae13f 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -1,15 +1,156 @@ +/* + 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 STATIC_COLOR_COUNT (sizeof(colors) / sizeof(RGBBacklightStaticColor)) + #define TAG "RGB_BACKLIGHT_SRV" -int32_t rgb_backlight_srv (void* p){ -UNUSED (p); -while (1){ - FURI_LOG_I (TAG,"working"); - furi_delay_ms (2000); +static const RGBBacklightStaticColor 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}, +}; + +void rgb_backlight_set_custom_color(uint8_t red, uint8_t green, uint8_t blue, float brightness) { + for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { + uint8_t r = red * (brightness); + uint8_t g = green * (brightness); + uint8_t b = blue * (brightness); + SK6805_set_led_color(i, r, g, b); + } + SK6805_update(); } -return 0; + +static void rainbow_timer_callback(void* context) { + furi_assert(context); + RGBBacklightApp* app = context; + + // if rgb_mode_rainbow_mode is rainbow do rainbow effect + if(app->settings->rainbow_mode == 1) { + switch(app->rainbow_stage) { + // from red to yellow + case 1: + app->rainbow_green += app->settings->rainbow_step; + if(app->rainbow_green >= 255) { + app->rainbow_green = 255; + app->rainbow_stage++; + } + break; + // yellow red to green + case 2: + app->rainbow_red -= app->settings->rainbow_step; + if(app->rainbow_red <= 0) { + app->rainbow_red = 0; + app->rainbow_stage++; + } + break; + // from green to light blue + case 3: + app->rainbow_blue += app->settings->rainbow_step; + if(app->rainbow_blue >= 255) { + app->rainbow_blue = 255; + app->rainbow_stage++; + } + break; + //from light blue to blue + case 4: + app->rainbow_green -= app->settings->rainbow_step; + if(app->rainbow_green <= 0) { + app->rainbow_green = 0; + app->rainbow_stage++; + } + break; + //from blue to violet + case 5: + app->rainbow_red += app->settings->rainbow_step; + if(app->rainbow_red >= 255) { + app->rainbow_red = 255; + app->rainbow_stage++; + } + break; + //from violet to red + case 6: + app->rainbow_blue -= app->settings->rainbow_step; + if(app->rainbow_blue <= 0) { + app->rainbow_blue = 0; + app->rainbow_stage = 1; + } + break; + default: + break; + } + + rgb_backlight_set_custom_color( + app->rainbow_red, + app->rainbow_green, + app->rainbow_blue, + app->settings->brightness); + } + + // if rgb_mode_rainbow_mode is ..... do another effect + // if(app->settings.rainbow_mode == 2) { + // } +} + +void rgb_backlight_settings_apply(RGBBacklightSettings* settings) { + UNUSED (settings); + //запуск таймера если все включено + // применить сохраненые настройки цвета к дисплею статику или кастом если индекс=13 +} + +int32_t rgb_backlight_srv (void* 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); + + // load or init new settings and apply it + rgb_backlight_settings_load (app->settings); + rgb_backlight_settings_apply (app->settings); + + UNUSED(p); + while(1) { + FURI_LOG_I(TAG, "working"); + furi_delay_ms(2000); + } + return 0; } \ No newline at end of file diff --git a/applications/services/rgb_backlight/rgb_backlight.h b/applications/services/rgb_backlight/rgb_backlight.h index e69de29bb..88f3270c1 100644 --- a/applications/services/rgb_backlight/rgb_backlight.h +++ b/applications/services/rgb_backlight/rgb_backlight.h @@ -0,0 +1,44 @@ +/* + 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 "rgb_backlight_settings.h" +#include "SK6805.h" + +typedef struct { + char* name; + uint8_t red; + uint8_t green; + uint8_t blue; +} RGBBacklightStaticColor; + +typedef struct { + FuriTimer* rainbow_timer; + + int16_t rainbow_red; + int16_t rainbow_green; + int16_t rainbow_blue; + uint8_t rainbow_stage; + + RGBBacklightSettings* settings; + +} RGBBacklightApp; + +#define RECORD_RGB_BACKLIGHT "rgb_backlight" + 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..62cc47994 --- /dev/null +++ b/applications/services/rgb_backlight/rgb_backlight_settings.c @@ -0,0 +1,95 @@ +#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 display_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 0"); + memset(settings, 0, sizeof(RGBBacklightSettings)); + 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"); + } +} 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..f7a4af177 --- /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 display_static_color_index; + uint8_t custom_r; + uint8_t custom_g; + uint8_t custom_b; + 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 8e184a706..2ad4aa030 100644 --- a/applications/settings/application.fam +++ b/applications/settings/application.fam @@ -7,7 +7,6 @@ App( "system_settings", "clock_settings", "input_settings", - "rgb_backlight_settings", "about", ], ) diff --git a/applications/settings/rgb_backlight_settings/application.fam b/applications/settings/rgb_backlight_settings/application.fam deleted file mode 100644 index 50621228a..000000000 --- a/applications/settings/rgb_backlight_settings/application.fam +++ /dev/null @@ -1,9 +0,0 @@ -App( - appid="rgb_backlight_settings", - name="RGB backlight", - apptype=FlipperAppType.SETTINGS, - entry_point="rgb_backlight_settings", - requires=["rgb_backlight"], - stack_size=1 * 1024, - order=110, -) \ No newline at end of file diff --git a/applications/settings/rgb_backlight_settings/rgb_backlight_settings.c b/applications/settings/rgb_backlight_settings/rgb_backlight_settings.c deleted file mode 100644 index 096852063..000000000 --- a/applications/settings/rgb_backlight_settings/rgb_backlight_settings.c +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include -#include -#include "rgb_backlight_settings.h" - -#define TAG "RGB_BACKLIGHT_SETTINGS" - -int32_t rgb_backlight_settings (void* p){ -UNUSED (p); -FURI_LOG_I (TAG,"Settings"); -furi_delay_ms (2000); -return 0; -} \ No newline at end of file diff --git a/applications/settings/rgb_backlight_settings/rgb_backlight_settings.h b/applications/settings/rgb_backlight_settings/rgb_backlight_settings.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index f78775215..310a669ef 100644 --- 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,, @@ -411,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 @@ -3139,6 +3143,8 @@ 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_settings_load,void,RGBBacklightSettings* +Function,+,rgb_backlight_settings_save,void,const RGBBacklightSettings* Function,-,rindex,char*,"const char*, int" Function,-,rint,double,double Function,-,rintf,float,float From 7a19c9e5494839e2aa496aebd9932e5b47c0ffa1 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Wed, 12 Mar 2025 18:15:38 +0700 Subject: [PATCH 012/125] Still in progress --- .../services/notification/application.fam | 2 +- .../services/notification/notification_app.c | 239 +++++++++--------- .../services/notification/notification_app.h | 20 +- .../services/rgb_backlight/application.fam | 2 +- .../services/rgb_backlight/rgb_backlight.c | 176 +++++++++---- .../services/rgb_backlight/rgb_backlight.h | 24 +- .../rgb_backlight/rgb_backlight_settings.c | 2 +- .../rgb_backlight/rgb_backlight_settings.h | 8 +- .../notification_settings_app.c | 88 ++++--- .../notification_settings/rgb_backlight.c | 229 ----------------- .../notification_settings/rgb_backlight.h | 94 ------- lib/drivers/SK6805.h | 7 + targets/f7/api_symbols.csv | 9 +- targets/f7/furi_hal/furi_hal_light.c | 4 +- 14 files changed, 361 insertions(+), 543 deletions(-) delete mode 100644 applications/settings/notification_settings/rgb_backlight.c delete mode 100644 applications/settings/notification_settings/rgb_backlight.h 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 8096c2cc3..afb900706 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -9,7 +9,7 @@ #include "notification.h" #include "notification_messages.h" #include "notification_app.h" -#include "applications/settings/notification_settings/rgb_backlight.h" +#include "applications/services/rgb_backlight/rgb_backlight.h" #define TAG "NotificationSrv" @@ -189,110 +189,110 @@ static void notification_display_timer(void* ctx) { notification_message(app, &sequence_display_backlight_off); } -// --- RGB MOD RAINBOW SECTION --- +// // --- RGB MOD RAINBOW SECTION --- -//start furi timer for rgb_mod_rainbow -static void rgb_mod_rainbow_timer_start(NotificationApp* app) { - furi_timer_start( - app->rgb_mod_rainbow_timer, furi_ms_to_ticks(app->settings.rgb_mod_rainbow_speed_ms)); -} +// //start furi timer for rgb_mod_rainbow +// static void rgb_mod_rainbow_timer_start(NotificationApp* app) { +// furi_timer_start( +// app->rgb_mod_rainbow_timer, furi_ms_to_ticks(app->settings.rgb_mod_rainbow_speed_ms)); +// } -//stop furi timer for rgb_mod_rainbow -static void rgb_mod_rainbow_timer_stop(NotificationApp* app) { - furi_timer_stop(app->rgb_mod_rainbow_timer); -} +// //stop furi timer for rgb_mod_rainbow +// static void rgb_mod_rainbow_timer_stop(NotificationApp* app) { +// furi_timer_stop(app->rgb_mod_rainbow_timer); +// } -// start/restart/stop rgb_mod_rainbow_timer only if rgb_mod_installed and apply rainbow colors to backlight -static void rgb_mod_rainbow_timer_starter(NotificationApp* app) { - if(app->settings.rgb_mod_installed) { - if(app->settings.rgb_mod_rainbow_mode > 0) { - rgb_mod_rainbow_update( - app->rgb_mod_rainbow_red, - app->rgb_mod_rainbow_green, - app->rgb_mod_rainbow_blue, - app->settings.display_brightness); - rgb_mod_rainbow_timer_start(app); - } else { - if(furi_timer_is_running(app->rgb_mod_rainbow_timer)) { - rgb_mod_rainbow_timer_stop(app); - } - } - } -} +// // start/restart/stop rgb_mod_rainbow_timer only if rgb_mod_installed and apply rainbow colors to backlight +// static void rgb_mod_rainbow_timer_starter(NotificationApp* app) { +// if(app->settings.rgb_mod_installed) { +// if(app->settings.rgb_mod_rainbow_mode > 0) { +// rgb_mod_rainbow_update( +// app->rgb_mod_rainbow_red, +// app->rgb_mod_rainbow_green, +// app->rgb_mod_rainbow_blue, +// app->settings.display_brightness); +// rgb_mod_rainbow_timer_start(app); +// } else { +// if(furi_timer_is_running(app->rgb_mod_rainbow_timer)) { +// rgb_mod_rainbow_timer_stop(app); +// } +// } +// } +// } -// callback for rgb_mod_rainbow_timer (what we do when timer end) -static void rgb_mod_rainbow_timer_callback(void* context) { - furi_assert(context); - NotificationApp* app = context; +// // callback for rgb_mod_rainbow_timer (what we do when timer end) +// static void rgb_mod_rainbow_timer_callback(void* context) { +// furi_assert(context); +// NotificationApp* app = context; - // if rgb_mode_rainbow_mode is rainbow do rainbow effect - if(app->settings.rgb_mod_rainbow_mode == 1) { - switch(app->rgb_mod_rainbow_stage) { - // from red to yellow - case 1: - app->rgb_mod_rainbow_green += app->settings.rgb_mod_rainbow_step; - if(app->rgb_mod_rainbow_green >= 255) { - app->rgb_mod_rainbow_green = 255; - app->rgb_mod_rainbow_stage++; - } - break; - // yellow red to green - case 2: - app->rgb_mod_rainbow_red -= app->settings.rgb_mod_rainbow_step; - if(app->rgb_mod_rainbow_red <= 0) { - app->rgb_mod_rainbow_red = 0; - app->rgb_mod_rainbow_stage++; - } - break; - // from green to light blue - case 3: - app->rgb_mod_rainbow_blue += app->settings.rgb_mod_rainbow_step; - if(app->rgb_mod_rainbow_blue >= 255) { - app->rgb_mod_rainbow_blue = 255; - app->rgb_mod_rainbow_stage++; - } - break; - //from light blue to blue - case 4: - app->rgb_mod_rainbow_green -= app->settings.rgb_mod_rainbow_step; - if(app->rgb_mod_rainbow_green <= 0) { - app->rgb_mod_rainbow_green = 0; - app->rgb_mod_rainbow_stage++; - } - break; - //from blue to violet - case 5: - app->rgb_mod_rainbow_red += app->settings.rgb_mod_rainbow_step; - if(app->rgb_mod_rainbow_red >= 255) { - app->rgb_mod_rainbow_red = 255; - app->rgb_mod_rainbow_stage++; - } - break; - //from violet to red - case 6: - app->rgb_mod_rainbow_blue -= app->settings.rgb_mod_rainbow_step; - if(app->rgb_mod_rainbow_blue <= 0) { - app->rgb_mod_rainbow_blue = 0; - app->rgb_mod_rainbow_stage = 1; - } - break; - default: - break; - } +// // if rgb_mode_rainbow_mode is rainbow do rainbow effect +// if(app->settings.rgb_mod_rainbow_mode == 1) { +// switch(app->rgb_mod_rainbow_stage) { +// // from red to yellow +// case 1: +// app->rgb_mod_rainbow_green += app->settings.rgb_mod_rainbow_step; +// if(app->rgb_mod_rainbow_green >= 255) { +// app->rgb_mod_rainbow_green = 255; +// app->rgb_mod_rainbow_stage++; +// } +// break; +// // yellow red to green +// case 2: +// app->rgb_mod_rainbow_red -= app->settings.rgb_mod_rainbow_step; +// if(app->rgb_mod_rainbow_red <= 0) { +// app->rgb_mod_rainbow_red = 0; +// app->rgb_mod_rainbow_stage++; +// } +// break; +// // from green to light blue +// case 3: +// app->rgb_mod_rainbow_blue += app->settings.rgb_mod_rainbow_step; +// if(app->rgb_mod_rainbow_blue >= 255) { +// app->rgb_mod_rainbow_blue = 255; +// app->rgb_mod_rainbow_stage++; +// } +// break; +// //from light blue to blue +// case 4: +// app->rgb_mod_rainbow_green -= app->settings.rgb_mod_rainbow_step; +// if(app->rgb_mod_rainbow_green <= 0) { +// app->rgb_mod_rainbow_green = 0; +// app->rgb_mod_rainbow_stage++; +// } +// break; +// //from blue to violet +// case 5: +// app->rgb_mod_rainbow_red += app->settings.rgb_mod_rainbow_step; +// if(app->rgb_mod_rainbow_red >= 255) { +// app->rgb_mod_rainbow_red = 255; +// app->rgb_mod_rainbow_stage++; +// } +// break; +// //from violet to red +// case 6: +// app->rgb_mod_rainbow_blue -= app->settings.rgb_mod_rainbow_step; +// if(app->rgb_mod_rainbow_blue <= 0) { +// app->rgb_mod_rainbow_blue = 0; +// app->rgb_mod_rainbow_stage = 1; +// } +// break; +// default: +// break; +// } - rgb_mod_rainbow_update( - app->rgb_mod_rainbow_red, - app->rgb_mod_rainbow_green, - app->rgb_mod_rainbow_blue, - app->settings.display_brightness); - } +// rgb_mod_rainbow_update( +// app->rgb_mod_rainbow_red, +// app->rgb_mod_rainbow_green, +// app->rgb_mod_rainbow_blue, +// app->settings.display_brightness); +// } - // if rgb_mode_rainbow_mode is ..... do another effect - // if(app->settings.rgb_mod_rainbow_mode == 2) { - // } -} +// // if rgb_mode_rainbow_mode is ..... do another effect +// // if(app->settings.rgb_mod_rainbow_mode == 2) { +// // } +// } -// --- END OF RGB MOD RAINBOW SECTION --- +// // --- END OF RGB MOD RAINBOW SECTION --- // message processing static void notification_process_notification_message( @@ -326,7 +326,7 @@ static void notification_process_notification_message( reset_mask |= reset_display_mask; //start rgb_mod_rainbow_timer when display backlight is ON and all corresponding settings is ON too - rgb_mod_rainbow_timer_starter(app); + rainbow_timer_starter(app->rgb_srv); } else { reset_mask &= ~reset_display_mask; @@ -335,8 +335,8 @@ static void notification_process_notification_message( furi_timer_stop(app->display_timer); } //stop rgb_mod_rainbow_timer when display backlight is OFF - if(furi_timer_is_running(app->rgb_mod_rainbow_timer)) { - rgb_mod_rainbow_timer_stop(app); + if(furi_timer_is_running(app->rgb_srv->rainbow_timer)) { + rainbow_timer_stop(app->rgb_srv); } } break; @@ -664,25 +664,26 @@ static NotificationApp* notification_app_alloc(void) { furi_pubsub_subscribe(app->event_record, input_event_callback, app); notification_message(app, &sequence_display_backlight_on); - // --- RGB MOD INIT SETTINGS SECTION --- + // // --- RGB MOD INIT SETTINGS SECTION --- - app->settings.rgb_mod_installed = false; - app->settings.rgb_mod_rainbow_mode = 0; - app->settings.rgb_mod_rainbow_speed_ms = 100; - app->settings.rgb_mod_rainbow_step = 5; - app->rgb_mod_rainbow_red = 255; - app->rgb_mod_rainbow_green = 0; - app->rgb_mod_rainbow_blue = 0; - app->rgb_mod_rainbow_stage = 1; + // app->settings.rgb_mod_installed = false; + // app->settings.rgb_mod_rainbow_mode = 0; + // app->settings.rgb_mod_rainbow_speed_ms = 100; + // app->settings.rgb_mod_rainbow_step = 5; + // app->rgb_mod_rainbow_red = 255; + // app->rgb_mod_rainbow_green = 0; + // app->rgb_mod_rainbow_blue = 0; + // app->rgb_mod_rainbow_stage = 1; + + // //define rgb_mod_rainbow_timer and they callback + // app->rgb_mod_rainbow_timer = + // furi_timer_alloc(rgb_mod_rainbow_timer_callback, FuriTimerTypePeriodic, app); + // // --- END OF RGB MOD INIT SETTINGS SECTION --- - //define rgb_mod_rainbow_timer and they callback - app->rgb_mod_rainbow_timer = - furi_timer_alloc(rgb_mod_rainbow_timer_callback, FuriTimerTypePeriodic, app); return app; - - // --- END OF RGB MOD INIT SETTINGS SECTION --- } + static void notification_storage_callback(const void* message, void* context) { furi_assert(context); NotificationApp* app = context; @@ -703,8 +704,8 @@ static void notification_apply_settings(NotificationApp* app) { } notification_apply_lcd_contrast(app); - //start rgb_mod_rainbow_timer on system init if they ON in config - rgb_mod_rainbow_timer_starter(app); + // //start rgb_mod_rainbow_timer on system init if they ON in config + // rgb_mod_rainbow_timer_starter(app); } static void notification_init_settings(NotificationApp* app) { @@ -723,7 +724,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(); @@ -748,8 +749,8 @@ int32_t notification_srv(void* p) { break; case SaveSettingsMessage: //call rgb_mod_timer_control (start or stop) when we save settings - rgb_mod_rainbow_timer_starter(app); - rgb_backlight_save_settings(); + rainbow_timer_starter(app->rgb_srv); + rgb_backlight_settings_save(app->rgb_srv->settings); notification_save_settings(app); break; case LoadSettingsMessage: diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 54b3ab7a9..4383ca6bc 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 @@ -45,10 +46,10 @@ typedef struct { int8_t contrast; bool vibro_on; /// --- RGB MOD SETTINGS SECTION --- - bool rgb_mod_installed; - uint32_t rgb_mod_rainbow_mode; - uint32_t rgb_mod_rainbow_speed_ms; - uint16_t rgb_mod_rainbow_step; + // bool rgb_mod_installed; + // uint32_t rgb_mod_rainbow_mode; + // uint32_t rgb_mod_rainbow_speed_ms; + // uint16_t rgb_mod_rainbow_step; /// --- END OF RGB MOD SETTINGS SECTION --- } NotificationSettings; @@ -63,14 +64,15 @@ struct NotificationApp { uint8_t display_led_lock; // --- RGB RAINBOW MODE VARIABLES SECTION --- - FuriTimer* rgb_mod_rainbow_timer; - int16_t rgb_mod_rainbow_red; - int16_t rgb_mod_rainbow_green; - int16_t rgb_mod_rainbow_blue; - uint8_t rgb_mod_rainbow_stage; + // FuriTimer* rgb_mod_rainbow_timer; + // int16_t rgb_mod_rainbow_red; + // int16_t rgb_mod_rainbow_green; + // int16_t rgb_mod_rainbow_blue; + // uint8_t rgb_mod_rainbow_stage; // --- ENd OF RGB RAINBOW MODE VARIABLES SECTION --- NotificationSettings settings; + RGBBacklightApp* rgb_srv; }; 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 index bb42d7b83..5e05233db 100644 --- a/applications/services/rgb_backlight/application.fam +++ b/applications/services/rgb_backlight/application.fam @@ -5,6 +5,6 @@ App( entry_point="rgb_backlight_srv", cdefines=["SRV_RGB_BACKLIGHT"], stack_size=1 * 1024, - order=99, + 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 index f198ae13f..64c04b9cb 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -25,11 +25,11 @@ #include "rgb_backlight.h" -#define STATIC_COLOR_COUNT (sizeof(colors) / sizeof(RGBBacklightStaticColor)) +#define PREDEFINED_COLOR_COUNT (sizeof(colors) / sizeof(RGBBacklightPredefinedColor)) #define TAG "RGB_BACKLIGHT_SRV" -static const RGBBacklightStaticColor colors[] = { +static const RGBBacklightPredefinedColor colors[] = { {"Orange", 255, 60, 0}, {"Yellow", 255, 144, 0}, {"Spring", 167, 255, 0}, @@ -46,16 +46,89 @@ static const RGBBacklightStaticColor colors[] = { {"Custom", 0, 0, 0}, }; -void rgb_backlight_set_custom_color(uint8_t red, uint8_t green, uint8_t blue, float brightness) { +uint8_t rgb_backlight_get_color_count(void) { + return PREDEFINED_COLOR_COUNT; + } + +const char* rgb_backlight_get_color_text(uint8_t index) { + return colors[index].name; + } + + +void rgb_backlight_set_static_color(uint8_t index, float brightness) { + // use RECORD for acces to rgb service instance and use current_* colors and static colors + RGBBacklightApp* app = furi_record_open(RECORD_RGB_BACKLIGHT); + for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { - uint8_t r = red * (brightness); - uint8_t g = green * (brightness); - uint8_t b = blue * (brightness); + app->current_red = colors[index].red; + app->current_green = colors[index].green; + app->current_blue = colors[index].blue; + + uint8_t r = app->current_red * brightness; + uint8_t g = app->current_green * brightness; + uint8_t b = app->current_blue * brightness; + SK6805_set_led_color(i, r, g, b); } + + furi_record_close(RECORD_RGB_BACKLIGHT); SK6805_update(); } +// void rgb_backlight_set_custom_color(uint8_t red, uint8_t green, uint8_t blue, float brightness) { +// for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { +// uint8_t r = red * (brightness); +// uint8_t g = green * (brightness); +// uint8_t b = blue * (brightness); +// SK6805_set_led_color(i, r, g, b); +// } +// SK6805_update(); +// } + +// apply new brightness to current display color set +void rgb_backlight_update (float brightness) { + // use RECORD for acces to rgb service instance and use current_* colors + 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; + uint8_t g = app->current_green * brightness; + uint8_t b = app->current_blue * brightness; + SK6805_set_led_color(i, r, g, b); + } + + furi_record_close(RECORD_RGB_BACKLIGHT); + SK6805_update(); +} +//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->rgb_mod_installed) { + if(app->settings->rainbow_mode > 0) { + // rgb_backlight_set_custom_color( + // app->rainbow_red, + // app->rainbow_green, + // app->rainbow_blue, + // app->settings->brightness); + 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; @@ -63,51 +136,51 @@ static void rainbow_timer_callback(void* context) { // if rgb_mode_rainbow_mode is rainbow do rainbow effect if(app->settings->rainbow_mode == 1) { switch(app->rainbow_stage) { - // from red to yellow + // from red to yellow (255,0,0) - (255,255,0) case 1: - app->rainbow_green += app->settings->rainbow_step; - if(app->rainbow_green >= 255) { - app->rainbow_green = 255; + app->current_green += app->settings->rainbow_step; + if(app->current_green >= 255) { + app->current_green = 255; app->rainbow_stage++; } break; - // yellow red to green + // yellow to green (255,255,0) - (0,255,0) case 2: - app->rainbow_red -= app->settings->rainbow_step; - if(app->rainbow_red <= 0) { - app->rainbow_red = 0; + 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 + // from green to light blue (0,255,0) - (0,255,255) case 3: - app->rainbow_blue += app->settings->rainbow_step; - if(app->rainbow_blue >= 255) { - app->rainbow_blue = 255; + 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 + //from light blue to blue (0,255,255) - (0,0,255) case 4: - app->rainbow_green -= app->settings->rainbow_step; - if(app->rainbow_green <= 0) { - app->rainbow_green = 0; + app->current_green -= app->settings->rainbow_step; + if(app->current_green <= 0) { + app->current_green = 0; app->rainbow_stage++; } break; - //from blue to violet + //from blue to violet (0,0,255) - (255,0,255) case 5: - app->rainbow_red += app->settings->rainbow_step; - if(app->rainbow_red >= 255) { - app->rainbow_red = 255; + app->current_red += app->settings->rainbow_step; + if(app->current_red >= 255) { + app->current_red = 255; app->rainbow_stage++; } break; - //from violet to red + //from violet to red (255,0,255) - (255,0,0) case 6: - app->rainbow_blue -= app->settings->rainbow_step; - if(app->rainbow_blue <= 0) { - app->rainbow_blue = 0; + app->current_blue -= app->settings->rainbow_step; + if(app->current_blue <= 0) { + app->current_blue = 0; app->rainbow_stage = 1; } break; @@ -115,25 +188,23 @@ static void rainbow_timer_callback(void* context) { break; } - rgb_backlight_set_custom_color( - app->rainbow_red, - app->rainbow_green, - app->rainbow_blue, - app->settings->brightness); + // rgb_backlight_set_custom_color( + // app->current_red, + // app->current_green, + // app->current_blue, + // app->settings->brightness); } + + rgb_backlight_update (app->settings->brightness); // if rgb_mode_rainbow_mode is ..... do another effect // if(app->settings.rainbow_mode == 2) { // } } -void rgb_backlight_settings_apply(RGBBacklightSettings* settings) { - UNUSED (settings); - //запуск таймера если все включено - // применить сохраненые настройки цвета к дисплею статику или кастом если индекс=13 -} +int32_t rgb_backlight_srv (void* p) { + UNUSED(p); -int32_t rgb_backlight_srv (void* 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)); @@ -143,11 +214,28 @@ int32_t rgb_backlight_srv (void* p){ app->rainbow_timer = furi_timer_alloc(rainbow_timer_callback, FuriTimerTypePeriodic, app); - // load or init new settings and apply it + // settings load or create default rgb_backlight_settings_load (app->settings); - rgb_backlight_settings_apply (app->settings); - UNUSED(p); + // Init app variables + app->current_red = 255; + app->current_green = 60; + app->current_green = 0; + app->rainbow_stage = 1; + + // а нужно ли это все при старте сервиса, если мы получим сигнал на подсветку от Нотификейшена. Может вынести в ИНИТ и при старте нотиф дернуть его 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, app->settings->brightness); + } + // if not rgb_mod_installed set default static orange color (index=0) + } else { + rgb_backlight_set_static_color(0, app->settings->brightness); + } + while(1) { FURI_LOG_I(TAG, "working"); furi_delay_ms(2000); diff --git a/applications/services/rgb_backlight/rgb_backlight.h b/applications/services/rgb_backlight/rgb_backlight.h index 88f3270c1..531d3a9e7 100644 --- a/applications/services/rgb_backlight/rgb_backlight.h +++ b/applications/services/rgb_backlight/rgb_backlight.h @@ -17,23 +17,28 @@ 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; -} RGBBacklightStaticColor; +} RGBBacklightPredefinedColor; typedef struct { FuriTimer* rainbow_timer; - int16_t rainbow_red; - int16_t rainbow_green; - int16_t rainbow_blue; + int16_t current_red; + int16_t current_green; + int16_t current_blue; uint8_t rainbow_stage; RGBBacklightSettings* settings; @@ -42,3 +47,14 @@ typedef struct { #define RECORD_RGB_BACKLIGHT "rgb_backlight" +void rgb_backlight_update (float brightness); +void rgb_backlight_set_static_color(uint8_t index, float brightness); +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 index 62cc47994..9cf1c1440 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.c +++ b/applications/services/rgb_backlight/rgb_backlight_settings.c @@ -17,7 +17,7 @@ typedef struct { uint8_t version; bool rgb_mod_installed; - uint8_t display_static_color_index; + uint8_t static_color_index; uint8_t custom_r; uint8_t custom_g; uint8_t custom_b; diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.h b/applications/services/rgb_backlight/rgb_backlight_settings.h index f7a4af177..48b0c43b9 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.h +++ b/applications/services/rgb_backlight/rgb_backlight_settings.h @@ -7,10 +7,10 @@ typedef struct { uint8_t version; bool rgb_mod_installed; - uint8_t display_static_color_index; - uint8_t custom_r; - uint8_t custom_g; - uint8_t custom_b; + uint8_t static_color_index; + uint8_t custom_red; + uint8_t custom_green; + uint8_t custom_blue; float brightness; uint32_t rainbow_mode; diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 8c6871acd..c2262d327 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -4,7 +4,6 @@ #include #include #include -#include #define MAX_NOTIFICATION_SETTINGS 4 @@ -170,6 +169,8 @@ static void backlight_changed(VariableItem* item) { variable_item_set_current_value_text(item, backlight_text[index]); app->notification->settings.display_brightness = backlight_value[index]; + //save brightness to rgb backlight settings too + app->notification->rgb_srv->settings->brightness = backlight_value[index]; notification_message(app->notification, &sequence_display_backlight_on); } @@ -225,21 +226,21 @@ 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_text[index]); - app->notification->settings.rgb_mod_installed = rgb_mod_value[index]; + app->notification->rgb_srv->settings->rgb_mod_installed = rgb_mod_value[index]; } 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->settings.rgb_mod_rainbow_mode = rgb_mod_rainbow_mode_value[index]; + app->notification->rgb_srv->settings->rainbow_mode = rgb_mod_rainbow_mode_value[index]; // 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(app->notification->settings.rgb_mod_rainbow_mode > 0) { + if(app->notification->rgb_srv->settings->rainbow_mode > 0) { variable_item_set_locked(t_item, true, "Rainbow mode\nenabled!"); } else { variable_item_set_locked(t_item, false, "Rainbow mode\nenabled!"); @@ -249,8 +250,8 @@ static void rgb_mod_rainbow_changed(VariableItem* item) { notification_message_save_settings(app->notification); // restore saved rgb backlight settings if we switch_off rainbow mode - if(app->notification->settings.rgb_mod_rainbow_mode == 0) { - rgb_backlight_update(app->notification->settings.display_brightness * 255, true); + if(app->notification->rgb_srv->settings->rainbow_mode == 0) { + rgb_backlight_update(app->notification->settings.display_brightness); } } @@ -258,7 +259,7 @@ 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->settings.rgb_mod_rainbow_speed_ms = rgb_mod_rainbow_speed_value[index]; + app->notification->rgb_srv->settings->rainbow_speed_ms = rgb_mod_rainbow_speed_value[index]; //use message for restart rgb_mod_rainbow_timer with new delay notification_message_save_settings(app->notification); } @@ -267,14 +268,14 @@ 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->settings.rgb_mod_rainbow_step = rgb_mod_rainbow_step_value[index]; + app->notification->rgb_srv->settings->rainbow_step = rgb_mod_rainbow_step_value[index]; } -// Set RGB backlight color +// --- Set RGB backlight colors --- static void color_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - rgb_backlight_set_color(index); + rgb_backlight_set_static_color(index,app->notification->rgb_srv->settings->brightness); variable_item_set_current_value_text(item, rgb_backlight_get_color_text(index)); notification_message(app->notification, &sequence_display_backlight_on); } @@ -283,12 +284,18 @@ static void color_changed(VariableItem* item) { 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); - rgb_backlight_set_custom_color(index, 0); + + //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; + rgb_backlight_update(app->notification->rgb_srv->settings->brightness); + char valtext[4] = {}; snprintf(valtext, sizeof(valtext), "%d", index); variable_item_set_current_value_text(item, valtext); - rgb_backlight_set_color(13); - rgb_backlight_update(app->notification->settings.display_brightness * 0xFF, true); + + // 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)); @@ -297,12 +304,19 @@ static void color_set_custom_red(VariableItem* item) { 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); - rgb_backlight_set_custom_color(index, 1); - char valtext[4] = {}; + + //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; + rgb_backlight_update(app->notification->rgb_srv->settings->brightness); + + char valtext[4] = {}; snprintf(valtext, sizeof(valtext), "%d", index); variable_item_set_current_value_text(item, valtext); - rgb_backlight_set_color(13); - rgb_backlight_update(app->notification->settings.display_brightness * 0xFF, true); + // rgb_backlight_set_color(13); + // rgb_backlight_update(app->rgb_srv->settings->brightness); + // 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)); @@ -311,12 +325,18 @@ static void color_set_custom_green(VariableItem* item) { 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); - rgb_backlight_set_custom_color(index, 2); + //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; + rgb_backlight_update(app->notification->rgb_srv->settings->brightness); + char valtext[4] = {}; snprintf(valtext, sizeof(valtext), "%d", index); variable_item_set_current_value_text(item, valtext); - rgb_backlight_set_color(13); - rgb_backlight_update(app->notification->settings.display_brightness * 0xFF, true); + // rgb_backlight_set_color(13); + // rgb_backlight_update(app->rgb_srv->settings->brightness); + // 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)); @@ -328,7 +348,7 @@ void variable_item_list_enter_callback(void* context, uint32_t index) { UNUSED(context); NotificationAppSettings* app = context; - if(((app->notification->settings.rgb_mod_installed) || + 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); @@ -366,7 +386,7 @@ static NotificationAppSettings* alloc_settings(void) { uint8_t value_index; //Show RGB settings only when debug_mode or rgb_mod_installed is active - if((app->notification->settings.rgb_mod_installed) || + 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); } @@ -442,7 +462,7 @@ static NotificationAppSettings* alloc_settings(void) { rgb_mod_installed_changed, app); value_index = value_index_bool( - app->notification->settings.rgb_mod_installed, rgb_mod_value, RGB_MOD_COUNT); + app->notification->rgb_srv->settings->rgb_mod_installed, rgb_mod_value, RGB_MOD_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, rgb_mod_text[value_index]); } @@ -454,41 +474,41 @@ static NotificationAppSettings* alloc_settings(void) { rgb_backlight_get_color_count(), color_changed, app); - value_index = rgb_backlight_get_settings()->display_color_index; + 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->settings.rgb_mod_rainbow_mode > 0), "Rainbow mode\nenabled!"); + item, (app->notification->rgb_srv->settings->rainbow_mode > 0), "Rainbow mode\nenabled!"); 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 = rgb_backlight_get_settings()->custom_r; + 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->settings.rgb_mod_rainbow_mode > 0), "Rainbow mode\nenabled!"); + item, (app->notification->rgb_srv->settings->rainbow_mode > 0), "Rainbow mode\nenabled!"); item = variable_item_list_add( app->variable_item_list_rgb, "Custom Green", 255, color_set_custom_green, app); - value_index = rgb_backlight_get_settings()->custom_g; + 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->settings.rgb_mod_rainbow_mode > 0), "Rainbow mode\nenabled!"); + item, (app->notification->rgb_srv->settings->rainbow_mode > 0), "Rainbow mode\nenabled!"); item = variable_item_list_add( app->variable_item_list_rgb, "Custom Blue", 255, color_set_custom_blue, app); - value_index = rgb_backlight_get_settings()->custom_b; + 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->settings.rgb_mod_rainbow_mode > 0), "Rainbow mode\nenabled!"); + item, (app->notification->rgb_srv->settings->rainbow_mode > 0), "Rainbow mode\nenabled!"); // Rainbow (based on Willy-JL idea) settings item = variable_item_list_add( @@ -498,7 +518,7 @@ static NotificationAppSettings* alloc_settings(void) { rgb_mod_rainbow_changed, app); value_index = value_index_uint32( - app->notification->settings.rgb_mod_rainbow_mode, + 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); @@ -511,7 +531,7 @@ static NotificationAppSettings* alloc_settings(void) { rgb_mod_rainbow_speed_changed, app); value_index = value_index_uint32( - app->notification->settings.rgb_mod_rainbow_speed_ms, + 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); @@ -524,7 +544,7 @@ static NotificationAppSettings* alloc_settings(void) { rgb_mod_rainbow_step_changed, app); value_index = value_index_uint32( - app->notification->settings.rgb_mod_rainbow_step, + 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); diff --git a/applications/settings/notification_settings/rgb_backlight.c b/applications/settings/notification_settings/rgb_backlight.c deleted file mode 100644 index 4fcb898f7..000000000 --- a/applications/settings/notification_settings/rgb_backlight.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - 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 "rgb_backlight.h" -#include -#include - -#define RGB_BACKLIGHT_SETTINGS_VERSION 6 -#define RGB_BACKLIGHT_SETTINGS_FILE_NAME ".rgb_backlight.settings" -#define RGB_BACKLIGHT_SETTINGS_PATH INT_PATH(RGB_BACKLIGHT_SETTINGS_FILE_NAME) - -#define COLOR_COUNT (sizeof(colors) / sizeof(RGBBacklightColor)) - -#define TAG "RGB Backlight" - -static RGBBacklightSettings rgb_settings = { - .version = RGB_BACKLIGHT_SETTINGS_VERSION, - .display_color_index = 0, - .custom_r = 254, - .custom_g = 254, - .custom_b = 254, - .settings_is_loaded = false}; - -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; -} - -void rgb_backlight_load_settings(void) { - // Do not load settings if we are in other boot modes than normal - if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { - rgb_settings.settings_is_loaded = true; - return; - } - - // Wait for all required services to start and create their records - uint8_t timeout = 0; - while(!furi_record_exists(RECORD_STORAGE)) { - timeout++; - if(timeout > 150) { - rgb_settings.settings_is_loaded = true; - return; - } - furi_delay_ms(5); - } - - RGBBacklightSettings settings; - File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - const size_t settings_size = sizeof(RGBBacklightSettings); - - FURI_LOG_D(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_D(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; -} - -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); - - FURI_LOG_D(TAG, "saving settings to \"%s\"", RGB_BACKLIGHT_SETTINGS_PATH); - - memcpy(&settings, &rgb_settings, settings_size); - - bool fs_result = - storage_file_open(file, RGB_BACKLIGHT_SETTINGS_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS); - - if(fs_result) { - uint16_t bytes_count = storage_file_write(file, &settings, settings_size); - - if(bytes_count != settings_size) { - fs_result = false; - } - } - - if(fs_result) { - FURI_LOG_D(TAG, "save success"); - } else { - FURI_LOG_E(TAG, "save failed, %s", storage_file_get_error_desc(file)); - } - - 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_set_custom_color(uint8_t color, uint8_t index) { - if(index > 2) return; - if(index == 0) { - rgb_settings.custom_r = color; - } else if(index == 1) { - rgb_settings.custom_g = color; - } else if(index == 2) { - rgb_settings.custom_b = color; - } -} - -void rgb_backlight_update(uint8_t brightness, bool bypass) { - if(!rgb_settings.settings_is_loaded) { - rgb_backlight_load_settings(); - } - - if(!bypass) { - 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) { - return; - } - - last_brightness = brightness; - last_color_index = rgb_settings.display_color_index; - } - - for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { - if(rgb_settings.display_color_index == 13) { - uint8_t r = rgb_settings.custom_r * (brightness / 255.0f); - uint8_t g = rgb_settings.custom_g * (brightness / 255.0f); - uint8_t b = rgb_settings.custom_b * (brightness / 255.0f); - - SK6805_set_led_color(i, r, g, b); - } else { - if((colors[rgb_settings.display_color_index].red == 0) && - (colors[rgb_settings.display_color_index].green == 0) && - (colors[rgb_settings.display_color_index].blue == 0)) { - uint8_t r = colors[0].red * (brightness / 255.0f); - uint8_t g = colors[0].green * (brightness / 255.0f); - uint8_t b = colors[0].blue * (brightness / 255.0f); - - SK6805_set_led_color(i, r, g, b); - } else { - 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); - } - } - } - - SK6805_update(); -} - -// --- RGB MOD RAINBOW --- -void rgb_mod_rainbow_update(uint8_t red, uint8_t green, uint8_t blue, float brightness) { - for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { - uint8_t r = red * (brightness); - uint8_t g = green * (brightness); - uint8_t b = blue * (brightness); - SK6805_set_led_color(i, r, g, b); - } - SK6805_update(); -} -// --- END OF RGB MOD RAINBOW --- diff --git a/applications/settings/notification_settings/rgb_backlight.h b/applications/settings/notification_settings/rgb_backlight.h deleted file mode 100644 index 66e0e26a1..000000000 --- a/applications/settings/notification_settings/rgb_backlight.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - 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 "SK6805.h" - -typedef struct { - char* name; - uint8_t red; - uint8_t green; - uint8_t blue; -} RGBBacklightColor; - -typedef struct { - uint8_t version; - uint8_t display_color_index; - uint8_t custom_r; - uint8_t custom_g; - uint8_t custom_b; - bool settings_is_loaded; -} RGBBacklightSettings; - -/** - * @brief Получить текущие настройки RGB-подсветки - * - * @return Указатель на структуру настроек - */ -RGBBacklightSettings* rgb_backlight_get_settings(void); - -/** - * @brief Загрузить настройки подсветки с SD-карты - */ -void rgb_backlight_load_settings(void); - -/** - * @brief Сохранить текущие настройки RGB-подсветки - */ -void rgb_backlight_save_settings(void); - -/** - * @brief Применить текущие настройки RGB-подсветки - * - * @param brightness Яркость свечения (0-255) - * @param bypass Применить настройки принудительно - */ -void rgb_backlight_update(uint8_t brightness, bool bypass); - -/** - * @brief Установить цвет RGB-подсветки - * - * @param color_index Индекс цвета (0 - rgb_backlight_get_color_count()) - */ -void rgb_backlight_set_color(uint8_t color_index); - -/** - * @brief Set custom color values by index - 0=R 1=G 2=B - * - * @param color - color value (0-255) - * @param index - color index (0-2) 0=R 1=G 2=B - */ -void rgb_backlight_set_custom_color(uint8_t color, uint8_t index); - -/** - * @brief Получить количество доступных цветов - * - * @return Число доступных вариантов цвета - */ -uint8_t rgb_backlight_get_color_count(void); - -/** - * @brief Получить текстовое название цвета - * - * @param index Индекс из доступных вариантов цвета - * @return Указатель на строку с названием цвета - */ -const char* rgb_backlight_get_color_text(uint8_t index); - -// set custom color to display; -void rgb_mod_rainbow_update(uint8_t red, uint8_t green, uint8_t blue, float brightness); diff --git a/lib/drivers/SK6805.h b/lib/drivers/SK6805.h index c97054f6d..733f394ad 100644 --- a/lib/drivers/SK6805.h +++ b/lib/drivers/SK6805.h @@ -15,6 +15,9 @@ 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_ @@ -49,3 +52,7 @@ 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_ */ + +#ifdef __cplusplus +} +#endif diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 310a669ef..f25b9c273 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,83.1,, +Version,+,84.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,, @@ -3125,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, @@ -3143,8 +3146,12 @@ 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_static_color,void,"uint8_t, float" 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 9ee542034..6cc60da11 100644 --- a/targets/f7/furi_hal/furi_hal_light.c +++ b/targets/f7/furi_hal/furi_hal_light.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include "applications/services/rgb_backlight/rgb_backlight.h" #define LED_CURRENT_RED (50u) #define LED_CURRENT_GREEN (50u) @@ -46,7 +46,7 @@ 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_update(value, false); + rgb_backlight_update(value); } furi_hal_i2c_release(&furi_hal_i2c_handle_power); } From e589cf7246d9aab24cfa7d9b5c2980ea4910147a Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Thu, 13 Mar 2025 00:42:03 +0700 Subject: [PATCH 013/125] Still working --- applications/services/rgb_backlight/rgb_backlight.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index 64c04b9cb..bb1480793 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -71,8 +71,8 @@ void rgb_backlight_set_static_color(uint8_t index, float brightness) { SK6805_set_led_color(i, r, g, b); } - furi_record_close(RECORD_RGB_BACKLIGHT); SK6805_update(); + furi_record_close(RECORD_RGB_BACKLIGHT); } // void rgb_backlight_set_custom_color(uint8_t red, uint8_t green, uint8_t blue, float brightness) { @@ -208,6 +208,7 @@ int32_t rgb_backlight_srv (void* 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 @@ -215,12 +216,13 @@ int32_t rgb_backlight_srv (void* p) { 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->current_red = 255; app->current_green = 60; - app->current_green = 0; + app->current_blue = 0; app->rainbow_stage = 1; // а нужно ли это все при старте сервиса, если мы получим сигнал на подсветку от Нотификейшена. Может вынести в ИНИТ и при старте нотиф дернуть его 1 раз From c9313c6f52c3d530e63e7f0ebc4138a5fdc905e3 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Thu, 13 Mar 2025 18:06:39 +0700 Subject: [PATCH 014/125] still fucking )) --- .../services/notification/notification_app.c | 6 +- .../services/rgb_backlight/rgb_backlight.c | 88 ++++++++----------- .../services/rgb_backlight/rgb_backlight.h | 4 +- .../rgb_backlight/rgb_backlight_settings.c | 2 + .../notification_settings_app.c | 19 ++-- targets/f7/api_symbols.csv | 4 +- 6 files changed, 56 insertions(+), 67 deletions(-) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index afb900706..df3bf213e 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -748,9 +748,9 @@ int32_t notification_srv(void* p) { notification_process_internal_message(app, &message); break; case SaveSettingsMessage: - //call rgb_mod_timer_control (start or stop) when we save settings - rainbow_timer_starter(app->rgb_srv); - rgb_backlight_settings_save(app->rgb_srv->settings); + // //call rgb_mod_timer_control (start or stop) when we save settings + // rainbow_timer_starter(app->rgb_srv); + // rgb_backlight_settings_save(app->rgb_srv->settings); notification_save_settings(app); break; case LoadSettingsMessage: diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index bb1480793..f449edbee 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -25,11 +25,11 @@ #include "rgb_backlight.h" -#define PREDEFINED_COLOR_COUNT (sizeof(colors) / sizeof(RGBBacklightPredefinedColor)) +#define COLOR_COUNT (sizeof(colors) / sizeof(RGBBacklightColor)) #define TAG "RGB_BACKLIGHT_SRV" -static const RGBBacklightPredefinedColor colors[] = { +static const RGBBacklightColor colors[] = { {"Orange", 255, 60, 0}, {"Yellow", 255, 144, 0}, {"Spring", 167, 255, 0}, @@ -47,43 +47,32 @@ static const RGBBacklightPredefinedColor colors[] = { }; uint8_t rgb_backlight_get_color_count(void) { - return PREDEFINED_COLOR_COUNT; + return COLOR_COUNT; } const char* rgb_backlight_get_color_text(uint8_t index) { return colors[index].name; } - -void rgb_backlight_set_static_color(uint8_t index, float brightness) { - // use RECORD for acces to rgb service instance and use current_* colors and static colors +// 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); - - for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { - app->current_red = colors[index].red; - app->current_green = colors[index].green; - app->current_blue = colors[index].blue; - - uint8_t r = app->current_red * brightness; - uint8_t g = app->current_green * brightness; - uint8_t b = app->current_blue * brightness; - SK6805_set_led_color(i, r, g, b); - } - - SK6805_update(); + app->current_red = colors[index].red; + app->current_green = colors[index].green; + app->current_blue = colors[index].blue; + furi_record_close(RECORD_RGB_BACKLIGHT); } -// void rgb_backlight_set_custom_color(uint8_t red, uint8_t green, uint8_t blue, float brightness) { -// for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { -// uint8_t r = red * (brightness); -// uint8_t g = green * (brightness); -// uint8_t b = blue * (brightness); -// SK6805_set_led_color(i, r, g, b); -// } -// SK6805_update(); -// } +// 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); +} // apply new brightness to current display color set void rgb_backlight_update (float brightness) { @@ -96,10 +85,10 @@ void rgb_backlight_update (float brightness) { uint8_t b = app->current_blue * brightness; SK6805_set_led_color(i, r, g, b); } - - furi_record_close(RECORD_RGB_BACKLIGHT); SK6805_update(); + furi_record_close(RECORD_RGB_BACKLIGHT); } + //start furi timer for rainbow void rainbow_timer_start(RGBBacklightApp* app) { furi_timer_start( @@ -115,11 +104,6 @@ void rainbow_timer_stop(RGBBacklightApp* app) { void rainbow_timer_starter(RGBBacklightApp* app) { if(app->settings->rgb_mod_installed) { if(app->settings->rainbow_mode > 0) { - // rgb_backlight_set_custom_color( - // app->rainbow_red, - // app->rainbow_green, - // app->rainbow_blue, - // app->settings->brightness); rainbow_timer_start(app); } else { if(furi_timer_is_running(app->rainbow_timer)) { @@ -133,7 +117,7 @@ static void rainbow_timer_callback(void* context) { furi_assert(context); RGBBacklightApp* app = context; - // if rgb_mode_rainbow_mode is rainbow do rainbow effect + // 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) @@ -187,18 +171,12 @@ static void rainbow_timer_callback(void* context) { default: break; } - - // rgb_backlight_set_custom_color( - // app->current_red, - // app->current_green, - // app->current_blue, - // app->settings->brightness); - } - + } + //rgb_backlight_set_custom_color(app->current_red,app->current_green,app->current_blue); rgb_backlight_update (app->settings->brightness); - // if rgb_mode_rainbow_mode is ..... do another effect - // if(app->settings.rainbow_mode == 2) { + // if rainbow_mode is ..... do another effect + // if(app->settings.rainbow_mode == ...) { // } } @@ -206,7 +184,7 @@ 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 + // allocate memory and create RECORD for access to app structure from outside RGBBacklightApp* app = malloc(sizeof(RGBBacklightApp)); furi_record_create(RECORD_RGB_BACKLIGHT, app); @@ -220,22 +198,28 @@ int32_t rgb_backlight_srv (void* p) { rgb_backlight_settings_load (app->settings); // Init app variables - app->current_red = 255; - app->current_green = 60; - app->current_blue = 0; app->rainbow_stage = 1; + // app->current_red = 255; + // app->current_green = 60; + // app->current_blue = 0; + // а нужно ли это все при старте сервиса, если мы получим сигнал на подсветку от Нотификейшена. Может вынести в ИНИТ и при старте нотиф дернуть его 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 ) { + // app->current_red = 255; + // app->current_green = 0; + // app->current_blue = 0; rainbow_timer_starter(app); } else { - rgb_backlight_set_static_color(app->settings->static_color_index, app->settings->brightness); + rgb_backlight_set_static_color(app->settings->static_color_index); + rgb_backlight_update (app->settings->brightness); } // if not rgb_mod_installed set default static orange color (index=0) } else { - rgb_backlight_set_static_color(0, app->settings->brightness); + rgb_backlight_set_static_color(0); + rgb_backlight_update (app->settings->brightness); } while(1) { diff --git a/applications/services/rgb_backlight/rgb_backlight.h b/applications/services/rgb_backlight/rgb_backlight.h index 531d3a9e7..b0f5530ee 100644 --- a/applications/services/rgb_backlight/rgb_backlight.h +++ b/applications/services/rgb_backlight/rgb_backlight.h @@ -31,7 +31,7 @@ typedef struct { uint8_t red; uint8_t green; uint8_t blue; -} RGBBacklightPredefinedColor; +} RGBBacklightColor; typedef struct { FuriTimer* rainbow_timer; @@ -48,7 +48,7 @@ typedef struct { #define RECORD_RGB_BACKLIGHT "rgb_backlight" void rgb_backlight_update (float brightness); -void rgb_backlight_set_static_color(uint8_t index, float brightness); +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); diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.c b/applications/services/rgb_backlight/rgb_backlight_settings.c index 9cf1c1440..45a7ae65e 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.c +++ b/applications/services/rgb_backlight/rgb_backlight_settings.c @@ -91,5 +91,7 @@ void rgb_backlight_settings_save(const RGBBacklightSettings* settings) { if(!success) { FURI_LOG_E(TAG, "Failed to save rgb_backlight_settings file"); + } else { + FURI_LOG_I(TAG, "Settings saved"); } } diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index c2262d327..c62c78dd8 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -246,12 +246,13 @@ static void rgb_mod_rainbow_changed(VariableItem* item) { variable_item_set_locked(t_item, false, "Rainbow mode\nenabled!"); } } - //save settings and start/stop rgb_mod_rainbow_timer - notification_message_save_settings(app->notification); + + rainbow_timer_starter(app->notification->rgb_srv); + rgb_backlight_settings_save(app->notification->rgb_srv->settings); // restore saved rgb backlight settings if we switch_off rainbow mode if(app->notification->rgb_srv->settings->rainbow_mode == 0) { - rgb_backlight_update(app->notification->settings.display_brightness); + rgb_backlight_update(app->notification->rgb_srv->settings->brightness); } } @@ -271,16 +272,17 @@ static void rgb_mod_rainbow_step_changed(VariableItem* item) { app->notification->rgb_srv->settings->rainbow_step = rgb_mod_rainbow_step_value[index]; } -// --- Set RGB backlight colors --- +// 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); - rgb_backlight_set_static_color(index,app->notification->rgb_srv->settings->brightness); + rgb_backlight_set_static_color(index); variable_item_set_current_value_text(item, rgb_backlight_get_color_text(index)); + + rgb_backlight_update(app->notification->rgb_srv->settings->brightness); notification_message(app->notification, &sequence_display_backlight_on); } -// TODO: refactor and fix this 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); @@ -289,8 +291,7 @@ static void color_set_custom_red(VariableItem* item) { app->notification->rgb_srv->settings->custom_red = index; app->notification->rgb_srv->current_red = index; app->notification->rgb_srv->settings->static_color_index=13; - rgb_backlight_update(app->notification->rgb_srv->settings->brightness); - + char valtext[4] = {}; snprintf(valtext, sizeof(valtext), "%d", index); variable_item_set_current_value_text(item, valtext); @@ -299,6 +300,8 @@ static void color_set_custom_red(VariableItem* item) { // 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); notification_message(app->notification, &sequence_display_backlight_on); } static void color_set_custom_green(VariableItem* item) { diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index f25b9c273..ecb5047e8 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,84.1,, +Version,+,86.0,, 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,, @@ -3148,7 +3148,7 @@ 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_static_color,void,"uint8_t, float" +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 From 9b3d737693c072a91ed7bf47548358b168fa3ff0 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Fri, 14 Mar 2025 02:18:14 +0700 Subject: [PATCH 015/125] Moving RGB Backlight setings and effect to rgb service finished. --- .../services/notification/notification_app.c | 3 - .../services/rgb_backlight/rgb_backlight.c | 95 ++++----- .../services/rgb_backlight/rgb_backlight.h | 3 +- .../rgb_backlight/rgb_backlight_settings.c | 8 +- .../notification_settings_app.c | 193 +++++++++++------- targets/f7/api_symbols.csv | 3 +- targets/f7/furi_hal/furi_hal_light.c | 36 ++-- 7 files changed, 194 insertions(+), 147 deletions(-) mode change 100644 => 100755 targets/f7/api_symbols.csv diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index df3bf213e..4bd93cfbc 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -748,9 +748,6 @@ int32_t notification_srv(void* p) { notification_process_internal_message(app, &message); break; case SaveSettingsMessage: - // //call rgb_mod_timer_control (start or stop) when we save settings - // rainbow_timer_starter(app->rgb_srv); - // rgb_backlight_settings_save(app->rgb_srv->settings); notification_save_settings(app); break; case LoadSettingsMessage: diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index f449edbee..5510ea916 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -24,7 +24,6 @@ #include #include "rgb_backlight.h" - #define COLOR_COUNT (sizeof(colors) / sizeof(RGBBacklightColor)) #define TAG "RGB_BACKLIGHT_SRV" @@ -47,21 +46,27 @@ static const RGBBacklightColor colors[] = { }; uint8_t rgb_backlight_get_color_count(void) { - return COLOR_COUNT; - } + return COLOR_COUNT; +} const char* rgb_backlight_get_color_text(uint8_t index) { - return colors[index].name; - } + 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); - app->current_red = colors[index].red; - app->current_green = colors[index].green; - app->current_blue = colors[index].blue; - + //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); } @@ -74,15 +79,14 @@ void rgb_backlight_set_custom_color(uint8_t red, uint8_t green, uint8_t blue) { furi_record_close(RECORD_RGB_BACKLIGHT); } -// apply new brightness to current display color set -void rgb_backlight_update (float brightness) { - // use RECORD for acces to rgb service instance and use current_* colors +// 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; - uint8_t g = app->current_green * brightness; - uint8_t b = app->current_blue * brightness; + 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(); @@ -91,8 +95,7 @@ void rgb_backlight_update (float brightness) { //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)); + furi_timer_start(app->rainbow_timer, furi_ms_to_ticks(app->settings->rainbow_speed_ms)); } //stop furi timer for rainbow @@ -102,17 +105,15 @@ void rainbow_timer_stop(RGBBacklightApp* app) { // 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->rgb_mod_installed) { - if(app->settings->rainbow_mode > 0) { - rainbow_timer_start(app); - } else { - if(furi_timer_is_running(app->rainbow_timer)) { - rainbow_timer_stop(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; @@ -171,60 +172,50 @@ static void rainbow_timer_callback(void* context) { default: break; } - } - //rgb_backlight_set_custom_color(app->current_red,app->current_green,app->current_blue); - rgb_backlight_update (app->settings->brightness); + } + 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) { +int32_t rgb_backlight_srv(void* p) { UNUSED(p); - // Define object app (full app with settings and running variables), + // 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); + 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); + rgb_backlight_settings_load(app->settings); // Init app variables app->rainbow_stage = 1; - // app->current_red = 255; - // app->current_green = 60; - // app->current_blue = 0; - - // а нужно ли это все при старте сервиса, если мы получим сигнал на подсветку от Нотификейшена. Может вынести в ИНИТ и при старте нотиф дернуть его 1 раз - // if rgb_mod_installed start rainbow or set static color from settings (default index = 0) + // 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 ) { - // app->current_red = 255; - // app->current_green = 0; - // app->current_blue = 0; + 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); + rgb_backlight_update(app->settings->brightness); } - // if not rgb_mod_installed set default static orange color (index=0) + // 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); - } + rgb_backlight_update(app->settings->brightness); + } while(1) { - FURI_LOG_I(TAG, "working"); - furi_delay_ms(2000); + // place for message queue and other future options + furi_delay_ms(5000); + FURI_LOG_I(TAG, "Service is running"); } return 0; -} \ No newline at end of file +} diff --git a/applications/services/rgb_backlight/rgb_backlight.h b/applications/services/rgb_backlight/rgb_backlight.h index b0f5530ee..fd683bf16 100644 --- a/applications/services/rgb_backlight/rgb_backlight.h +++ b/applications/services/rgb_backlight/rgb_backlight.h @@ -47,7 +47,8 @@ typedef struct { #define RECORD_RGB_BACKLIGHT "rgb_backlight" -void rgb_backlight_update (float brightness); +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); diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.c b/applications/services/rgb_backlight/rgb_backlight_settings.c index 45a7ae65e..7e69eb0dc 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.c +++ b/applications/services/rgb_backlight/rgb_backlight_settings.c @@ -48,7 +48,8 @@ void rgb_backlight_settings_load(RGBBacklightSettings* settings) { 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)); + RGBBacklightSettingsPrevious* settings_previous = + malloc(sizeof(RGBBacklightSettingsPrevious)); success = saved_struct_load( RGB_BACKLIGHT_SETTINGS_PATH, @@ -73,8 +74,11 @@ void rgb_backlight_settings_load(RGBBacklightSettings* settings) { // 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 0"); + 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); } } diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index c62c78dd8..82e4526ae 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -4,6 +4,7 @@ #include #include #include +#include "applications/services/rgb_backlight/rgb_backlight.h" #define MAX_NOTIFICATION_SETTINGS 4 @@ -108,13 +109,13 @@ const char* const vibro_text[VIBRO_COUNT] = { }; const bool vibro_value[VIBRO_COUNT] = {false, true}; -// --- RGB MOD RAINBOW --- -#define RGB_MOD_COUNT 2 -const char* const rgb_mod_text[RGB_MOD_COUNT] = { +// --- 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_value[RGB_MOD_COUNT] = {false, true}; +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] = { @@ -152,7 +153,7 @@ typedef enum { RGBViewId, } ViewId; -// --- END OF RGB MOD RAINBOW --- +// --- RGB BACKLIGHT END --- static void contrast_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); @@ -169,8 +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]; - //save brightness to rgb backlight settings too + + //--- 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); } @@ -220,130 +226,155 @@ static void vibro_changed(VariableItem* item) { notification_message(app->notification, &sequence_single_vibro); } -// --- RGB MOD AND RAINBOW --- +//--- 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_text[index]); - app->notification->rgb_srv->settings->rgb_mod_installed = rgb_mod_value[index]; + 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++) { + 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(app->notification->rgb_srv->settings->rainbow_mode > 0) { + if(index > 0) { variable_item_set_locked(t_item, true, "Rainbow mode\nenabled!"); } else { variable_item_set_locked(t_item, false, "Rainbow mode\nenabled!"); } } - - rainbow_timer_starter(app->notification->rgb_srv); - rgb_backlight_settings_save(app->notification->rgb_srv->settings); // restore saved rgb backlight settings if we switch_off rainbow mode if(app->notification->rgb_srv->settings->rainbow_mode == 0) { - rgb_backlight_update(app->notification->rgb_srv->settings->brightness); + 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]; - //use message for restart rgb_mod_rainbow_timer with new delay - notification_message_save_settings(app->notification); + + //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); - rgb_backlight_set_static_color(index); - variable_item_set_current_value_text(item, rgb_backlight_get_color_text(index)); + 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); - notification_message(app->notification, &sequence_display_backlight_on); + 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; - + 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); - notification_message(app->notification, &sequence_display_backlight_on); + 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; - rgb_backlight_update(app->notification->rgb_srv->settings->brightness); - - char valtext[4] = {}; - snprintf(valtext, sizeof(valtext), "%d", index); - variable_item_set_current_value_text(item, valtext); - // rgb_backlight_set_color(13); - // rgb_backlight_update(app->rgb_srv->settings->brightness); - // 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)); - notification_message(app->notification, &sequence_display_backlight_on); -} -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; - rgb_backlight_update(app->notification->rgb_srv->settings->brightness); + //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); - // rgb_backlight_set_color(13); - // rgb_backlight_update(app->rgb_srv->settings->brightness); - + // 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)); - notification_message(app->notification, &sequence_display_backlight_on); + + 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) @@ -363,7 +394,7 @@ static uint32_t notification_app_rgb_settings_exit(void* context) { UNUSED(context); return MainViewId; } -// --- END OF RGB MOD AND RAINBOW --- +//--- RGB BACKLIGHT END --- static uint32_t notification_app_settings_exit(void* context) { UNUSED(context); @@ -378,21 +409,23 @@ static NotificationAppSettings* alloc_settings(void) { app->variable_item_list = variable_item_list_alloc(); View* view = variable_item_list_get_view(app->variable_item_list); - //set callback for exit from view - view_set_previous_callback(view, notification_app_settings_exit); - - // set callback for OK pressed in menu - variable_item_list_set_enter_callback( - app->variable_item_list, variable_item_list_enter_callback, app); - 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); @@ -450,9 +483,10 @@ static NotificationAppSettings* alloc_settings(void) { variable_item_set_current_value_text(item, vibro_text[value_index]); } - // --- RGB SETTINGS VIEW --- + //--- 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); @@ -461,16 +495,18 @@ static NotificationAppSettings* alloc_settings(void) { item = variable_item_list_add( app->variable_item_list_rgb, "RGB MOD Installed", - RGB_MOD_COUNT, + RGB_MOD_INSTALLED_COUNT, rgb_mod_installed_changed, app); value_index = value_index_bool( - app->notification->rgb_srv->settings->rgb_mod_installed, rgb_mod_value, RGB_MOD_COUNT); + 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_text[value_index]); + variable_item_set_current_value_text(item, rgb_mod_installed_text[value_index]); } - // RGB Colors settings + // Static Colors settings item = variable_item_list_add( app->variable_item_list_rgb, "LCD Color", @@ -482,6 +518,9 @@ static NotificationAppSettings* alloc_settings(void) { 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 @@ -494,6 +533,8 @@ static NotificationAppSettings* alloc_settings(void) { 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); @@ -503,6 +544,8 @@ static NotificationAppSettings* alloc_settings(void) { 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); @@ -512,6 +555,8 @@ static NotificationAppSettings* alloc_settings(void) { 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( @@ -526,6 +571,8 @@ static NotificationAppSettings* alloc_settings(void) { 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, @@ -539,6 +586,8 @@ static NotificationAppSettings* alloc_settings(void) { 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, @@ -552,8 +601,10 @@ static NotificationAppSettings* alloc_settings(void) { 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!"); - // --- End of RGB SETTING VIEW --- + //--- RGB BACKLIGHT END --- app->view_dispatcher = view_dispatcher_alloc(); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv old mode 100644 new mode 100755 index ecb5047e8..07bbe80f7 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,86.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,, @@ -3148,6 +3148,7 @@ 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* diff --git a/targets/f7/furi_hal/furi_hal_light.c b/targets/f7/furi_hal/furi_hal_light.c index 6cc60da11..2d6b4bbfe 100644 --- a/targets/f7/furi_hal/furi_hal_light.c +++ b/targets/f7/furi_hal/furi_hal_light.c @@ -32,23 +32,25 @@ void furi_hal_light_init(void) { } void furi_hal_light_set(Light light, uint8_t value) { - furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); - if(light & LightRed) { - lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value); - } - if(light & LightGreen) { - lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value); - } - if(light & LightBlue) { - lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value); - } - if(light & LightBacklight) { - 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_update(value); - } - furi_hal_i2c_release(&furi_hal_i2c_handle_power); + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + if(light & LightRed) { + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value); + } + if(light & LightGreen) { + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value); + } + if(light & LightBlue) { + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value); + } + if(light & LightBacklight) { + 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); } void furi_hal_light_blink_start(Light light, uint8_t brightness, uint16_t on_time, uint16_t period) { From cf63e9c03623ba0ea400303d7aeb756d216cef24 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Fri, 14 Mar 2025 18:40:19 +0700 Subject: [PATCH 016/125] Restore Input_vibro_touch compability with rgb_backlight. rgb_backlight driver litle bit improvements --- applications/services/input/input.c | 4 +++- lib/drivers/SK6805.c | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) 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/lib/drivers/SK6805.c b/lib/drivers/SK6805.c index b6f525eb8..2ad8e18d3 100644 --- a/lib/drivers/SK6805.c +++ b/lib/drivers/SK6805.c @@ -98,6 +98,5 @@ void SK6805_update(void) { } } } - furi_delay_us(100); FURI_CRITICAL_EXIT(); } From b2185594f21359ba3fae2c86446a62262f596f9c Mon Sep 17 00:00:00 2001 From: doomwastaken Date: Fri, 14 Mar 2025 20:19:24 +0300 Subject: [PATCH 017/125] increased hid remote stack, increased swipe speed, added enterprise sleep --- applications/system/hid_app/application.fam | 4 ++-- .../system/hid_app/views/hid_tiktok.c | 24 +++++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/applications/system/hid_app/application.fam b/applications/system/hid_app/application.fam index cc218c31a..5e7e421e3 100644 --- a/applications/system/hid_app/application.fam +++ b/applications/system/hid_app/application.fam @@ -3,7 +3,7 @@ App( name="Remote", apptype=FlipperAppType.EXTERNAL, entry_point="hid_usb_app", - stack_size=1 * 1024, + stack_size=1 * 1024 + 512, sources=["*.c", "!transport_ble.c"], cdefines=["HID_TRANSPORT_USB"], fap_description="Use Flipper as a HID remote control over USB", @@ -20,7 +20,7 @@ App( name="Remote", apptype=FlipperAppType.EXTERNAL, entry_point="hid_ble_app", - stack_size=1 * 1024, + stack_size=1 * 1024 + 512, sources=["*.c", "!transport_usb.c"], cdefines=["HID_TRANSPORT_BLE"], fap_libs=["ble_profile"], diff --git a/applications/system/hid_app/views/hid_tiktok.c b/applications/system/hid_app/views/hid_tiktok.c index f1501027c..f0997f72e 100644 --- a/applications/system/hid_app/views/hid_tiktok.c +++ b/applications/system/hid_app/views/hid_tiktok.c @@ -103,7 +103,10 @@ static void hid_tiktok_reset_cursor(HidTikTok* hid_tiktok) { furi_delay_ms(50); } // Move cursor from the corner - hid_hal_mouse_move(hid_tiktok->hid, 20, 120); + // Actions split for some mobiles to properly process mouse movements + hid_hal_mouse_move(hid_tiktok->hid, 10, 60); + furi_delay_ms(3); + hid_hal_mouse_move(hid_tiktok->hid, 0, 60); furi_delay_ms(50); } @@ -162,29 +165,30 @@ static bool hid_tiktok_input_callback(InputEvent* event, void* context) { consumed = true; } else if(event->type == InputTypeShort) { if(event->key == InputKeyOk) { + // delays adjusted for emulation of a finger tap hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); - furi_delay_ms(50); + furi_delay_ms(25); hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); - furi_delay_ms(50); + furi_delay_ms(75); hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); - furi_delay_ms(50); + furi_delay_ms(25); hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); consumed = true; } else if(event->key == InputKeyUp) { // Emulate up swipe - hid_hal_mouse_scroll(hid_tiktok->hid, -6); hid_hal_mouse_scroll(hid_tiktok->hid, -12); - hid_hal_mouse_scroll(hid_tiktok->hid, -19); + hid_hal_mouse_scroll(hid_tiktok->hid, -24); + hid_hal_mouse_scroll(hid_tiktok->hid, -38); + hid_hal_mouse_scroll(hid_tiktok->hid, -24); hid_hal_mouse_scroll(hid_tiktok->hid, -12); - hid_hal_mouse_scroll(hid_tiktok->hid, -6); consumed = true; } else if(event->key == InputKeyDown) { // Emulate down swipe - hid_hal_mouse_scroll(hid_tiktok->hid, 6); hid_hal_mouse_scroll(hid_tiktok->hid, 12); - hid_hal_mouse_scroll(hid_tiktok->hid, 19); + hid_hal_mouse_scroll(hid_tiktok->hid, 24); + hid_hal_mouse_scroll(hid_tiktok->hid, 38); + hid_hal_mouse_scroll(hid_tiktok->hid, 24); hid_hal_mouse_scroll(hid_tiktok->hid, 12); - hid_hal_mouse_scroll(hid_tiktok->hid, 6); consumed = true; } else if(event->key == InputKeyBack) { hid_hal_consumer_key_release_all(hid_tiktok->hid); From 61a54a1b06fb22ae16b72785c4279064e6cdc980 Mon Sep 17 00:00:00 2001 From: doomwastaken Date: Fri, 14 Mar 2025 20:25:38 +0300 Subject: [PATCH 018/125] decreased extra stack by 256b --- applications/system/hid_app/application.fam | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/system/hid_app/application.fam b/applications/system/hid_app/application.fam index 5e7e421e3..3a5e0951f 100644 --- a/applications/system/hid_app/application.fam +++ b/applications/system/hid_app/application.fam @@ -3,7 +3,7 @@ App( name="Remote", apptype=FlipperAppType.EXTERNAL, entry_point="hid_usb_app", - stack_size=1 * 1024 + 512, + stack_size=1 * 1024 + 256, sources=["*.c", "!transport_ble.c"], cdefines=["HID_TRANSPORT_USB"], fap_description="Use Flipper as a HID remote control over USB", @@ -20,7 +20,7 @@ App( name="Remote", apptype=FlipperAppType.EXTERNAL, entry_point="hid_ble_app", - stack_size=1 * 1024 + 512, + stack_size=1 * 1024 + 256, sources=["*.c", "!transport_usb.c"], cdefines=["HID_TRANSPORT_BLE"], fap_libs=["ble_profile"], From 8ca3581fb049559d7c7c42bf9cd151929f40b292 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 15 Mar 2025 07:23:23 +0300 Subject: [PATCH 019/125] subghz bugfixes and experimental options --- .../scenes/subghz_scene_radio_settings.c | 16 +- .../subghz/scenes/subghz_scene_set_type.c | 858 ++++++++++-------- .../subghz/scenes/subghz_scene_transmitter.c | 2 +- lib/subghz/protocols/alutech_at_4n.c | 2 +- lib/subghz/protocols/came_atomo.c | 2 +- lib/subghz/protocols/faac_slh.c | 68 +- lib/subghz/protocols/hay21.c | 3 + lib/subghz/protocols/keeloq.c | 4 +- lib/subghz/protocols/kinggates_stylo_4k.c | 2 +- lib/subghz/protocols/nice_flor_s.c | 2 +- lib/subghz/protocols/somfy_keytis.c | 2 +- lib/subghz/protocols/somfy_telis.c | 2 +- lib/subghz/protocols/star_line.c | 2 +- targets/f7/api_symbols.csv | 4 +- targets/f7/furi_hal/furi_hal_subghz.c | 6 +- targets/f7/furi_hal/furi_hal_subghz.h | 8 +- 16 files changed, 554 insertions(+), 429 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_radio_settings.c b/applications/main/subghz/scenes/subghz_scene_radio_settings.c index 974a2f564..8e808618b 100644 --- a/applications/main/subghz/scenes/subghz_scene_radio_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_radio_settings.c @@ -26,7 +26,7 @@ const char* const debug_pin_text[DEBUG_P_COUNT] = { "17(1W)", }; -#define DEBUG_COUNTER_COUNT 13 +#define DEBUG_COUNTER_COUNT 16 const char* const debug_counter_text[DEBUG_COUNTER_COUNT] = { "+1", "+2", @@ -34,21 +34,26 @@ const char* const debug_counter_text[DEBUG_COUNTER_COUNT] = { "+4", "+5", "+10", - "0", + "+50", + "OVFL", + "No", "-1", "-2", "-3", "-4", "-5", "-10", + "-50", }; -const uint32_t debug_counter_val[DEBUG_COUNTER_COUNT] = { +const int32_t debug_counter_val[DEBUG_COUNTER_COUNT] = { 1, 2, 3, 4, 5, 10, + 50, + 65535, 0, -1, -2, @@ -56,6 +61,7 @@ const uint32_t debug_counter_val[DEBUG_COUNTER_COUNT] = { -4, -5, -10, + -50, }; static void subghz_scene_radio_settings_set_device(VariableItem* item) { @@ -118,7 +124,7 @@ void subghz_scene_radio_settings_on_enter(void* context) { SubGhz* subghz = context; VariableItemList* variable_item_list = subghz->variable_item_list; - uint8_t value_index; + int32_t value_index; VariableItem* item; uint8_t value_count_device = RADIO_DEVICE_COUNT; @@ -152,7 +158,7 @@ void subghz_scene_radio_settings_on_enter(void* context) { furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) ? DEBUG_COUNTER_COUNT : 3, subghz_scene_receiver_config_set_debug_counter, subghz); - value_index = value_index_uint32( + value_index = value_index_int32( furi_hal_subghz_get_rolling_counter_mult(), debug_counter_val, furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) ? DEBUG_COUNTER_COUNT : 3); diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 20cef68df..3155f9f1e 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -193,104 +193,114 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { GenInfo gen_info = {0}; switch(event.event) { case SetTypePricenton433: - gen_info = (GenInfo){.type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_PRINCETON_NAME, - .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 - .data.bits = 24, - .data.te = 400}; + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_PRINCETON_NAME, + .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 + .data.bits = 24, + .data.te = 400}; break; case SetTypePricenton315: - gen_info = (GenInfo){.type = GenData, - .mod = "AM650", - .freq = 315000000, - .data.name = SUBGHZ_PROTOCOL_PRINCETON_NAME, - .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 - .data.bits = 24, - .data.te = 400}; + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 315000000, + .data.name = SUBGHZ_PROTOCOL_PRINCETON_NAME, + .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 + .data.bits = 24, + .data.te = 400}; break; case SetTypeNiceFlo12bit: - gen_info = (GenInfo){.type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_NICE_FLO_NAME, - .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 - .data.bits = 12, - .data.te = 0}; + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_NICE_FLO_NAME, + .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 + .data.bits = 12, + .data.te = 0}; break; case SetTypeNiceFlo24bit: - gen_info = (GenInfo){.type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_NICE_FLO_NAME, - .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 - .data.bits = 24, - .data.te = 0}; + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_NICE_FLO_NAME, + .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 + .data.bits = 24, + .data.te = 0}; break; case SetTypeCAME12bit: - gen_info = (GenInfo){.type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_CAME_NAME, - .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 - .data.bits = 12, - .data.te = 0}; + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_CAME_NAME, + .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 + .data.bits = 12, + .data.te = 0}; break; case SetTypeCAME24bit: - gen_info = (GenInfo){.type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_CAME_NAME, - .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 - .data.bits = 24, - .data.te = 0}; + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_CAME_NAME, + .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 + .data.bits = 24, + .data.te = 0}; break; case SetTypeCAME12bit868: - gen_info = (GenInfo){.type = GenData, - .mod = "AM650", - .freq = 868350000, - .data.name = SUBGHZ_PROTOCOL_CAME_NAME, - .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 - .data.bits = 12, - .data.te = 0}; + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 868350000, + .data.name = SUBGHZ_PROTOCOL_CAME_NAME, + .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 + .data.bits = 12, + .data.te = 0}; break; case SetTypeCAME24bit868: - gen_info = (GenInfo){.type = GenData, - .mod = "AM650", - .freq = 868350000, - .data.name = SUBGHZ_PROTOCOL_CAME_NAME, - .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 - .data.bits = 24, - .data.te = 0}; + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 868350000, + .data.name = SUBGHZ_PROTOCOL_CAME_NAME, + .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 + .data.bits = 24, + .data.te = 0}; break; case SetTypeLinear_300_00: - gen_info = (GenInfo){.type = GenData, - .mod = "AM650", - .freq = 300000000, - .data.name = SUBGHZ_PROTOCOL_LINEAR_NAME, - .data.key = (key & 0x3FF), - .data.bits = 10, - .data.te = 0}; + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 300000000, + .data.name = SUBGHZ_PROTOCOL_LINEAR_NAME, + .data.key = (key & 0x3FF), + .data.bits = 10, + .data.te = 0}; break; case SetTypeBETT_433: - gen_info = (GenInfo){.type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_BETT_NAME, - .data.key = (key & 0x0000FFF0), - .data.bits = 18, - .data.te = 0}; + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_BETT_NAME, + .data.key = (key & 0x0000FFF0), + .data.bits = 18, + .data.te = 0}; break; case SetTypeCAMETwee: - gen_info = (GenInfo){.type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_CAME_TWEE_NAME, - .data.key = 0x003FFF7200000000 | - ((key & 0x0FFFFFF0) ^ 0xE0E0E0EE), // ???? - .data.bits = 54, - .data.te = 0}; + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_CAME_TWEE_NAME, + .data.key = 0x003FFF7200000000 | ((key & 0x0FFFFFF0) ^ 0xE0E0E0EE), // ???? + .data.bits = 54, + .data.te = 0}; break; case SetTypeGateTX: gen_info = (GenInfo){ @@ -329,14 +339,14 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { .data.te = 0}; break; case SetTypeReversRB2_433: - gen_info = (GenInfo){.type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_REVERSRB2_NAME, // 64bits no buttons - .data.key = (key & 0x00000FFFFFFFF000) | 0xFFFFF00000000000 | - 0x0000000000000A00, - .data.bits = 64, - .data.te = 0}; + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_REVERSRB2_NAME, // 64bits no buttons + .data.key = (key & 0x00000FFFFFFFF000) | 0xFFFFF00000000000 | 0x0000000000000A00, + .data.bits = 64, + .data.te = 0}; break; case SetTypeMarantec24_868: gen_info = (GenInfo){ @@ -349,379 +359,421 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { .data.te = 0}; break; case SetTypeFaacSLH_433: - gen_info = (GenInfo){.type = GenFaacSLH, - .mod = "AM650", - .freq = 433920000, - .faac_slh.serial = ((key & 0x00FFFFF0) | 0xA0000006) >> 4, - .faac_slh.btn = 0x06, - .faac_slh.cnt = 0x02, - .faac_slh.seed = key, - .faac_slh.manuf = "FAAC_SLH"}; + gen_info = (GenInfo){ + .type = GenFaacSLH, + .mod = "AM650", + .freq = 433920000, + .faac_slh.serial = ((key & 0x00FFFFF0) | 0xA0000006) >> 4, + .faac_slh.btn = 0x06, + .faac_slh.cnt = 0x02, + .faac_slh.seed = key, + .faac_slh.manuf = "FAAC_SLH"}; break; case SetTypeFaacSLH_868: - gen_info = (GenInfo){.type = GenFaacSLH, - .mod = "AM650", - .freq = 868350000, - .faac_slh.serial = ((key & 0x00FFFFF0) | 0xA0000006) >> 4, - .faac_slh.btn = 0x06, - .faac_slh.cnt = 0x02, - .faac_slh.seed = (key & 0x0FFFFFFF), - .faac_slh.manuf = "FAAC_SLH"}; + gen_info = (GenInfo){ + .type = GenFaacSLH, + .mod = "AM650", + .freq = 868350000, + .faac_slh.serial = ((key & 0x00FFFFF0) | 0xA0000006) >> 4, + .faac_slh.btn = 0x06, + .faac_slh.cnt = 0x02, + .faac_slh.seed = (key & 0x0FFFFFFF), + .faac_slh.manuf = "FAAC_SLH"}; break; case SetTypeBeninca433: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x000FFF00) | 0x00800080, - .keeloq.btn = 0x01, - .keeloq.cnt = 0x05, - .keeloq.manuf = "Beninca"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x000FFF00) | 0x00800080, + .keeloq.btn = 0x01, + .keeloq.cnt = 0x05, + .keeloq.manuf = "Beninca"}; break; case SetTypeBeninca868: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 868350000, - .keeloq.serial = (key & 0x000FFF00) | 0x00800080, - .keeloq.btn = 0x01, - .keeloq.cnt = 0x05, - .keeloq.manuf = "Beninca"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 868350000, + .keeloq.serial = (key & 0x000FFF00) | 0x00800080, + .keeloq.btn = 0x01, + .keeloq.cnt = 0x05, + .keeloq.manuf = "Beninca"}; break; case SetTypeAllmatic433: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x00FFFF00) | 0x01000011, - .keeloq.btn = 0x0C, - .keeloq.cnt = 0x05, - .keeloq.manuf = "Beninca"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x00FFFF00) | 0x01000011, + .keeloq.btn = 0x0C, + .keeloq.cnt = 0x05, + .keeloq.manuf = "Beninca"}; break; case SetTypeAllmatic868: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 868350000, - .keeloq.serial = (key & 0x00FFFF00) | 0x01000011, - .keeloq.btn = 0x0C, - .keeloq.cnt = 0x05, - .keeloq.manuf = "Beninca"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 868350000, + .keeloq.serial = (key & 0x00FFFF00) | 0x01000011, + .keeloq.btn = 0x0C, + .keeloq.cnt = 0x05, + .keeloq.manuf = "Beninca"}; break; case SetTypeCenturion433: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x0000FFFF), - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Centurion"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x0000FFFF), + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Centurion"}; break; case SetTypeMonarch433: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x0000FFFF), - .keeloq.btn = 0x0A, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Monarch"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x0000FFFF), + .keeloq.btn = 0x0A, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Monarch"}; break; case SetTypeJollyMotors433: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x000FFFFF), - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Jolly_Motors"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x000FFFFF), + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Jolly_Motors"}; break; case SetTypeElmesElectronic: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x00FFFFFF) | 0x02000000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Elmes_Poland"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x00FFFFFF) | 0x02000000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Elmes_Poland"}; break; case SetTypeANMotorsAT4: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x000FFFFF) | 0x04700000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x21, - .keeloq.manuf = "AN-Motors"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x000FFFFF) | 0x04700000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x21, + .keeloq.manuf = "AN-Motors"}; break; case SetTypeAprimatic: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x000FFFFF) | 0x00600000, - .keeloq.btn = 0x08, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Aprimatic"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x000FFFFF) | 0x00600000, + .keeloq.btn = 0x08, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Aprimatic"}; break; case SetTypeGibidi433: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Gibidi"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Gibidi"}; break; case SetTypeGSN: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x0FFFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "GSN"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x0FFFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "GSN"}; break; case SetTypeIronLogic: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFF0, - .keeloq.btn = 0x04, - .keeloq.cnt = 0x05, - .keeloq.manuf = "IronLogic"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFF0, + .keeloq.btn = 0x04, + .keeloq.cnt = 0x05, + .keeloq.manuf = "IronLogic"}; break; case SetTypeStilmatic: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x0FFFFFFF, - .keeloq.btn = 0x01, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Stilmatic"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x0FFFFFFF, + .keeloq.btn = 0x01, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Stilmatic"}; break; case SetTypeSommer_FM_434: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "FM476", - .freq = 434420000, - .keeloq.serial = (key & 0x0000FFFF) | 0x01700000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Sommer(fsk476)"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "FM476", + .freq = 434420000, + .keeloq.serial = (key & 0x0000FFFF) | 0x01700000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Sommer(fsk476)"}; break; case SetTypeSommer_FM_868: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "FM476", - .freq = 868800000, - .keeloq.serial = (key & 0x0000FFFF) | 0x01700000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Sommer(fsk476)"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "FM476", + .freq = 868800000, + .keeloq.serial = (key & 0x0000FFFF) | 0x01700000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Sommer(fsk476)"}; break; case SetTypeSommer_FM238_434: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "FM238", - .freq = 434420000, - .keeloq.serial = key & 0x0000FFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Sommer(fsk476)"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "FM238", + .freq = 434420000, + .keeloq.serial = key & 0x0000FFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Sommer(fsk476)"}; break; case SetTypeSommer_FM238_868: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "FM238", - .freq = 868800000, - .keeloq.serial = key & 0x0000FFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Sommer(fsk476)"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "FM238", + .freq = 868800000, + .keeloq.serial = key & 0x0000FFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Sommer(fsk476)"}; break; case SetTypeDTMNeo433: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x000FFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x05, - .keeloq.manuf = "DTM_Neo"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x000FFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x05, + .keeloq.manuf = "DTM_Neo"}; break; case SetTypeCAMESpace: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x04, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Came_Space"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x04, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Came_Space"}; break; case SetTypeCameAtomo433: - gen_info = (GenInfo){.type = GenCameAtomo, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x0FFFFFFF) | 0x10000000, - .keeloq.cnt = 0x03}; + gen_info = (GenInfo){ + .type = GenCameAtomo, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x0FFFFFFF) | 0x10000000, + .keeloq.cnt = 0x03}; break; case SetTypeCameAtomo868: - gen_info = (GenInfo){.type = GenCameAtomo, - .mod = "AM650", - .freq = 868350000, - .keeloq.serial = (key & 0x0FFFFFFF) | 0x10000000, - .keeloq.cnt = 0x03}; + gen_info = (GenInfo){ + .type = GenCameAtomo, + .mod = "AM650", + .freq = 868350000, + .keeloq.serial = (key & 0x0FFFFFFF) | 0x10000000, + .keeloq.cnt = 0x03}; break; case SetTypeBFTMitto: - gen_info = (GenInfo){.type = GenKeeloqBFT, - .mod = "AM650", - .freq = 433920000, - .keeloq_bft.serial = key & 0x000FFFFF, - .keeloq_bft.btn = 0x02, - .keeloq_bft.cnt = 0x02, - .keeloq_bft.seed = key & 0x000FFFFF, - .keeloq_bft.manuf = "BFT"}; + gen_info = (GenInfo){ + .type = GenKeeloqBFT, + .mod = "AM650", + .freq = 433920000, + .keeloq_bft.serial = key & 0x000FFFFF, + .keeloq_bft.btn = 0x02, + .keeloq_bft.cnt = 0x02, + .keeloq_bft.seed = key & 0x000FFFFF, + .keeloq_bft.manuf = "BFT"}; break; case SetTypeAlutechAT4N: - gen_info = (GenInfo){.type = GenAlutechAt4n, - .mod = "AM650", - .freq = 433920000, - .alutech_at_4n.serial = (key & 0x000FFFFF) | 0x00100000, - .alutech_at_4n.btn = 0x44, - .alutech_at_4n.cnt = 0x03}; + gen_info = (GenInfo){ + .type = GenAlutechAt4n, + .mod = "AM650", + .freq = 433920000, + .alutech_at_4n.serial = (key & 0x000FFFFF) | 0x00100000, + .alutech_at_4n.btn = 0x44, + .alutech_at_4n.cnt = 0x03}; break; case SetTypeSomfyTelis: - gen_info = (GenInfo){.type = GenSomfyTelis, - .mod = "AM650", - .freq = 433420000, - .somfy_telis.serial = key & 0x00FFFFFF, - .somfy_telis.btn = 0x02, - .somfy_telis.cnt = 0x03}; + gen_info = (GenInfo){ + .type = GenSomfyTelis, + .mod = "AM650", + .freq = 433420000, + .somfy_telis.serial = key & 0x00FFFFFF, + .somfy_telis.btn = 0x02, + .somfy_telis.cnt = 0x03}; break; case SetTypeDoorHan_433_92: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x0FFFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "DoorHan"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x0FFFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "DoorHan"}; break; case SetTypeDoorHan_315_00: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 315000000, - .keeloq.serial = key & 0x0FFFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "DoorHan"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 315000000, + .keeloq.serial = key & 0x0FFFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "DoorHan"}; break; case SetTypeNiceFlorS_433_92: - gen_info = (GenInfo){.type = GenNiceFlorS, - .mod = "AM650", - .freq = 433920000, - .nice_flor_s.serial = key & 0x0FFFFFFF, - .nice_flor_s.btn = 0x01, - .nice_flor_s.cnt = 0x03, - .nice_flor_s.nice_one = false}; + gen_info = (GenInfo){ + .type = GenNiceFlorS, + .mod = "AM650", + .freq = 433920000, + .nice_flor_s.serial = key & 0x0FFFFFFF, + .nice_flor_s.btn = 0x01, + .nice_flor_s.cnt = 0x03, + .nice_flor_s.nice_one = false}; break; case SetTypeNiceOne_433_92: - gen_info = (GenInfo){.type = GenNiceFlorS, - .mod = "AM650", - .freq = 433920000, - .nice_flor_s.serial = key & 0x0FFFFFFF, - .nice_flor_s.btn = 0x01, - .nice_flor_s.cnt = 0x03, - .nice_flor_s.nice_one = true}; + gen_info = (GenInfo){ + .type = GenNiceFlorS, + .mod = "AM650", + .freq = 433920000, + .nice_flor_s.serial = key & 0x0FFFFFFF, + .nice_flor_s.btn = 0x01, + .nice_flor_s.cnt = 0x03, + .nice_flor_s.nice_one = true}; break; case SetTypeNiceSmilo_433_92: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "NICE_Smilo"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "NICE_Smilo"}; break; case SetTypeNiceMHouse_433_92: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x09, - .keeloq.cnt = 0x03, - .keeloq.manuf = "NICE_MHOUSE"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x09, + .keeloq.cnt = 0x03, + .keeloq.manuf = "NICE_MHOUSE"}; break; case SetTypeDeaMio433: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x0FFFF000) | 0x00000869, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Dea_Mio"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x0FFFF000) | 0x00000869, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Dea_Mio"}; break; case SetTypeGeniusBravo433: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x06, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Genius_Bravo"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x06, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Genius_Bravo"}; break; case SetTypeJCM_433_92: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "JCM_Tech"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "JCM_Tech"}; break; case SetTypeNovoferm_433_92: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x0000FFFF) | 0x018F0000, - .keeloq.btn = 0x01, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Novoferm"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x0000FFFF) | 0x018F0000, + .keeloq.btn = 0x01, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Novoferm"}; break; case SetTypeHormannEcoStar_433_92: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x000FFFFF) | 0x02200000, - .keeloq.btn = 0x04, - .keeloq.cnt = 0x03, - .keeloq.manuf = "EcoStar"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x000FFFFF) | 0x02200000, + .keeloq.btn = 0x04, + .keeloq.cnt = 0x03, + .keeloq.manuf = "EcoStar"}; break; case SetTypeFAACRCXT_433_92: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x0000FFFF) | 0x00100000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "FAAC_RC,XT"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x0000FFFF) | 0x00100000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "FAAC_RC,XT"}; break; case SetTypeFAACRCXT_868: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 868350000, - .keeloq.serial = (key & 0x0000FFFF) | 0x00100000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "FAAC_RC,XT"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 868350000, + .keeloq.serial = (key & 0x0000FFFF) | 0x00100000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "FAAC_RC,XT"}; break; case SetTypeNormstahl_433_92: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x0000FFFF, - .keeloq.btn = 0x04, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Normstahl"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x0000FFFF, + .keeloq.btn = 0x04, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Normstahl"}; break; case SetTypeHCS101_433_92: - gen_info = (GenInfo){.type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x000FFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "HCS101"}; + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x000FFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "HCS101"}; break; case SetTypeSecPlus_v1_315_00: gen_info = (GenInfo){.type = GenSecPlus1, .mod = "AM650", .freq = 315000000}; @@ -733,36 +785,40 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { gen_info = (GenInfo){.type = GenSecPlus1, .mod = "AM650", .freq = 433920000}; break; case SetTypeSecPlus_v2_310_00: - gen_info = (GenInfo){.type = GenSecPlus2, - .mod = "AM650", - .freq = 310000000, - .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing - .sec_plus_2.btn = 0x68, - .sec_plus_2.cnt = 0xE500000}; + gen_info = (GenInfo){ + .type = GenSecPlus2, + .mod = "AM650", + .freq = 310000000, + .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing + .sec_plus_2.btn = 0x68, + .sec_plus_2.cnt = 0xE500000}; break; case SetTypeSecPlus_v2_315_00: - gen_info = (GenInfo){.type = GenSecPlus2, - .mod = "AM650", - .freq = 315000000, - .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing - .sec_plus_2.btn = 0x68, - .sec_plus_2.cnt = 0xE500000}; + gen_info = (GenInfo){ + .type = GenSecPlus2, + .mod = "AM650", + .freq = 315000000, + .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing + .sec_plus_2.btn = 0x68, + .sec_plus_2.cnt = 0xE500000}; break; case SetTypeSecPlus_v2_390_00: - gen_info = (GenInfo){.type = GenSecPlus2, - .mod = "AM650", - .freq = 390000000, - .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing - .sec_plus_2.btn = 0x68, - .sec_plus_2.cnt = 0xE500000}; + gen_info = (GenInfo){ + .type = GenSecPlus2, + .mod = "AM650", + .freq = 390000000, + .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing + .sec_plus_2.btn = 0x68, + .sec_plus_2.cnt = 0xE500000}; break; case SetTypeSecPlus_v2_433_00: - gen_info = (GenInfo){.type = GenSecPlus2, - .mod = "AM650", - .freq = 433920000, - .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing - .sec_plus_2.btn = 0x68, - .sec_plus_2.cnt = 0xE500000}; + gen_info = (GenInfo){ + .type = GenSecPlus2, + .mod = "AM650", + .freq = 433920000, + .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing + .sec_plus_2.btn = 0x68, + .sec_plus_2.cnt = 0xE500000}; break; default: furi_crash("Not implemented"); diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 07c7b6041..ebd69059f 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -79,7 +79,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { subghz_txrx_stop(subghz->txrx); if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) { subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); - int8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); + int32_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); furi_hal_subghz_set_rolling_counter_mult(0); // Calling restore! subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 71e1aca32..873f61ba9 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -279,7 +279,7 @@ static bool subghz_protocol_alutech_at_4n_gen_data( } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } - } else if(instance->generic.cnt >= 0xFFFF) { + } else if((instance->generic.cnt >= 0xFFFF) && (furi_hal_subghz_get_rolling_counter_mult() != 0)) { instance->generic.cnt = 0; } crc = subghz_protocol_alutech_at_4n_decrypt_data_crc((uint8_t)(instance->generic.cnt & 0xFF)); diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index a89a05d8d..5b9e6defd 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -191,7 +191,7 @@ static void subghz_protocol_encoder_came_atomo_get_upload( } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } - } else if(instance->generic.cnt >= 0xFFFF) { + } else if((instance->generic.cnt >= 0xFFFF) && (furi_hal_subghz_get_rolling_counter_mult() != 0)) { instance->generic.cnt = 0; } diff --git a/lib/subghz/protocols/faac_slh.c b/lib/subghz/protocols/faac_slh.c index b095977e1..489fbdbc2 100644 --- a/lib/subghz/protocols/faac_slh.c +++ b/lib/subghz/protocols/faac_slh.c @@ -140,9 +140,40 @@ static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* inst data_prg[0] = 0x00; if(allow_zero_seed || (instance->generic.seed != 0x0)) { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + if(!(furi_hal_subghz_get_rolling_counter_mult() >= 0xFFFF)) { + if(instance->generic.cnt < 0xFFFFF) { + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > + 0xFFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } + } else if( + (instance->generic.cnt >= 0xFFFFF) && + (furi_hal_subghz_get_rolling_counter_mult() != 0)) { + instance->generic.cnt = 0; + } + } else { + instance->generic.cnt += 1; + } + if(temp_counter_backup != 0x0) { - temp_counter_backup += furi_hal_subghz_get_rolling_counter_mult(); + if(!(furi_hal_subghz_get_rolling_counter_mult() >= 0xFFFF)) { + if(temp_counter_backup < 0xFFFFF) { + if((temp_counter_backup + furi_hal_subghz_get_rolling_counter_mult()) > + 0xFFFFF) { + temp_counter_backup = 0; + } else { + temp_counter_backup += furi_hal_subghz_get_rolling_counter_mult(); + } + } else if( + (temp_counter_backup >= 0xFFFFF) && + (furi_hal_subghz_get_rolling_counter_mult() != 0)) { + temp_counter_backup = 0; + } + } else { + temp_counter_backup += 1; + } } } @@ -193,7 +224,9 @@ static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* inst (temp_fix_backup != 0x0) && !faac_prog_mode) { instance->generic.serial = temp_fix_backup >> 4; instance->generic.btn = temp_fix_backup & 0xF; - instance->generic.cnt = temp_counter_backup; + if(temp_counter_backup != 0x0) { + instance->generic.cnt = temp_counter_backup; + } } uint32_t fix = instance->generic.serial << 4 | instance->generic.btn; uint32_t hop = 0; @@ -207,7 +240,32 @@ static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* inst } if(allow_zero_seed || (instance->generic.seed != 0x0)) { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + if(!(furi_hal_subghz_get_rolling_counter_mult() >= 0xFFFF)) { + if(instance->generic.cnt < 0xFFFFF) { + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > + 0xFFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } + } else if( + (instance->generic.cnt >= 0xFFFFF) && + (furi_hal_subghz_get_rolling_counter_mult() != 0)) { + instance->generic.cnt = 0; + } + } else { + if(instance->generic.cnt < 0xFFFFF) { + if((instance->generic.cnt + 0xFFFFF) > 0xFFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += 0xFFFFF; + } + } else if( + (instance->generic.cnt >= 0xFFFFF) && + (furi_hal_subghz_get_rolling_counter_mult() != 0)) { + instance->generic.cnt = 0; + } + } } if((instance->generic.cnt % 2) == 0) { @@ -248,7 +306,7 @@ bool subghz_protocol_faac_slh_create_data( const char* manufacture_name, SubGhzRadioPreset* preset) { furi_assert(context); - // roguemaster don't steal!!! + // OwO SubGhzProtocolEncoderFaacSLH* instance = context; instance->generic.serial = serial; instance->generic.btn = btn; diff --git a/lib/subghz/protocols/hay21.c b/lib/subghz/protocols/hay21.c index 21d186df8..1e3576459 100644 --- a/lib/subghz/protocols/hay21.c +++ b/lib/subghz/protocols/hay21.c @@ -151,6 +151,9 @@ static void subghz_protocol_encoder_hay21_get_upload(SubGhzProtocolEncoderHay21* } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } + if(furi_hal_subghz_get_rolling_counter_mult() >= 0xF) { + instance->generic.cnt = 0xF; + } } else if(instance->generic.cnt >= 0xF) { instance->generic.cnt = 0; } diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 12d739dec..a774e5825 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -190,7 +190,9 @@ static bool subghz_protocol_keeloq_gen_data( } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } - } else if(instance->generic.cnt >= 0xFFFF) { + } else if( + (instance->generic.cnt >= 0xFFFF) && + (furi_hal_subghz_get_rolling_counter_mult() != 0)) { instance->generic.cnt = 0; } } diff --git a/lib/subghz/protocols/kinggates_stylo_4k.c b/lib/subghz/protocols/kinggates_stylo_4k.c index 56795d2dd..119a198bc 100644 --- a/lib/subghz/protocols/kinggates_stylo_4k.c +++ b/lib/subghz/protocols/kinggates_stylo_4k.c @@ -161,7 +161,7 @@ static bool subghz_protocol_kinggates_stylo_4k_gen_data( } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } - } else if(instance->generic.cnt >= 0xFFFF) { + } else if((instance->generic.cnt >= 0xFFFF) && (furi_hal_subghz_get_rolling_counter_mult() != 0)) { instance->generic.cnt = 0; } diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index 8e007582b..50adb43dc 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -157,7 +157,7 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload( } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } - } else if(instance->generic.cnt >= 0xFFFF) { + } else if((instance->generic.cnt >= 0xFFFF) && (furi_hal_subghz_get_rolling_counter_mult() != 0)) { instance->generic.cnt = 0; } uint64_t decrypt = ((uint64_t)instance->generic.serial << 16) | instance->generic.cnt; diff --git a/lib/subghz/protocols/somfy_keytis.c b/lib/subghz/protocols/somfy_keytis.c index 22d2b5e9f..0606b9bf5 100644 --- a/lib/subghz/protocols/somfy_keytis.c +++ b/lib/subghz/protocols/somfy_keytis.c @@ -136,7 +136,7 @@ static bool } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } - } else if(instance->generic.cnt >= 0xFFFF) { + } else if((instance->generic.cnt >= 0xFFFF) && (furi_hal_subghz_get_rolling_counter_mult() != 0)) { instance->generic.cnt = 0; } diff --git a/lib/subghz/protocols/somfy_telis.c b/lib/subghz/protocols/somfy_telis.c index a1308dd6d..fd41180d5 100644 --- a/lib/subghz/protocols/somfy_telis.c +++ b/lib/subghz/protocols/somfy_telis.c @@ -130,7 +130,7 @@ static bool subghz_protocol_somfy_telis_gen_data( } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } - } else if(instance->generic.cnt >= 0xFFFF) { + } else if((instance->generic.cnt >= 0xFFFF) && (furi_hal_subghz_get_rolling_counter_mult() != 0)) { instance->generic.cnt = 0; } diff --git a/lib/subghz/protocols/star_line.c b/lib/subghz/protocols/star_line.c index 75a7fd471..0005ad5fc 100644 --- a/lib/subghz/protocols/star_line.c +++ b/lib/subghz/protocols/star_line.c @@ -135,7 +135,7 @@ static bool } else { instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); } - } else if(instance->generic.cnt >= 0xFFFF) { + } else if((instance->generic.cnt >= 0xFFFF) && (furi_hal_subghz_get_rolling_counter_mult() != 0)) { instance->generic.cnt = 0; } uint32_t fix = btn << 24 | instance->generic.serial; diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 7ad21efb5..45f912861 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1716,7 +1716,7 @@ Function,+,furi_hal_subghz_flush_tx,void, Function,+,furi_hal_subghz_get_data_gpio,const GpioPin*, Function,+,furi_hal_subghz_get_ext_leds_and_amp,_Bool, Function,+,furi_hal_subghz_get_lqi,uint8_t, -Function,+,furi_hal_subghz_get_rolling_counter_mult,int8_t, +Function,+,furi_hal_subghz_get_rolling_counter_mult,int32_t, Function,+,furi_hal_subghz_get_rssi,float, Function,+,furi_hal_subghz_idle,void, Function,-,furi_hal_subghz_init,void, @@ -1736,7 +1736,7 @@ Function,+,furi_hal_subghz_set_ext_leds_and_amp,void,_Bool Function,+,furi_hal_subghz_set_frequency,uint32_t,uint32_t Function,+,furi_hal_subghz_set_frequency_and_path,uint32_t,uint32_t Function,+,furi_hal_subghz_set_path,void,FuriHalSubGhzPath -Function,+,furi_hal_subghz_set_rolling_counter_mult,void,int8_t +Function,+,furi_hal_subghz_set_rolling_counter_mult,void,int32_t Function,+,furi_hal_subghz_shutdown,void, Function,+,furi_hal_subghz_sleep,void, Function,+,furi_hal_subghz_start_async_rx,void,"FuriHalSubGhzCaptureCallback, void*" diff --git a/targets/f7/furi_hal/furi_hal_subghz.c b/targets/f7/furi_hal/furi_hal_subghz.c index 19aa0f766..dc6add277 100644 --- a/targets/f7/furi_hal/furi_hal_subghz.c +++ b/targets/f7/furi_hal/furi_hal_subghz.c @@ -51,7 +51,7 @@ typedef struct { volatile SubGhzRegulation regulation; const GpioPin* async_mirror_pin; - int8_t rolling_counter_mult; + int32_t rolling_counter_mult; bool ext_leds_and_amp : 1; bool dangerous_frequency_i : 1; } FuriHalSubGhz; @@ -65,11 +65,11 @@ volatile FuriHalSubGhz furi_hal_subghz = { .dangerous_frequency_i = false, }; -int8_t furi_hal_subghz_get_rolling_counter_mult(void) { +int32_t furi_hal_subghz_get_rolling_counter_mult(void) { return furi_hal_subghz.rolling_counter_mult; } -void furi_hal_subghz_set_rolling_counter_mult(int8_t mult) { +void furi_hal_subghz_set_rolling_counter_mult(int32_t mult) { furi_hal_subghz.rolling_counter_mult = mult; } diff --git a/targets/f7/furi_hal/furi_hal_subghz.h b/targets/f7/furi_hal/furi_hal_subghz.h index 20843520a..b08d41ba4 100644 --- a/targets/f7/furi_hal/furi_hal_subghz.h +++ b/targets/f7/furi_hal/furi_hal_subghz.h @@ -174,14 +174,14 @@ uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value); bool furi_hal_subghz_is_tx_allowed(uint32_t value); /** Get the current rolling protocols counter ++/-- value - * @return int8_t current value + * @return int32_t current value */ -int8_t furi_hal_subghz_get_rolling_counter_mult(void); +int32_t furi_hal_subghz_get_rolling_counter_mult(void); /** Set the current rolling protocols counter ++/-- value - * @param mult int8_t = -1, -10, -100, 0, 1, 10, 100 + * @param mult int32_t = -1, -10, -50, 0, 1, 10, 50 */ -void furi_hal_subghz_set_rolling_counter_mult(int8_t mult); +void furi_hal_subghz_set_rolling_counter_mult(int32_t mult); /** Set frequency * From 9da510389a7ec95afa8379e7ad96cb5687145192 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 15 Mar 2025 07:58:51 +0300 Subject: [PATCH 020/125] small fixes --- .../services/notification/notification_app.c | 128 +----------------- .../services/notification/notification_app.h | 15 -- .../notification_settings_app.c | 2 +- 3 files changed, 3 insertions(+), 142 deletions(-) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 4bd93cfbc..cf03d4389 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -189,111 +189,6 @@ static void notification_display_timer(void* ctx) { notification_message(app, &sequence_display_backlight_off); } -// // --- RGB MOD RAINBOW SECTION --- - -// //start furi timer for rgb_mod_rainbow -// static void rgb_mod_rainbow_timer_start(NotificationApp* app) { -// furi_timer_start( -// app->rgb_mod_rainbow_timer, furi_ms_to_ticks(app->settings.rgb_mod_rainbow_speed_ms)); -// } - -// //stop furi timer for rgb_mod_rainbow -// static void rgb_mod_rainbow_timer_stop(NotificationApp* app) { -// furi_timer_stop(app->rgb_mod_rainbow_timer); -// } - -// // start/restart/stop rgb_mod_rainbow_timer only if rgb_mod_installed and apply rainbow colors to backlight -// static void rgb_mod_rainbow_timer_starter(NotificationApp* app) { -// if(app->settings.rgb_mod_installed) { -// if(app->settings.rgb_mod_rainbow_mode > 0) { -// rgb_mod_rainbow_update( -// app->rgb_mod_rainbow_red, -// app->rgb_mod_rainbow_green, -// app->rgb_mod_rainbow_blue, -// app->settings.display_brightness); -// rgb_mod_rainbow_timer_start(app); -// } else { -// if(furi_timer_is_running(app->rgb_mod_rainbow_timer)) { -// rgb_mod_rainbow_timer_stop(app); -// } -// } -// } -// } - -// // callback for rgb_mod_rainbow_timer (what we do when timer end) -// static void rgb_mod_rainbow_timer_callback(void* context) { -// furi_assert(context); -// NotificationApp* app = context; - -// // if rgb_mode_rainbow_mode is rainbow do rainbow effect -// if(app->settings.rgb_mod_rainbow_mode == 1) { -// switch(app->rgb_mod_rainbow_stage) { -// // from red to yellow -// case 1: -// app->rgb_mod_rainbow_green += app->settings.rgb_mod_rainbow_step; -// if(app->rgb_mod_rainbow_green >= 255) { -// app->rgb_mod_rainbow_green = 255; -// app->rgb_mod_rainbow_stage++; -// } -// break; -// // yellow red to green -// case 2: -// app->rgb_mod_rainbow_red -= app->settings.rgb_mod_rainbow_step; -// if(app->rgb_mod_rainbow_red <= 0) { -// app->rgb_mod_rainbow_red = 0; -// app->rgb_mod_rainbow_stage++; -// } -// break; -// // from green to light blue -// case 3: -// app->rgb_mod_rainbow_blue += app->settings.rgb_mod_rainbow_step; -// if(app->rgb_mod_rainbow_blue >= 255) { -// app->rgb_mod_rainbow_blue = 255; -// app->rgb_mod_rainbow_stage++; -// } -// break; -// //from light blue to blue -// case 4: -// app->rgb_mod_rainbow_green -= app->settings.rgb_mod_rainbow_step; -// if(app->rgb_mod_rainbow_green <= 0) { -// app->rgb_mod_rainbow_green = 0; -// app->rgb_mod_rainbow_stage++; -// } -// break; -// //from blue to violet -// case 5: -// app->rgb_mod_rainbow_red += app->settings.rgb_mod_rainbow_step; -// if(app->rgb_mod_rainbow_red >= 255) { -// app->rgb_mod_rainbow_red = 255; -// app->rgb_mod_rainbow_stage++; -// } -// break; -// //from violet to red -// case 6: -// app->rgb_mod_rainbow_blue -= app->settings.rgb_mod_rainbow_step; -// if(app->rgb_mod_rainbow_blue <= 0) { -// app->rgb_mod_rainbow_blue = 0; -// app->rgb_mod_rainbow_stage = 1; -// } -// break; -// default: -// break; -// } - -// rgb_mod_rainbow_update( -// app->rgb_mod_rainbow_red, -// app->rgb_mod_rainbow_green, -// app->rgb_mod_rainbow_blue, -// app->settings.display_brightness); -// } - -// // if rgb_mode_rainbow_mode is ..... do another effect -// // if(app->settings.rgb_mod_rainbow_mode == 2) { -// // } -// } - -// // --- END OF RGB MOD RAINBOW SECTION --- - // message processing static void notification_process_notification_message( NotificationApp* app, @@ -629,7 +524,7 @@ static void input_event_callback(const void* value, void* context) { static NotificationApp* notification_app_alloc(void) { NotificationApp* app = malloc(sizeof(NotificationApp)); app->queue = furi_message_queue_alloc(8, sizeof(NotificationAppMessage)); - app->display_timer = furi_timer_alloc(notification_display_timer, FuriTimerTypePeriodic, app); + app->display_timer = furi_timer_alloc(notification_display_timer, FuriTimerTypeOnce, app); app->settings.speaker_volume = 1.0f; app->settings.display_brightness = 1.0f; @@ -664,26 +559,9 @@ static NotificationApp* notification_app_alloc(void) { furi_pubsub_subscribe(app->event_record, input_event_callback, app); notification_message(app, &sequence_display_backlight_on); - // // --- RGB MOD INIT SETTINGS SECTION --- - - // app->settings.rgb_mod_installed = false; - // app->settings.rgb_mod_rainbow_mode = 0; - // app->settings.rgb_mod_rainbow_speed_ms = 100; - // app->settings.rgb_mod_rainbow_step = 5; - // app->rgb_mod_rainbow_red = 255; - // app->rgb_mod_rainbow_green = 0; - // app->rgb_mod_rainbow_blue = 0; - // app->rgb_mod_rainbow_stage = 1; - - // //define rgb_mod_rainbow_timer and they callback - // app->rgb_mod_rainbow_timer = - // furi_timer_alloc(rgb_mod_rainbow_timer_callback, FuriTimerTypePeriodic, app); - // // --- END OF RGB MOD INIT SETTINGS SECTION --- - return app; } - static void notification_storage_callback(const void* message, void* context) { furi_assert(context); NotificationApp* app = context; @@ -704,8 +582,6 @@ static void notification_apply_settings(NotificationApp* app) { } notification_apply_lcd_contrast(app); - // //start rgb_mod_rainbow_timer on system init if they ON in config - // rgb_mod_rainbow_timer_starter(app); } static void notification_init_settings(NotificationApp* app) { @@ -724,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); + 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 4383ca6bc..0209ffa0b 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -45,13 +45,6 @@ typedef struct { uint32_t display_off_delay_ms; int8_t contrast; bool vibro_on; - /// --- RGB MOD SETTINGS SECTION --- - // bool rgb_mod_installed; - // uint32_t rgb_mod_rainbow_mode; - // uint32_t rgb_mod_rainbow_speed_ms; - // uint16_t rgb_mod_rainbow_step; - /// --- END OF RGB MOD SETTINGS SECTION --- - } NotificationSettings; struct NotificationApp { @@ -63,14 +56,6 @@ struct NotificationApp { NotificationLedLayer led[NOTIFICATION_LED_COUNT]; uint8_t display_led_lock; - // --- RGB RAINBOW MODE VARIABLES SECTION --- - // FuriTimer* rgb_mod_rainbow_timer; - // int16_t rgb_mod_rainbow_red; - // int16_t rgb_mod_rainbow_green; - // int16_t rgb_mod_rainbow_blue; - // uint8_t rgb_mod_rainbow_stage; - // --- ENd OF RGB RAINBOW MODE VARIABLES SECTION --- - NotificationSettings settings; RGBBacklightApp* rgb_srv; }; diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 82e4526ae..ff90e96e7 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -435,7 +435,7 @@ static NotificationAppSettings* alloc_settings(void) { variable_item_set_current_value_text(item, contrast_text[value_index]); item = variable_item_list_add( - app->variable_item_list, "LCD Brightness", BACKLIGHT_COUNT, backlight_changed, app); + app->variable_item_list, "LCD Backlight", BACKLIGHT_COUNT, backlight_changed, app); value_index = value_index_float( app->notification->settings.display_brightness, backlight_value, BACKLIGHT_COUNT); variable_item_set_current_value_index(item, value_index); From 7f1c8684c666f780562748070e31c484e7c117bf Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 15 Mar 2025 08:10:25 +0300 Subject: [PATCH 021/125] remove build [ci skip] --- .ci_files/devbuild_msg_discord.txt | 5 +- .ci_files/devbuild_msg_telegram.txt | 4 +- .ci_files/release_msg_discord.txt | 5 +- .ci_files/release_msg_telegram.txt | 4 +- .ci_files/rgb.patch | 677 ---------------------------- .drone.yml | 76 ---- ReadMe.md | 2 +- documentation/FAQ.md | 9 +- 8 files changed, 14 insertions(+), 768 deletions(-) delete mode 100644 .ci_files/rgb.patch diff --git a/.ci_files/devbuild_msg_discord.txt b/.ci_files/devbuild_msg_discord.txt index 1b7b7bd7f..0bc802364 100644 --- a/.ci_files/devbuild_msg_discord.txt +++ b/.ci_files/devbuild_msg_discord.txt @@ -9,8 +9,7 @@ How to [install firmware](https://github.com/DarkFlippers/unleashed-firmware/blo [Default](https://lab.flipper.net/?url=https://unleashedflip.com/fw/dev/flipper-z-f7-update-(buildnum).tgz&channel=dev-cfw&version=(buildnum)) > ` ` [Extra apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)e.tgz&channel=dev-cfw&version=(buildnum)e) > `e` [No apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)c.tgz&channel=dev-cfw&version=(buildnum)c) > `c` -[RGB patch - only for hardware mod!](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)r.tgz&channel=dev-cfw&version=(buildnum)r) > `r` -What ` `, `e`, `c`, `r` means? -> [versions info](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#what-n-r-e---c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater) +What ` `, `e`, `c` means? -> [versions info](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#what-n-r-e---c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater) ### Direct tgz download links: -[Default](https://unleashedflip.com/fw/dev/flipper-z-f7-update-(buildnum).tgz) > ` ` - [Extra apps](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)e.tgz) > `e` - [No apps](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)c.tgz) > `c` - [RGB patch - only for hardware mod!](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)r.tgz) > `r` +[Default](https://unleashedflip.com/fw/dev/flipper-z-f7-update-(buildnum).tgz) > ` ` - [Extra apps](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)e.tgz) > `e` - [No apps](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)c.tgz) > `c` diff --git a/.ci_files/devbuild_msg_telegram.txt b/.ci_files/devbuild_msg_telegram.txt index e03d19c6c..5a3051471 100644 --- a/.ci_files/devbuild_msg_telegram.txt +++ b/.ci_files/devbuild_msg_telegram.txt @@ -10,13 +10,11 @@ How to [install firmware](https://github.com/DarkFlippers/unleashed-firmware/blo [Default](https://lab.flipper.net/?url=https://unleashedflip.com/fw/dev/flipper-z-f7-update-(buildnum).tgz&channel=dev-cfw&version=(buildnum)) > ` ` [Extra apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)e.tgz&channel=dev-cfw&version=(buildnum)e) > `e` [No apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)c.tgz&channel=dev-cfw&version=(buildnum)c) > `c` -[RGB patch - only for hardware mod!](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)r.tgz&channel=dev-cfw&version=(buildnum)r) > `r` -What ` `, `e`, `c`, `r` means? -> [versions info](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#what-n-r-e---c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater) +What ` `, `e`, `c` means? -> [versions info](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#what-n-r-e---c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater) **Direct tgz download links:** [Default](https://unleashedflip.com/fw/dev/flipper-z-f7-update-(buildnum).tgz) > ` ` [Extra apps](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)e.tgz) > `e` [No apps](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)c.tgz) > `c` -[RGB patch - only for hardware mod!](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)r.tgz) > `r` diff --git a/.ci_files/release_msg_discord.txt b/.ci_files/release_msg_discord.txt index 079135f40..e25e0d95b 100644 --- a/.ci_files/release_msg_discord.txt +++ b/.ci_files/release_msg_discord.txt @@ -9,8 +9,7 @@ How to [install firmware](https://github.com/DarkFlippers/unleashed-firmware/blo [Default](https://lab.flipper.net/?url=https://unleashedflip.com/fw/(releasever)/flipper-z-f7-update-(releasever).tgz&channel=release-cfw&version=(releasever)) > ` ` [Extra apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)e.tgz&channel=release-cfw&version=(releasever)e) > `e` [No apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)c.tgz&channel=release-cfw&version=(releasever)c) > `c` -[RGB patch - only for hardware mod!](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)r.tgz&channel=release-cfw&version=(releasever)r) > `r` -What ` `, `e`, `c`, `r` means? -> [versions info](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#what-n-r-e---c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater) +What ` `, `e`, `c` means? -> [versions info](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#what-n-r-e---c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater) ### Direct tgz download links: -[Default](https://unleashedflip.com/fw/(releasever)/flipper-z-f7-update-(releasever).tgz) > ` ` - [Extra apps](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)e.tgz) > `e` - [No apps](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)c.tgz) > `c` - [RGB patch - only for hardware mod!](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)r.tgz) > `r` +[Default](https://unleashedflip.com/fw/(releasever)/flipper-z-f7-update-(releasever).tgz) > ` ` - [Extra apps](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)e.tgz) > `e` - [No apps](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)c.tgz) > `c` diff --git a/.ci_files/release_msg_telegram.txt b/.ci_files/release_msg_telegram.txt index f561fee21..fd8c13bcf 100644 --- a/.ci_files/release_msg_telegram.txt +++ b/.ci_files/release_msg_telegram.txt @@ -10,13 +10,11 @@ How to [install firmware](https://github.com/DarkFlippers/unleashed-firmware/blo [Default](https://lab.flipper.net/?url=https://unleashedflip.com/fw/(releasever)/flipper-z-f7-update-(releasever).tgz&channel=release-cfw&version=(releasever)) > ` ` [Extra apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)e.tgz&channel=release-cfw&version=(releasever)e) > `e` [No apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)c.tgz&channel=release-cfw&version=(releasever)c) > `c` -[RGB patch - only for hardware mod!](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)r.tgz&channel=release-cfw&version=(releasever)r) > `r` -What ` `, `e`, `c`, `r` means? -> [versions info](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#what-n-r-e---c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater) +What ` `, `e`, `c` means? -> [versions info](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#what-n-r-e---c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater) **Direct tgz download links:** [Default](https://unleashedflip.com/fw/(releasever)/flipper-z-f7-update-(releasever).tgz) > ` ` [Extra apps](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)e.tgz) > `e` [No apps](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)c.tgz) > `c` -[RGB patch - only for hardware mod!](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)r.tgz) > `r` diff --git a/.ci_files/rgb.patch b/.ci_files/rgb.patch deleted file mode 100644 index 81783325f..000000000 --- a/.ci_files/rgb.patch +++ /dev/null @@ -1,677 +0,0 @@ -diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c -index 35d2fe6..1af97e2 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/settings/notification_settings/rgb_backlight.h" - - #define TAG "NotificationSrv" - -@@ -616,6 +617,7 @@ int32_t notification_srv(void* p) { - break; - case SaveSettingsMessage: - notification_save_settings(app); -+ rgb_backlight_save_settings(); - break; - case LoadSettingsMessage: - notification_load_settings(app); -diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c -index 2462b32..8e045ce 100644 ---- a/applications/settings/notification_settings/notification_settings_app.c -+++ b/applications/settings/notification_settings/notification_settings_app.c -@@ -3,6 +3,7 @@ - #include - #include - #include -+#include - - #define MAX_NOTIFICATION_SETTINGS 4 - -@@ -13,6 +14,8 @@ typedef struct { - VariableItemList* variable_item_list; - } NotificationAppSettings; - -+static VariableItem* temp_item; -+ - static const NotificationSequence sequence_note_c = { - &message_note_c5, - &message_delay_100, -@@ -168,6 +171,59 @@ static void vibro_changed(VariableItem* item) { - notification_message(app->notification, &sequence_single_vibro); - } - -+// Set RGB backlight color -+static void color_changed(VariableItem* item) { -+ NotificationAppSettings* app = variable_item_get_context(item); -+ uint8_t index = variable_item_get_current_value_index(item); -+ rgb_backlight_set_color(index); -+ variable_item_set_current_value_text(item, rgb_backlight_get_color_text(index)); -+ notification_message(app->notification, &sequence_display_backlight_on); -+} -+ -+// TODO: refactor and fix this -+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); -+ rgb_backlight_set_custom_color(index, 0); -+ char valtext[4] = {}; -+ snprintf(valtext, sizeof(valtext), "%d", index); -+ variable_item_set_current_value_text(item, valtext); -+ rgb_backlight_set_color(13); -+ rgb_backlight_update(app->notification->settings.display_brightness * 0xFF, true); -+ // 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)); -+ notification_message(app->notification, &sequence_display_backlight_on); -+} -+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); -+ rgb_backlight_set_custom_color(index, 1); -+ char valtext[4] = {}; -+ snprintf(valtext, sizeof(valtext), "%d", index); -+ variable_item_set_current_value_text(item, valtext); -+ rgb_backlight_set_color(13); -+ rgb_backlight_update(app->notification->settings.display_brightness * 0xFF, true); -+ // 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)); -+ notification_message(app->notification, &sequence_display_backlight_on); -+} -+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); -+ rgb_backlight_set_custom_color(index, 2); -+ char valtext[4] = {}; -+ snprintf(valtext, sizeof(valtext), "%d", index); -+ variable_item_set_current_value_text(item, valtext); -+ rgb_backlight_set_color(13); -+ rgb_backlight_update(app->notification->settings.display_brightness * 0xFF, true); -+ // 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)); -+ notification_message(app->notification, &sequence_display_backlight_on); -+} -+ - static uint32_t notification_app_settings_exit(void* context) { - UNUSED(context); - return VIEW_NONE; -@@ -192,8 +248,40 @@ static NotificationAppSettings* alloc_settings(void) { - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, contrast_text[value_index]); - -+ // RGB Colors -+ item = variable_item_list_add( -+ app->variable_item_list, "LCD Color", rgb_backlight_get_color_count(), color_changed, app); -+ value_index = rgb_backlight_get_settings()->display_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)); -+ temp_item = item; -+ -+ // Custom Color - REFACTOR THIS -+ item = variable_item_list_add( -+ app->variable_item_list, "Custom Red", 255, color_set_custom_red, app); -+ value_index = rgb_backlight_get_settings()->custom_r; -+ 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); -+ -+ item = variable_item_list_add( -+ app->variable_item_list, "Custom Green", 255, color_set_custom_green, app); -+ value_index = rgb_backlight_get_settings()->custom_g; -+ variable_item_set_current_value_index(item, value_index); -+ snprintf(valtext, sizeof(valtext), "%d", value_index); -+ variable_item_set_current_value_text(item, valtext); -+ -+ item = variable_item_list_add( -+ app->variable_item_list, "Custom Blue", 255, color_set_custom_blue, app); -+ value_index = rgb_backlight_get_settings()->custom_b; -+ variable_item_set_current_value_index(item, value_index); -+ snprintf(valtext, sizeof(valtext), "%d", value_index); -+ variable_item_set_current_value_text(item, valtext); -+ // End of RGB -+ - item = variable_item_list_add( -- app->variable_item_list, "LCD Backlight", BACKLIGHT_COUNT, backlight_changed, app); -+ app->variable_item_list, "LCD Brightness", BACKLIGHT_COUNT, backlight_changed, app); - value_index = value_index_float( - app->notification->settings.display_brightness, backlight_value, BACKLIGHT_COUNT); - variable_item_set_current_value_index(item, value_index); -diff --git a/applications/settings/notification_settings/rgb_backlight.c b/applications/settings/notification_settings/rgb_backlight.c -new file mode 100644 -index 0000000..4edd775 ---- /dev/null -+++ b/applications/settings/notification_settings/rgb_backlight.c -@@ -0,0 +1,217 @@ -+/* -+ 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 "rgb_backlight.h" -+#include -+#include -+ -+#define RGB_BACKLIGHT_SETTINGS_VERSION 6 -+#define RGB_BACKLIGHT_SETTINGS_FILE_NAME ".rgb_backlight.settings" -+#define RGB_BACKLIGHT_SETTINGS_PATH INT_PATH(RGB_BACKLIGHT_SETTINGS_FILE_NAME) -+ -+#define COLOR_COUNT (sizeof(colors) / sizeof(RGBBacklightColor)) -+ -+#define TAG "RGB Backlight" -+ -+static RGBBacklightSettings rgb_settings = { -+ .version = RGB_BACKLIGHT_SETTINGS_VERSION, -+ .display_color_index = 0, -+ .custom_r = 254, -+ .custom_g = 254, -+ .custom_b = 254, -+ .settings_is_loaded = false}; -+ -+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; -+} -+ -+void rgb_backlight_load_settings(void) { -+ // Do not load settings if we are in other boot modes than normal -+ if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { -+ rgb_settings.settings_is_loaded = true; -+ return; -+ } -+ -+ // Wait for all required services to start and create their records -+ uint8_t timeout = 0; -+ while(!furi_record_exists(RECORD_STORAGE)) { -+ timeout++; -+ if(timeout > 150) { -+ rgb_settings.settings_is_loaded = true; -+ return; -+ } -+ furi_delay_ms(5); -+ } -+ -+ RGBBacklightSettings settings; -+ File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); -+ const size_t settings_size = sizeof(RGBBacklightSettings); -+ -+ FURI_LOG_D(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_D(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; -+} -+ -+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); -+ -+ FURI_LOG_D(TAG, "saving settings to \"%s\"", RGB_BACKLIGHT_SETTINGS_PATH); -+ -+ memcpy(&settings, &rgb_settings, settings_size); -+ -+ bool fs_result = -+ storage_file_open(file, RGB_BACKLIGHT_SETTINGS_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS); -+ -+ if(fs_result) { -+ uint16_t bytes_count = storage_file_write(file, &settings, settings_size); -+ -+ if(bytes_count != settings_size) { -+ fs_result = false; -+ } -+ } -+ -+ if(fs_result) { -+ FURI_LOG_D(TAG, "save success"); -+ } else { -+ FURI_LOG_E(TAG, "save failed, %s", storage_file_get_error_desc(file)); -+ } -+ -+ 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_set_custom_color(uint8_t color, uint8_t index) { -+ if(index > 2) return; -+ if(index == 0) { -+ rgb_settings.custom_r = color; -+ } else if(index == 1) { -+ rgb_settings.custom_g = color; -+ } else if(index == 2) { -+ rgb_settings.custom_b = color; -+ } -+} -+ -+void rgb_backlight_update(uint8_t brightness, bool bypass) { -+ if(!rgb_settings.settings_is_loaded) { -+ rgb_backlight_load_settings(); -+ } -+ -+ if(!bypass) { -+ 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) { -+ return; -+ } -+ -+ last_brightness = brightness; -+ last_color_index = rgb_settings.display_color_index; -+ } -+ -+ for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { -+ if(rgb_settings.display_color_index == 13) { -+ uint8_t r = rgb_settings.custom_r * (brightness / 255.0f); -+ uint8_t g = rgb_settings.custom_g * (brightness / 255.0f); -+ uint8_t b = rgb_settings.custom_b * (brightness / 255.0f); -+ -+ SK6805_set_led_color(i, r, g, b); -+ } else { -+ if((colors[rgb_settings.display_color_index].red == 0) && -+ (colors[rgb_settings.display_color_index].green == 0) && -+ (colors[rgb_settings.display_color_index].blue == 0)) { -+ uint8_t r = colors[0].red * (brightness / 255.0f); -+ uint8_t g = colors[0].green * (brightness / 255.0f); -+ uint8_t b = colors[0].blue * (brightness / 255.0f); -+ -+ SK6805_set_led_color(i, r, g, b); -+ } else { -+ 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); -+ } -+ } -+ } -+ -+ SK6805_update(); -+} -diff --git a/applications/settings/notification_settings/rgb_backlight.h b/applications/settings/notification_settings/rgb_backlight.h -new file mode 100644 -index 0000000..f215ed3 ---- /dev/null -+++ b/applications/settings/notification_settings/rgb_backlight.h -@@ -0,0 +1,91 @@ -+/* -+ 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 "SK6805.h" -+ -+typedef struct { -+ char* name; -+ uint8_t red; -+ uint8_t green; -+ uint8_t blue; -+} RGBBacklightColor; -+ -+typedef struct { -+ uint8_t version; -+ uint8_t display_color_index; -+ uint8_t custom_r; -+ uint8_t custom_g; -+ uint8_t custom_b; -+ bool settings_is_loaded; -+} RGBBacklightSettings; -+ -+/** -+ * @brief Получить текущие настройки RGB-подсветки -+ * -+ * @return Указатель на структуру настроек -+ */ -+RGBBacklightSettings* rgb_backlight_get_settings(void); -+ -+/** -+ * @brief Загрузить настройки подсветки с SD-карты -+ */ -+void rgb_backlight_load_settings(void); -+ -+/** -+ * @brief Сохранить текущие настройки RGB-подсветки -+ */ -+void rgb_backlight_save_settings(void); -+ -+/** -+ * @brief Применить текущие настройки RGB-подсветки -+ * -+ * @param brightness Яркость свечения (0-255) -+ * @param bypass Применить настройки принудительно -+ */ -+void rgb_backlight_update(uint8_t brightness, bool bypass); -+ -+/** -+ * @brief Установить цвет RGB-подсветки -+ * -+ * @param color_index Индекс цвета (0 - rgb_backlight_get_color_count()) -+ */ -+void rgb_backlight_set_color(uint8_t color_index); -+ -+/** -+ * @brief Set custom color values by index - 0=R 1=G 2=B -+ * -+ * @param color - color value (0-255) -+ * @param index - color index (0-2) 0=R 1=G 2=B -+ */ -+void rgb_backlight_set_custom_color(uint8_t color, uint8_t index); -+ -+/** -+ * @brief Получить количество доступных цветов -+ * -+ * @return Число доступных вариантов цвета -+ */ -+uint8_t rgb_backlight_get_color_count(void); -+ -+/** -+ * @brief Получить текстовое название цвета -+ * -+ * @param index Индекс из доступных вариантов цвета -+ * @return Указатель на строку с названием цвета -+ */ -+const char* rgb_backlight_get_color_text(uint8_t index); -diff --git a/lib/drivers/SK6805.c b/lib/drivers/SK6805.c -new file mode 100644 -index 0000000..b89f82a ---- /dev/null -+++ b/lib/drivers/SK6805.c -@@ -0,0 +1,103 @@ -+/* -+ 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(150); -+ 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_delay_us(150); -+ FURI_CRITICAL_EXIT(); -+} -diff --git a/lib/drivers/SK6805.h b/lib/drivers/SK6805.h -new file mode 100644 -index 0000000..c97054f ---- /dev/null -+++ b/lib/drivers/SK6805.h -@@ -0,0 +1,51 @@ -+/* -+ 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 . -+*/ -+ -+#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_ */ -diff --git a/targets/f7/furi_hal/furi_hal_light.c b/targets/f7/furi_hal/furi_hal_light.c -index 621478d..ef15153 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 - - #define LED_CURRENT_RED (50u) - #define LED_CURRENT_GREEN (50u) -@@ -31,22 +32,21 @@ void furi_hal_light_init(void) { - } - - void furi_hal_light_set(Light light, uint8_t value) { -- furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); -- if(light & LightRed) { -- lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value); -- } -- if(light & LightGreen) { -- lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value); -- } -- if(light & LightBlue) { -- lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value); -- } - if(light & LightBacklight) { -- 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_update(value, false); -+ } else { -+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); -+ if(light & LightRed) { -+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value); -+ } -+ if(light & LightGreen) { -+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value); -+ } -+ if(light & LightBlue) { -+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value); -+ } -+ furi_hal_i2c_release(&furi_hal_i2c_handle_power); - } -- furi_hal_i2c_release(&furi_hal_i2c_handle_power); - } - - void furi_hal_light_blink_start(Light light, uint8_t brightness, uint16_t on_time, uint16_t period) { diff --git a/.drone.yml b/.drone.yml index 008713039..15c66192c 100644 --- a/.drone.yml +++ b/.drone.yml @@ -81,25 +81,6 @@ steps: - mv dist/f7-C/* artifacts-extra-apps/ - ls -laS artifacts-extra-apps - ls -laS artifacts-extra-apps/f7-update-${DRONE_TAG}e - environment: - FBT_TOOLS_CUSTOM_LINK: - from_secret: fbt_link - - - name: "Build with RGB patch" - image: hfdj/fztools - pull: never - commands: - - git apply .ci_files/rgb.patch - - export DIST_SUFFIX=${DRONE_TAG}r - - export WORKFLOW_BRANCH_OR_TAG=release-cfw-rgb - - export FORCE_NO_DIRTY=yes - - export FBT_GIT_SUBMODULE_SHALLOW=1 - - rm -f build/f7-firmware-C/toolbox/version.* - - ./fbt COMPACT=1 DEBUG=0 updater_package - - mkdir artifacts-rgb-patch - - mv dist/f7-C/* artifacts-rgb-patch/ - - ls -laS artifacts-rgb-patch - - ls -laS artifacts-rgb-patch/f7-update-${DRONE_TAG}r - sed -i 's/(version)/'${DRONE_TAG}'/g' CHANGELOG.md - echo '# Install FW via Web Updater:' >> CHANGELOG.md - echo '### [Default](https://lab.flipper.net/?url=https://unleashedflip.com/fw/${DRONE_TAG}/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}') > ` `' >> CHANGELOG.md @@ -107,8 +88,6 @@ steps: - echo '### [Extra apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'e.tgz&channel=release-cfw&version='${DRONE_TAG}'e) > `e`' >> CHANGELOG.md - echo '' >> CHANGELOG.md - echo '### [No apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'c.tgz&channel=release-cfw&version='${DRONE_TAG}'c) > `c`' >> CHANGELOG.md - - echo '' >> CHANGELOG.md - - echo '### [RGB patch - only for hardware mod!](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'r.tgz&channel=release-cfw&version='${DRONE_TAG}'r) > `r`' >> CHANGELOG.md environment: FBT_TOOLS_CUSTOM_LINK: from_secret: fbt_link @@ -117,20 +96,16 @@ steps: image: joshkeegan/zip commands: - cp artifacts-extra-apps/flipper-z-f7-update-${DRONE_TAG}e.tgz . - - cp artifacts-rgb-patch/flipper-z-f7-update-${DRONE_TAG}r.tgz . - cp artifacts-clean/flipper-z-f7-update-${DRONE_TAG}c.tgz . - cp artifacts-default/flipper-z-f7-update-${DRONE_TAG}.tgz . - zip -r artifacts-extra-apps/flipper-z-f7-update-${DRONE_TAG}e.zip artifacts-extra-apps/f7-update-${DRONE_TAG}e - - zip -r artifacts-rgb-patch/flipper-z-f7-update-${DRONE_TAG}r.zip artifacts-rgb-patch/f7-update-${DRONE_TAG}r - zip -r artifacts-clean/flipper-z-f7-update-${DRONE_TAG}c.zip artifacts-clean/f7-update-${DRONE_TAG}c - zip -r artifacts-default/flipper-z-f7-update-${DRONE_TAG}.zip artifacts-default/f7-update-${DRONE_TAG} - tar czpf artifacts-default/flipper-z-any-scripts-${DRONE_TAG}.tgz scripts - rm -rf artifacts-extra-apps/f7-update-${DRONE_TAG} - - rm -rf artifacts-rgb-patch/f7-update-${DRONE_TAG} - rm -rf artifacts-clean/f7-update-${DRONE_TAG} - rm -rf artifacts-default/f7-update-${DRONE_TAG} - ls -laS artifacts-extra-apps - - ls -laS artifacts-rgb-patch - ls -laS artifacts-clean - ls -laS artifacts-default - mv artifacts-default/ ${DRONE_TAG} @@ -172,21 +147,6 @@ steps: from_secret: dep_target_extra source: flipper-z-f7-update-${DRONE_TAG}e.tgz - - name: "Upload rgb patch version to updates srv" - image: appleboy/drone-scp:linux-amd64 - settings: - host: - from_secret: dep_host - username: - from_secret: dep_user - password: - from_secret: dep_passwd - port: - from_secret: dep_port - target: - from_secret: dep_target_extra - source: flipper-z-f7-update-${DRONE_TAG}r.tgz - - name: "Upload clean version to updates srv" image: appleboy/drone-scp:linux-amd64 settings: @@ -215,7 +175,6 @@ steps: - ${DRONE_TAG}/*.tgz - ${DRONE_TAG}/*.zip - artifacts-extra-apps/*.tgz - - artifacts-rgb-patch/*.tgz - artifacts-clean/*.tgz title: ${DRONE_TAG} note: CHANGELOG.md @@ -399,30 +358,10 @@ steps: FBT_TOOLS_CUSTOM_LINK: from_secret: fbt_link - - name: "Build dev with rgb patch" - image: hfdj/fztools - pull: never - commands: - - git apply .ci_files/rgb.patch - - export DIST_SUFFIX=${DRONE_BUILD_NUMBER}r - - export WORKFLOW_BRANCH_OR_TAG=dev-cfw-rgb - - export FORCE_NO_DIRTY=yes - - export FBT_GIT_SUBMODULE_SHALLOW=1 - - rm -f build/f7-firmware-C/toolbox/version.* - - ./fbt COMPACT=1 DEBUG=0 updater_package - - mkdir artifacts-rgb-patch - - mv dist/f7-C/* artifacts-rgb-patch/ - - ls -laS artifacts-rgb-patch - - ls -laS artifacts-rgb-patch/f7-update-${DRONE_BUILD_NUMBER}r - environment: - FBT_TOOLS_CUSTOM_LINK: - from_secret: fbt_link - - name: "Bundle self-update packages" image: joshkeegan/zip commands: - cp artifacts-extra-apps/flipper-z-f7-update-${DRONE_BUILD_NUMBER}e.tgz . - - cp artifacts-rgb-patch/flipper-z-f7-update-${DRONE_BUILD_NUMBER}r.tgz . - cp artifacts-clean/flipper-z-f7-update-${DRONE_BUILD_NUMBER}c.tgz . - cp artifacts-default/flipper-z-f7-update-${DRONE_BUILD_NUMBER}.tgz . - rm -rf artifacts-default/f7-update-${DRONE_BUILD_NUMBER} @@ -481,21 +420,6 @@ steps: from_secret: dep_target_extra source: flipper-z-f7-update-${DRONE_BUILD_NUMBER}e.tgz - - name: "Upload rgb patch version to updates srv" - image: appleboy/drone-scp:linux-amd64 - settings: - host: - from_secret: dep_host - username: - from_secret: dep_user - password: - from_secret: dep_passwd - port: - from_secret: dep_port - target: - from_secret: dep_target_extra - source: flipper-z-f7-update-${DRONE_BUILD_NUMBER}r.tgz - - name: "Upload clean version to updates srv" image: appleboy/drone-scp:linux-amd64 settings: diff --git a/ReadMe.md b/ReadMe.md index 1ead8d451..c40fb71c4 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -28,7 +28,7 @@ Before getting started: - **Review the Official Documentation:** [docs.flipper.net](https://docs.flipper.net) - **Installation Guide & Version Info:** - How to install the firmware by following the [Installation Guide](/documentation/HowToInstall.md) and check the [version information](/CHANGELOG.md#recommended-update-option---web-updater) (`r`, `e`, ` `, `c`) + How to install the firmware by following the [Installation Guide](/documentation/HowToInstall.md) and check the [version information](/CHANGELOG.md#recommended-update-option---web-updater) (`e`, ` `, `c`) - **FAQ:** Find answers to common questions in the [FAQ](/documentation/FAQ.md) diff --git a/documentation/FAQ.md b/documentation/FAQ.md index a180c827d..cae0ba61c 100644 --- a/documentation/FAQ.md +++ b/documentation/FAQ.md @@ -9,15 +9,20 @@ See [this](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md) -## What version should I install? What do the letters `e`, `r`, `c`... mean? +## What version should I install? What do the letters `e`, `c`... mean? Follow this link for [details](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#recommended-update-option---web-updater). ## I installed Unleashed and now the backlight doesn't work -You’ve installed a version made for custom RGB modded flippers. The version ending in `r` is specifically for `RGB` modded flippers.
+You’ve enabled RGB backlight mod in settings made for custom RGB modded flippers.
Please, do not use that version if your flipper isn’t modded! +Disable in Settings -> Notifications -> RGB mod settings + +Make sure to have System -> Debug = ON before, otherwise first option (is mod installed) will not appear + +If you have RGB backlight mod do the same but enable the mod instead ## What apps (plugins) are included with Unleashed Firmware? From 21e2e9c148bdad581cafe8d8c85cac2bfab4112e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 15 Mar 2025 08:14:00 +0300 Subject: [PATCH 022/125] fmt and return settings to original value [ci skip] --- applications/services/notification/notification_app.h | 4 ++-- applications/services/rgb_backlight/rgb_backlight.c | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 0209ffa0b..798b01ab6 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -34,7 +34,7 @@ typedef struct { Light light; } NotificationLedLayer; -#define NOTIFICATION_SETTINGS_VERSION 0x03 +#define NOTIFICATION_SETTINGS_VERSION 0x02 #define NOTIFICATION_SETTINGS_PATH INT_PATH(NOTIFICATION_SETTINGS_FILE_NAME) typedef struct { @@ -60,4 +60,4 @@ struct NotificationApp { RGBBacklightApp* rgb_srv; }; -void notification_message_save_settings(NotificationApp* app); \ No newline at end of file +void notification_message_save_settings(NotificationApp* app); diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index 5510ea916..4104c20d3 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -105,7 +105,6 @@ void rainbow_timer_stop(RGBBacklightApp* app) { // 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 { From 16b8ec5a9c526757e9a8e557328bd269cbe37399 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 15 Mar 2025 08:37:37 +0300 Subject: [PATCH 023/125] upd changelog --- CHANGELOG.md | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c95c0d38..ff4ea9470 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,24 +1,28 @@ ## Main changes - Current API: 83.0 -* SubGHz: Add ReversRB2 / RB2M Protocol (static 64 bit) full support with add manually (by @xMasterX) -* SubGHz: Fix Hollarm protocol with more verification -* SubGHz: Fix GangQi protocol (by @DoberBit and @mishamyte (who spent 2 weeks on this)) -* SubGHz: Came Atomo button hold simulation with full cycle simulation (to allow proper pairing with receiver) +* SubGHz: Add **ReversRB2 / RB2M Protocol** (static 64 bit) **full support** with add manually (by @xMasterX) +* SubGHz: **Fix Hollarm protocol with more verification** +* SubGHz: **Fix GangQi protocol** (by @DoberBit and @mishamyte ( who spent 2 weeks on this :O )) +* SubGHz: **Came Atomo button hold simulation with full cycle** simulation (to allow proper pairing with receiver) +* System: **Сombining RGB Backlight mod** (by @quen0n) and original backlight support **in one firmware** (+ Rainbow effect (based on @Willy-JL idea)) (PR #877 | by @Dmitry422) - (**To enable RGB Backlight support go into Notifications settings with Debug mode = ON**) * OFW: LFRFID - **EM4305 support** -* OFW: Universal IR signal selection -* OFW: BadUSB: Mouse control +* OFW: **Universal IR signal selection** +* OFW: **BadUSB: Mouse control** * OFW: NFC - Added naming for DESFire cards + fix MF3ICD40 cards unable to be read -* Apps: Add FindMyFlipper to system apps and allow autostart on system boot [app by @MatthewKuKanich](https://github.com/MatthewKuKanich/FindMyFlipper) and autoloader by @Willy-JL - to use app please check how to add keys in [app repo](https://github.com/MatthewKuKanich/FindMyFlipper) +* Apps: Add **FindMyFlipper to system apps and allow autostart** on system boot [app by @MatthewKuKanich](https://github.com/MatthewKuKanich/FindMyFlipper) and autoloader by @Willy-JL - to use app please check how to add keys in [app repo](https://github.com/MatthewKuKanich/FindMyFlipper) * README Update: Enhanced Visuals & Navigation (PR #871 #872 | by @m-xim) * Docs: Update FAQ.md (PR #865 | by @mi-lrn) * Input: Vibro on Button press option (PR #867 | by @Dmitry422) -* Power: Option to limit battery charging (suppress charging on selected charge level) (PR #867 | by @Dmitry422) +* Power: Option to limit battery charging (suppress charging on selected charge level) (PR #867 | by @Dmitry422) (idea and example by @oltenxyz) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes +* SubGHz: Various bugfixes and experimental options (rolling counter overflow) (by @xMasterX) * Anims: Disable winter anims * NFC: mfclassic poller fix early key reuse in dictionary attack state machine (by @noproto) +* OFW PR 4149: HID Ble: increased stack and improvements (by @doomwastaken) * OFW PR 4126: Stricter constness for const data (by @hedger) * OFW PR 4017: Alarm improvements: Snooze, timeouts, and dismissing from the locked state (by @Astrrra) +* OFW: fix: flipper detected before it was rebooted * OFW: NFC: FeliCa Protocol Expose Read Block API and Allow Specifying Service * OFW: LFRFID: Fix Detection Conflict Between Securakey and Noralsy Format (by @zinongli) * OFW: Stdio API improvements @@ -78,20 +82,22 @@ and all other great people who supported our project and me (xMasterX), thanks t ## **Recommended update option - Web Updater** -### What `r`, `e`, ` `, `c` means? What I need to download if I don't want to use Web updater? -What build I should download and what this name means - `flipper-z-f7-update-(version)(r / e / c).tgz` ?
+### What `e`, ` `, `c` means? What I need to download if I don't want to use Web updater? +What build I should download and what this name means - `flipper-z-f7-update-(version)(e / c).tgz` ?
`flipper-z` = for Flipper Zero device
`f7` = Hardware version - same for all flipper zero devices
`update` = Update package, contains updater, all assets (plugins, IR libs, etc.), and firmware itself
`(version)` = Firmware version
-| Designation | [Base Apps](https://github.com/xMasterX/all-the-plugins#default-pack) | [Extra Apps](https://github.com/xMasterX/all-the-plugins#extra-pack) | ⚠️RGB mode* | -|-----|:---:|:---:|:---:| -| ` ` | ✅ | | | -| `c` | | | | -| `e` | ✅ | ✅ | | -| `r` | ✅ | ✅ | ⚠️ | +| Designation | [Base Apps](https://github.com/xMasterX/all-the-plugins#default-pack) | [Extra Apps](https://github.com/xMasterX/all-the-plugins#extra-pack) | +|-----|:---:|:---:| +| ` ` | ✅ | | +| `c` | | | +| `e` | ✅ | ✅ | + +**To enable RGB Backlight support go into Notifications settings with Debug mode = ON** + +⚠️RGB backlight [hardware mod](https://github.com/quen0n/flipperzero-firmware-rgb#readme), works only on modded flippers! do not enable on non modded device! -⚠️This is [hardware mod](https://github.com/quen0n/flipperzero-firmware-rgb#readme), works only on modded flippers! do not install on non modded device! Firmware Self-update package (update from microSD) - `flipper-z-f7-update-(version).tgz` for mobile app / qFlipper / web
Archive of `scripts` folder (contains scripts for FW/plugins development) - `flipper-z-any-scripts-(version).tgz`
From c04ce78fcd8e815f52c48c69551be355037c056f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 15 Mar 2025 09:02:21 +0300 Subject: [PATCH 024/125] fix messages [ci skip] --- .ci_files/devbuild_msg_discord.txt | 2 +- .ci_files/devbuild_msg_telegram.txt | 2 +- .ci_files/release_msg_discord.txt | 2 +- .ci_files/release_msg_telegram.txt | 2 +- CHANGELOG.md | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.ci_files/devbuild_msg_discord.txt b/.ci_files/devbuild_msg_discord.txt index 0bc802364..41a70e45e 100644 --- a/.ci_files/devbuild_msg_discord.txt +++ b/.ci_files/devbuild_msg_discord.txt @@ -9,7 +9,7 @@ How to [install firmware](https://github.com/DarkFlippers/unleashed-firmware/blo [Default](https://lab.flipper.net/?url=https://unleashedflip.com/fw/dev/flipper-z-f7-update-(buildnum).tgz&channel=dev-cfw&version=(buildnum)) > ` ` [Extra apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)e.tgz&channel=dev-cfw&version=(buildnum)e) > `e` [No apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)c.tgz&channel=dev-cfw&version=(buildnum)c) > `c` -What ` `, `e`, `c` means? -> [versions info](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#what-n-r-e---c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater) +What ` `, `e`, `c` means? -> [versions info](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#what-e---c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater) ### Direct tgz download links: [Default](https://unleashedflip.com/fw/dev/flipper-z-f7-update-(buildnum).tgz) > ` ` - [Extra apps](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)e.tgz) > `e` - [No apps](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)c.tgz) > `c` diff --git a/.ci_files/devbuild_msg_telegram.txt b/.ci_files/devbuild_msg_telegram.txt index 5a3051471..13d0545dd 100644 --- a/.ci_files/devbuild_msg_telegram.txt +++ b/.ci_files/devbuild_msg_telegram.txt @@ -11,7 +11,7 @@ How to [install firmware](https://github.com/DarkFlippers/unleashed-firmware/blo [Extra apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)e.tgz&channel=dev-cfw&version=(buildnum)e) > `e` [No apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(buildnum)c.tgz&channel=dev-cfw&version=(buildnum)c) > `c` -What ` `, `e`, `c` means? -> [versions info](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#what-n-r-e---c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater) +What ` `, `e`, `c` means? -> [versions info](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#what-e---c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater) **Direct tgz download links:** [Default](https://unleashedflip.com/fw/dev/flipper-z-f7-update-(buildnum).tgz) > ` ` diff --git a/.ci_files/release_msg_discord.txt b/.ci_files/release_msg_discord.txt index e25e0d95b..8eadaaf1f 100644 --- a/.ci_files/release_msg_discord.txt +++ b/.ci_files/release_msg_discord.txt @@ -9,7 +9,7 @@ How to [install firmware](https://github.com/DarkFlippers/unleashed-firmware/blo [Default](https://lab.flipper.net/?url=https://unleashedflip.com/fw/(releasever)/flipper-z-f7-update-(releasever).tgz&channel=release-cfw&version=(releasever)) > ` ` [Extra apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)e.tgz&channel=release-cfw&version=(releasever)e) > `e` [No apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)c.tgz&channel=release-cfw&version=(releasever)c) > `c` -What ` `, `e`, `c` means? -> [versions info](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#what-n-r-e---c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater) +What ` `, `e`, `c` means? -> [versions info](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#what-e---c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater) ### Direct tgz download links: [Default](https://unleashedflip.com/fw/(releasever)/flipper-z-f7-update-(releasever).tgz) > ` ` - [Extra apps](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)e.tgz) > `e` - [No apps](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)c.tgz) > `c` diff --git a/.ci_files/release_msg_telegram.txt b/.ci_files/release_msg_telegram.txt index fd8c13bcf..6d527970f 100644 --- a/.ci_files/release_msg_telegram.txt +++ b/.ci_files/release_msg_telegram.txt @@ -11,7 +11,7 @@ How to [install firmware](https://github.com/DarkFlippers/unleashed-firmware/blo [Extra apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)e.tgz&channel=release-cfw&version=(releasever)e) > `e` [No apps](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-(releasever)c.tgz&channel=release-cfw&version=(releasever)c) > `c` -What ` `, `e`, `c` means? -> [versions info](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#what-n-r-e---c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater) +What ` `, `e`, `c` means? -> [versions info](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#what-e---c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater) **Direct tgz download links:** [Default](https://unleashedflip.com/fw/(releasever)/flipper-z-f7-update-(releasever).tgz) > ` ` diff --git a/CHANGELOG.md b/CHANGELOG.md index ff4ea9470..34e119d3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,10 @@ ## Main changes -- Current API: 83.0 -* SubGHz: Add **ReversRB2 / RB2M Protocol** (static 64 bit) **full support** with add manually (by @xMasterX) +- Current API: 83.1 +* SubGHz: Add **Revers RB2 / RB2M Protocol** (static 64 bit) **full support** with add manually (by @xMasterX) * SubGHz: **Fix Hollarm protocol with more verification** -* SubGHz: **Fix GangQi protocol** (by @DoberBit and @mishamyte ( who spent 2 weeks on this :O )) +* SubGHz: **Fix GangQi protocol** (by @DoberBit and @mishamyte (who spent 2 weeks on this)) * SubGHz: **Came Atomo button hold simulation with full cycle** simulation (to allow proper pairing with receiver) -* System: **Сombining RGB Backlight mod** (by @quen0n) and original backlight support **in one firmware** (+ Rainbow effect (based on @Willy-JL idea)) (PR #877 | by @Dmitry422) - (**To enable RGB Backlight support go into Notifications settings with Debug mode = ON**) +* System: **Сombining RGB Backlight mod** (by @quen0n) and original backlight support **in one firmware** (+ Rainbow effect (based on @Willy-JL idea)) (PR #877 | by @Dmitry422) - (**To enable RGB Backlight support go into Notifications settings with Debug mode - ON**) * OFW: LFRFID - **EM4305 support** * OFW: **Universal IR signal selection** * OFW: **BadUSB: Mouse control** From 94b369657d8c411c7e101312e824c8012f023d66 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 15 Mar 2025 09:32:19 +0300 Subject: [PATCH 025/125] upd changelog and add fix --- CHANGELOG.md | 1 + applications/main/infrared/infrared_brute_force.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34e119d3e..adb257d38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ * SubGHz: Various bugfixes and experimental options (rolling counter overflow) (by @xMasterX) * Anims: Disable winter anims * NFC: mfclassic poller fix early key reuse in dictionary attack state machine (by @noproto) +* OFW PR 4132: Infrared: Fix universals sending (by @Willy-JL) * OFW PR 4149: HID Ble: increased stack and improvements (by @doomwastaken) * OFW PR 4126: Stricter constness for const data (by @hedger) * OFW PR 4017: Alarm improvements: Snooze, timeouts, and dismissing from the locked state (by @Astrrra) diff --git a/applications/main/infrared/infrared_brute_force.c b/applications/main/infrared/infrared_brute_force.c index 636635894..1ec4645e9 100644 --- a/applications/main/infrared/infrared_brute_force.c +++ b/applications/main/infrared/infrared_brute_force.c @@ -104,9 +104,9 @@ InfraredErrorCode infrared_brute_force_calculate_messages(InfraredBruteForce* br break; } - size_t signal_start = flipper_format_tell(ff); bool signal_valid = false; while(infrared_signal_read_name(ff, signal_name) == InfraredErrorCodeNone) { + size_t signal_start = flipper_format_tell(ff); error = infrared_signal_read_body(signal, ff); signal_valid = (!INFRARED_ERROR_PRESENT(error)) && infrared_signal_is_valid(signal); if(!signal_valid) break; From edd75a9b01d2cc7fd06328c0eb4dabc0087c1407 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 16 Mar 2025 04:21:02 +0300 Subject: [PATCH 026/125] init rgb only once on boot if mod is not present testing required!!! --- applications/services/application.fam | 1 + applications/services/region/application.fam | 10 -- applications/services/region/region.c | 140 ------------------ .../services/rgb_backlight/application.fam | 12 +- .../services/rgb_backlight/rgb_backlight.c | 34 +++-- .../rgb_backlight/rgb_backlight_on_boot.c | 56 +++++++ 6 files changed, 88 insertions(+), 165 deletions(-) delete mode 100644 applications/services/region/application.fam delete mode 100644 applications/services/region/region.c create mode 100644 applications/services/rgb_backlight/rgb_backlight_on_boot.c diff --git a/applications/services/application.fam b/applications/services/application.fam index 8cfb22cdb..f23b905e5 100644 --- a/applications/services/application.fam +++ b/applications/services/application.fam @@ -12,5 +12,6 @@ App( "power", "namechanger_srv", "rgb_backlight", + "rgb_backlight_startup", ], ) diff --git a/applications/services/region/application.fam b/applications/services/region/application.fam deleted file mode 100644 index a4cdc94ea..000000000 --- a/applications/services/region/application.fam +++ /dev/null @@ -1,10 +0,0 @@ -App( - appid="region", - name="RegionSrv", - apptype=FlipperAppType.STARTUP, - targets=["f7"], - entry_point="region_on_system_start", - cdefines=["SRV_REGION"], - requires=["storage"], - order=170, -) diff --git a/applications/services/region/region.c b/applications/services/region/region.c deleted file mode 100644 index bed676f9b..000000000 --- a/applications/services/region/region.c +++ /dev/null @@ -1,140 +0,0 @@ -#include - -#include -#include - -#include -#include - -#define TAG "RegionSrv" - -#define SUBGHZ_REGION_FILENAME INT_PATH(".region_data") - -static bool region_istream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) { - File* file = istream->state; - size_t ret = storage_file_read(file, buf, count); - return count == ret; -} - -static bool region_istream_decode_band(pb_istream_t* stream, const pb_field_t* field, void** arg) { - UNUSED(field); - - FuriHalRegion* region = *arg; - - PB_Region_Band band = {0}; - if(!pb_decode(stream, PB_Region_Band_fields, &band)) { - FURI_LOG_E(TAG, "PB Region band decode error: %s", PB_GET_ERROR(stream)); - return false; - } - - region->bands_count += 1; - region = realloc( //-V701 - region, - sizeof(FuriHalRegion) + sizeof(FuriHalRegionBand) * region->bands_count); - size_t pos = region->bands_count - 1; - region->bands[pos].start = band.start; - region->bands[pos].end = band.end; - region->bands[pos].power_limit = band.power_limit; - region->bands[pos].duty_cycle = band.duty_cycle; - *arg = region; - - FURI_LOG_I( - TAG, - "Add allowed band: start %luHz, stop %luHz, power_limit %ddBm, duty_cycle %u%%", - band.start, - band.end, - band.power_limit, - band.duty_cycle); - return true; -} - -static int32_t region_load_file(void* context) { - UNUSED(context); - - Storage* storage = furi_record_open(RECORD_STORAGE); - File* file = storage_file_alloc(storage); - - PB_Region pb_region = {0}; - pb_region.bands.funcs.decode = region_istream_decode_band; - - do { - FileInfo fileinfo = {0}; - - if(storage_common_stat(storage, SUBGHZ_REGION_FILENAME, &fileinfo) != FSE_OK || - fileinfo.size == 0) { - FURI_LOG_W(TAG, "Region file missing or empty"); - break; - - } else if(!storage_file_open(file, SUBGHZ_REGION_FILENAME, FSAM_READ, FSOM_OPEN_EXISTING)) { - FURI_LOG_E(TAG, "Failed to open region file"); - break; - } - - pb_istream_t istream = { - .callback = region_istream_read, - .state = file, - .errmsg = NULL, - .bytes_left = fileinfo.size, - }; - - pb_region.bands.arg = malloc(sizeof(FuriHalRegion)); - - if(!pb_decode(&istream, PB_Region_fields, &pb_region)) { - FURI_LOG_E(TAG, "Failed to decode region file"); - free(pb_region.bands.arg); - break; - } - - FuriHalRegion* region = pb_region.bands.arg; - - memcpy( - region->country_code, - pb_region.country_code->bytes, - MIN(pb_region.country_code->size, sizeof(region->country_code) - 1)); - - furi_hal_region_set(region); - - FURI_LOG_I(TAG, "Dynamic region set: %s", region->country_code); - } while(0); - - pb_release(PB_Region_fields, &pb_region); - storage_file_free(file); - furi_record_close(RECORD_STORAGE); - - return 0; -} - -static void - region_loader_release_callback(FuriThread* thread, FuriThreadState state, void* context) { - UNUSED(context); - - if(state == FuriThreadStateStopped) { - furi_thread_free(thread); - } -} - -static void region_storage_callback(const void* message, void* context) { - UNUSED(context); - const StorageEvent* event = message; - - if(event->type == StorageEventTypeCardMount) { - FuriThread* loader = furi_thread_alloc_ex(NULL, 2048, region_load_file, NULL); - furi_thread_set_state_callback(loader, region_loader_release_callback); - furi_thread_start(loader); - } -} - -int32_t region_on_system_start(void* p) { - UNUSED(p); - - Storage* storage = furi_record_open(RECORD_STORAGE); - furi_pubsub_subscribe(storage_get_pubsub(storage), region_storage_callback, NULL); - - if(storage_sd_status(storage) != FSE_OK) { - FURI_LOG_D(TAG, "SD Card not ready, skipping dynamic region"); - return 0; - } - - region_load_file(NULL); - return 0; -} diff --git a/applications/services/rgb_backlight/application.fam b/applications/services/rgb_backlight/application.fam index 5e05233db..95da20f61 100644 --- a/applications/services/rgb_backlight/application.fam +++ b/applications/services/rgb_backlight/application.fam @@ -7,4 +7,14 @@ App( stack_size=1 * 1024, order=95, sdk_headers=["rgb_backlight.h"], -) \ No newline at end of file +) + +App( + appid="rgb_backlight_startup", + name="RgbBackLightBootSrv", + apptype=FlipperAppType.STARTUP, + targets=["f7"], + entry_point="rgb_backlight_on_system_start", + cdefines=["SRV_RGB_BACKLIGHT"], + order=270, +) diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index 4104c20d3..d74c54a02 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -82,14 +82,15 @@ void rgb_backlight_set_custom_color(uint8_t red, uint8_t green, uint8_t blue) { // 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); + if(app->settings->rgb_mod_installed) { + 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(); } - SK6805_update(); furi_record_close(RECORD_RGB_BACKLIGHT); } @@ -171,8 +172,8 @@ static void rainbow_timer_callback(void* context) { default: break; } + rgb_backlight_update(app->settings->brightness); } - rgb_backlight_update(app->settings->brightness); // if rainbow_mode is ..... do another effect // if(app->settings.rainbow_mode == ...) { @@ -185,7 +186,6 @@ int32_t rgb_backlight_srv(void* 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); @@ -197,6 +197,8 @@ int32_t rgb_backlight_srv(void* p) { // Init app variables app->rainbow_stage = 1; + furi_record_create(RECORD_RGB_BACKLIGHT, app); + // 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) { @@ -206,15 +208,19 @@ int32_t rgb_backlight_srv(void* p) { 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); - } + } //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"); + if(app->settings->rgb_mod_installed) { + FURI_LOG_D(TAG, "Mod is enabled - serivce is running"); + } else { + FURI_LOG_D(TAG, "Mod is DISABLED - serivce is running"); + } } return 0; } diff --git a/applications/services/rgb_backlight/rgb_backlight_on_boot.c b/applications/services/rgb_backlight/rgb_backlight_on_boot.c new file mode 100644 index 000000000..8a55426ca --- /dev/null +++ b/applications/services/rgb_backlight/rgb_backlight_on_boot.c @@ -0,0 +1,56 @@ + +#include +#include +#include "applications/services/rgb_backlight/rgb_backlight.h" + +static int32_t boot_rgb_backlight_update(void* context) { + UNUSED(context); + RGBBacklightApp* app = furi_record_open(RECORD_RGB_BACKLIGHT); + if(!app->settings->rgb_mod_installed) { + rgb_backlight_set_static_color(0); + for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { + uint8_t r = app->current_red * (1.0f / 1.0f); + uint8_t g = app->current_green * (1.0f / 1.0f); + uint8_t b = app->current_blue * (1.0f / 1.0f); + SK6805_set_led_color(i, r, g, b); + } + SK6805_update(); + } + furi_record_close(RECORD_RGB_BACKLIGHT); + return 0; +} + +static void + rgb_boot_loader_release_callback(FuriThread* thread, FuriThreadState state, void* context) { + UNUSED(context); + + if(state == FuriThreadStateStopped) { + furi_thread_free(thread); + } +} + +static void rgb_boot_storage_callback(const void* message, void* context) { + UNUSED(context); + const StorageEvent* event = message; + + if(event->type == StorageEventTypeCardMount) { + FuriThread* loader = furi_thread_alloc_ex(NULL, 2048, boot_rgb_backlight_update, NULL); + furi_thread_set_state_callback(loader, rgb_boot_loader_release_callback); + furi_thread_start(loader); + } +} + +int32_t rgb_backlight_on_system_start(void* p) { + UNUSED(p); + + Storage* storage = furi_record_open(RECORD_STORAGE); + furi_pubsub_subscribe(storage_get_pubsub(storage), rgb_boot_storage_callback, NULL); + + if(storage_sd_status(storage) != FSE_OK) { + FURI_LOG_D("RGB_Boot_Init", "SD Card not ready, skipping rgb backlight init"); + return 0; + } + + boot_rgb_backlight_update(NULL); + return 0; +} From b48e00928a9593ed16f89d1c84472d1d5679cbcb Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 16 Mar 2025 05:24:20 +0300 Subject: [PATCH 027/125] remove overkill service --- applications/services/application.fam | 1 - .../services/rgb_backlight/application.fam | 10 ---- .../services/rgb_backlight/rgb_backlight.c | 16 ++++-- .../rgb_backlight/rgb_backlight_on_boot.c | 56 ------------------- 4 files changed, 12 insertions(+), 71 deletions(-) delete mode 100644 applications/services/rgb_backlight/rgb_backlight_on_boot.c diff --git a/applications/services/application.fam b/applications/services/application.fam index f23b905e5..8cfb22cdb 100644 --- a/applications/services/application.fam +++ b/applications/services/application.fam @@ -12,6 +12,5 @@ App( "power", "namechanger_srv", "rgb_backlight", - "rgb_backlight_startup", ], ) diff --git a/applications/services/rgb_backlight/application.fam b/applications/services/rgb_backlight/application.fam index 95da20f61..631ca01d5 100644 --- a/applications/services/rgb_backlight/application.fam +++ b/applications/services/rgb_backlight/application.fam @@ -8,13 +8,3 @@ App( order=95, sdk_headers=["rgb_backlight.h"], ) - -App( - appid="rgb_backlight_startup", - name="RgbBackLightBootSrv", - apptype=FlipperAppType.STARTUP, - targets=["f7"], - entry_point="rgb_backlight_on_system_start", - cdefines=["SRV_RGB_BACKLIGHT"], - order=270, -) diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index d74c54a02..03f8f9af0 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -208,10 +208,18 @@ int32_t rgb_backlight_srv(void* p) { 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); - //} + } else { + //rgb_backlight_set_static_color(0); + //rgb_backlight_update(app->settings->brightness); + rgb_backlight_set_static_color(0); + for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { + uint8_t r = app->current_red * (1.0f / 1.0f); + uint8_t g = app->current_green * (1.0f / 1.0f); + uint8_t b = app->current_blue * (1.0f / 1.0f); + SK6805_set_led_color(i, r, g, b); + } + SK6805_update(); + } while(1) { // place for message queue and other future options diff --git a/applications/services/rgb_backlight/rgb_backlight_on_boot.c b/applications/services/rgb_backlight/rgb_backlight_on_boot.c deleted file mode 100644 index 8a55426ca..000000000 --- a/applications/services/rgb_backlight/rgb_backlight_on_boot.c +++ /dev/null @@ -1,56 +0,0 @@ - -#include -#include -#include "applications/services/rgb_backlight/rgb_backlight.h" - -static int32_t boot_rgb_backlight_update(void* context) { - UNUSED(context); - RGBBacklightApp* app = furi_record_open(RECORD_RGB_BACKLIGHT); - if(!app->settings->rgb_mod_installed) { - rgb_backlight_set_static_color(0); - for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { - uint8_t r = app->current_red * (1.0f / 1.0f); - uint8_t g = app->current_green * (1.0f / 1.0f); - uint8_t b = app->current_blue * (1.0f / 1.0f); - SK6805_set_led_color(i, r, g, b); - } - SK6805_update(); - } - furi_record_close(RECORD_RGB_BACKLIGHT); - return 0; -} - -static void - rgb_boot_loader_release_callback(FuriThread* thread, FuriThreadState state, void* context) { - UNUSED(context); - - if(state == FuriThreadStateStopped) { - furi_thread_free(thread); - } -} - -static void rgb_boot_storage_callback(const void* message, void* context) { - UNUSED(context); - const StorageEvent* event = message; - - if(event->type == StorageEventTypeCardMount) { - FuriThread* loader = furi_thread_alloc_ex(NULL, 2048, boot_rgb_backlight_update, NULL); - furi_thread_set_state_callback(loader, rgb_boot_loader_release_callback); - furi_thread_start(loader); - } -} - -int32_t rgb_backlight_on_system_start(void* p) { - UNUSED(p); - - Storage* storage = furi_record_open(RECORD_STORAGE); - furi_pubsub_subscribe(storage_get_pubsub(storage), rgb_boot_storage_callback, NULL); - - if(storage_sd_status(storage) != FSE_OK) { - FURI_LOG_D("RGB_Boot_Init", "SD Card not ready, skipping rgb backlight init"); - return 0; - } - - boot_rgb_backlight_update(NULL); - return 0; -} From 05423d5cb357876b5b89dc519bc5d28c2e5da994 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Sun, 16 Mar 2025 22:42:22 +0700 Subject: [PATCH 028/125] Start rgb backlight settings refactoring and adding new options; --- .../services/rgb_backlight/rgb_backlight.c | 36 +-- .../rgb_backlight/rgb_backlight_settings.c | 22 +- .../rgb_backlight/rgb_backlight_settings.h | 14 +- .../notification_settings_app.c | 266 ++++++++++++------ 4 files changed, 226 insertions(+), 112 deletions(-) diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index 03f8f9af0..9b25ded5b 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -42,7 +42,7 @@ static const RGBBacklightColor colors[] = { {"Pink", 255, 0, 127}, {"Red", 255, 0, 0}, {"White", 254, 210, 200}, - {"Custom", 0, 0, 0}, + {"Custom", 255, 255, 255}, }; uint8_t rgb_backlight_get_color_count(void) { @@ -82,7 +82,7 @@ void rgb_backlight_set_custom_color(uint8_t red, uint8_t green, uint8_t blue) { // 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); - if(app->settings->rgb_mod_installed) { + if(app->settings->rgb_backlight_mode > 0) { 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); @@ -104,9 +104,9 @@ 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 +// if rgb_backlight_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)) { + if((app->settings->rainbow_mode > 0) && (app->settings->rgb_backlight_installed)) { rainbow_timer_start(app); } else { if(furi_timer_is_running(app->rainbow_timer)) { @@ -200,22 +200,22 @@ int32_t rgb_backlight_srv(void* p) { furi_record_create(RECORD_RGB_BACKLIGHT, app); // 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) + // + // TODO запуск сохраненного режима + if(app->settings->rgb_backlight_mode > 0) { + // 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 mode = 0 (rgb_backlight not installed) then set default static orange color (index=0) and light on default color } else { - //rgb_backlight_set_static_color(0); - //rgb_backlight_update(app->settings->brightness); rgb_backlight_set_static_color(0); for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { - uint8_t r = app->current_red * (1.0f / 1.0f); - uint8_t g = app->current_green * (1.0f / 1.0f); - uint8_t b = app->current_blue * (1.0f / 1.0f); + uint8_t r = app->current_red * 1.0f; + uint8_t g = app->current_green * 1.0f; + uint8_t b = app->current_blue * 1.0f; SK6805_set_led_color(i, r, g, b); } SK6805_update(); @@ -224,7 +224,7 @@ int32_t rgb_backlight_srv(void* p) { while(1) { // place for message queue and other future options furi_delay_ms(5000); - if(app->settings->rgb_mod_installed) { + if(app->settings->rgb_backlight_mode > 0) { FURI_LOG_D(TAG, "Mod is enabled - serivce is running"); } else { FURI_LOG_D(TAG, "Mod is DISABLED - serivce is running"); diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.c b/applications/services/rgb_backlight/rgb_backlight_settings.c index 7e69eb0dc..7c73ddf19 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.c +++ b/applications/services/rgb_backlight/rgb_backlight_settings.c @@ -10,18 +10,27 @@ #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 +#define RGB_BACKLIGHT_SETTINGS_VER (1) // Current version number //pervious settings must be copyed from previous rgb_backlight_settings.h file typedef struct { + //Common settings uint8_t version; - bool rgb_mod_installed; + uint8_t rgb_backlight_mode; + float brightness; + //static and custom colors mode settings uint8_t static_color_index; - uint8_t custom_r; - uint8_t custom_g; - uint8_t custom_b; + uint8_t custom_red; + uint8_t custom_green; + uint8_t custom_blue; + // static gradient mode settings + uint8_t static_vd1_index; + uint8_t static_vd2_index; + uint8_t static_vd3_index; + + // rainbow mode setings uint32_t rainbow_mode; uint32_t rainbow_speed_ms; uint16_t rainbow_step; @@ -79,6 +88,9 @@ void rgb_backlight_settings_load(RGBBacklightSettings* settings) { settings->brightness = 1.0f; settings->rainbow_speed_ms = 100; settings->rainbow_step = 1; + settings->custom_red=255; + settings->custom_green = 255; + settings->custom_blue=255; rgb_backlight_settings_save(settings); } } diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.h b/applications/services/rgb_backlight/rgb_backlight_settings.h index 48b0c43b9..478048039 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.h +++ b/applications/services/rgb_backlight/rgb_backlight_settings.h @@ -4,15 +4,23 @@ #include typedef struct { + //Common settings uint8_t version; - bool rgb_mod_installed; + uint8_t rgb_backlight_mode; + float brightness; + //static and custom colors mode settings uint8_t static_color_index; uint8_t custom_red; uint8_t custom_green; uint8_t custom_blue; - float brightness; - + + // static gradient mode settings + uint8_t static_vd1_index; + uint8_t static_vd2_index; + uint8_t static_vd3_index; + + // rainbow mode setings uint32_t rainbow_mode; uint32_t rainbow_speed_ms; uint16_t rainbow_step; diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index ff90e96e7..cc316e6aa 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -110,30 +110,40 @@ 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", +// #define RGB_BACKLIGHT_INSTALLED_COUNT 2 +// const char* const rgb_backlight_installed_text[RGB_BACKLIGHT_INSTALLED_COUNT] = { +// "OFF", +// "ON", +// }; +// const bool rgb_backlight_installed_value[RGB_BACKLIGHT_INSTALLED_COUNT] = {false, true}; + +#define RGB_BACKLIGHT_MODE_COUNT 4 +const char* const rgb_backlight_mode_text[RGB_BACKLIGHT_MODE_COUNT] = { + "OFF" + "OneColor", + 'Gradient', "Rainbow", }; -const uint32_t rgb_mod_rainbow_mode_value[RGB_MOD_RAINBOW_MODE_COUNT] = {0, 1}; +const uint32_t rgb_backlight_mode_value[RGB_BACKLIGHT_MODE_COUNT] = {0, 1, 3, 4}; -#define RGB_MOD_RAINBOW_SPEED_COUNT 20 -const char* const rgb_mod_rainbow_speed_text[RGB_MOD_RAINBOW_SPEED_COUNT] = { +#define RGB_BACKLIGHT_RAINBOW_MODE_COUNT 2 +const char* const rgb_backlight_rainbow_mode_text[RGB_BACKLIGHT_RAINBOW_MODE_COUNT] = { + "Rainbow", + "Wave", +}; +const uint32_t rgb_backlight_rainbow_mode_value[RGB_BACKLIGHT_RAINBOW_MODE_COUNT] = {1, 2}; + +#define RGB_BACKLIGHT_RAINBOW_SPEED_COUNT 20 +const char* const rgb_backlight_rainbow_speed_text[RGB_BACKLIGHT_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] = { +const uint32_t rgb_backlight_rainbow_speed_value[RGB_BACKLIGHT_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] = { +#define RGB_BACKLIGHT_RAINBOW_STEP_COUNT 10 +const char* const rgb_backlight_rainbow_step_text[RGB_BACKLIGHT_RAINBOW_STEP_COUNT] = { "1", "2", "3", @@ -145,7 +155,7 @@ const char* const rgb_mod_rainbow_step_text[RGB_MOD_RAINBOW_SPEED_COUNT] = { "9", "10", }; -const uint32_t rgb_mod_rainbow_step_value[RGB_MOD_RAINBOW_STEP_COUNT] = +const uint32_t rgb_backlight_rainbow_step_value[RGB_BACKLIGHT_RAINBOW_STEP_COUNT] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; typedef enum { @@ -228,33 +238,76 @@ static void vibro_changed(VariableItem* item) { //--- RGB BACKLIGHT --- -static void rgb_mod_installed_changed(VariableItem* item) { +// static void rgb_backlight_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_backlight_installed_text[index]); +// app->notification->rgb_srv->settings->rgb_backlight_installed = rgb_backlight_installed_value[index]; +// rgb_backlight_settings_save(app->notification->rgb_srv->settings); +// // Lock/Unlock all rgb settings depent from rgb_backlight_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\nOFF!"); +// } else { +// variable_item_set_locked(t_item, false, "RGB\nOFF!"); +// } +// } + +//TODO по умолчанию все пункты ВЫКЛ, когда включаем РГБ установлен, то разблокируем только +// переключатель режима РГБ и в зависимости от его значения остальные пункты +// когда переключталь РГБ выключен, то выключаем все пункты меню. +// } + +static void rgb_backlight_mode_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]; + variable_item_set_current_value_text(item, rgb_backlight_mode_text[index]); + app->notification->rgb_srv->settings->rgb_backlight_mode = rgb_backlight_mode_value[index]; rgb_backlight_settings_save(app->notification->rgb_srv->settings); - // Lock/Unlock rgb settings depent from rgb_mod_installed switch + + // Lock/Unlock rgb settings depent from selected mode 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!"); - } + + VariableItem* t_item = variable_item_list_get(app->variable_item_list_rgb, i); + + switch(index) { + // OneColor + case 0: + break; + // Gradient + case 1: + break; + // Rainbow + case 2: + break; + default: + break; } + + // 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) { +static void rgb_backlight_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]; + variable_item_set_current_value_text(item, rgb_backlight_rainbow_mode_text[index]); + app->notification->rgb_srv->settings->rainbow_mode = rgb_backlight_rainbow_mode_value[index]; rainbow_timer_starter(app->notification->rgb_srv); rgb_backlight_settings_save(app->notification->rgb_srv->settings); @@ -280,24 +333,25 @@ static void rgb_mod_rainbow_changed(VariableItem* item) { } } -static void rgb_mod_rainbow_speed_changed(VariableItem* item) { +static void rgb_backlight_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]; + variable_item_set_current_value_text(item, rgb_backlight_rainbow_speed_text[index]); + app->notification->rgb_srv->settings->rainbow_speed_ms = + rgb_backlight_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) { +static void rgb_backlight_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]; + variable_item_set_current_value_text(item, rgb_backlight_rainbow_step_text[index]); + app->notification->rgb_srv->settings->rainbow_step = rgb_backlight_rainbow_step_value[index]; rgb_backlight_settings_save(app->notification->rgb_srv->settings); } @@ -320,9 +374,12 @@ 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; + // Update all current colors with selected customs and save changed custom color to settings app->notification->rgb_srv->current_red = index; + app->notification->rgb_srv->current_green = app->notification->rgb_srv->settings->custom_green; + app->notification->rgb_srv->current_blue = app->notification->rgb_srv->settings->custom_blue; + + app->notification->rgb_srv->settings->custom_red = index; app->notification->rgb_srv->settings->static_color_index = 13; char valtext[4] = {}; @@ -340,9 +397,12 @@ 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; + // Update all current colors with selected customs and save changed custom color to settings + app->notification->rgb_srv->current_red = app->notification->rgb_srv->settings->custom_red; app->notification->rgb_srv->current_green = index; + app->notification->rgb_srv->current_blue = app->notification->rgb_srv->settings->custom_blue; + + app->notification->rgb_srv->settings->custom_green = index; app->notification->rgb_srv->settings->static_color_index = 13; char valtext[4] = {}; @@ -360,9 +420,12 @@ 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; + // Update all current colors with selected customs and save changed custom color to settings + app->notification->rgb_srv->current_red = app->notification->rgb_srv->settings->custom_red; + app->notification->rgb_srv->current_green = app->notification->rgb_srv->settings->custom_green; app->notification->rgb_srv->current_blue = index; + + app->notification->rgb_srv->settings->custom_blue = index; app->notification->rgb_srv->settings->static_color_index = 13; char valtext[4] = {}; @@ -377,12 +440,12 @@ static void color_set_custom_blue(VariableItem* item) { 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) +// open rgb_settings_view if user press OK on first (index=0) menu string and (debug mode or rgb_backlight_installed 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) || + if(((app->notification->rgb_srv->settings->rgb_backlight_installed) || (furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug))) && (index == 0)) { view_dispatcher_switch_to_view(app->view_dispatcher, RGBViewId); @@ -420,10 +483,10 @@ static NotificationAppSettings* alloc_settings(void) { 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) || + //Show RGB settings only when debug_mode or rgb_backlight_installed is active + if((app->notification->rgb_srv->settings->rgb_backlight_installed) || (furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug))) { - item = variable_item_list_add(app->variable_item_list, "RGB mod settings", 0, NULL, app); + item = variable_item_list_add(app->variable_item_list, "RGB settings", 0, NULL, app); } //--- RGB BACKLIGHT END --- @@ -490,22 +553,39 @@ static NotificationAppSettings* alloc_settings(void) { // 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]); - } + // // Show rgb_backlight_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_BACKLIGHT_INSTALLED_COUNT, + // rgb_backlight_installed_changed, + // app); + // value_index = value_index_bool( + // app->notification->rgb_srv->settings->rgb_backlight_installed, + // rgb_backlight_installed_value, + // RGB_BACKLIGHT_INSTALLED_COUNT); + // variable_item_set_current_value_index(item, value_index); + // variable_item_set_current_value_text(item, rgb_backlight_installed_text[value_index]); + // } + // Show rgb_backlight_mode_swith only in Debug mode or when rgb_mode is not OFF. + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) || + (app->notification->rgb_srv->settings->rgb_backlight_mode > 0)) { + item = variable_item_list_add( + app->variable_item_list_rgb, + "RGB MODE", + RGB_BACKLIGHT_MODE_COUNT, + rgb_backlight_mode_changed, + app); + value_index = value_index_uint32( + app->notification->rgb_srv->settings->rgb_backlight_mode, + rgb_backlight_mode_value, + RGB_BACKLIGHT_MODE_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_backlight_mode_text[value_index]); + } + // Static Colors settings item = variable_item_list_add( app->variable_item_list_rgb, @@ -519,7 +599,9 @@ static NotificationAppSettings* alloc_settings(void) { 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, + (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); temp_item = item; @@ -534,7 +616,9 @@ static NotificationAppSettings* alloc_settings(void) { 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, + (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); item = variable_item_list_add( app->variable_item_list_rgb, "Custom Green", 255, color_set_custom_green, app); @@ -545,7 +629,9 @@ static NotificationAppSettings* alloc_settings(void) { 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, + (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); item = variable_item_list_add( app->variable_item_list_rgb, "Custom Blue", 255, color_set_custom_blue, app); @@ -556,53 +642,61 @@ static NotificationAppSettings* alloc_settings(void) { 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, + (app->notification->rgb_srv->settings->rgb_backlight_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, + RGB_BACKLIGHT_RAINBOW_MODE_COUNT, + rgb_backlight_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); + rgb_backlight_rainbow_mode_value, + RGB_BACKLIGHT_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_current_value_text(item, rgb_backlight_rainbow_mode_text[value_index]); variable_item_set_locked( - item, (app->notification->rgb_srv->settings->rgb_mod_installed == 0), "RGB MOD \nOFF!"); + item, + (app->notification->rgb_srv->settings->rgb_backlight_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, + RGB_BACKLIGHT_RAINBOW_SPEED_COUNT, + rgb_backlight_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); + rgb_backlight_rainbow_speed_value, + RGB_BACKLIGHT_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_current_value_text(item, rgb_backlight_rainbow_speed_text[value_index]); variable_item_set_locked( - item, (app->notification->rgb_srv->settings->rgb_mod_installed == 0), "RGB MOD \nOFF!"); + item, + (app->notification->rgb_srv->settings->rgb_backlight_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, + RGB_BACKLIGHT_RAINBOW_STEP_COUNT, + rgb_backlight_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); + rgb_backlight_rainbow_step_value, + RGB_BACKLIGHT_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_current_value_text(item, rgb_backlight_rainbow_step_text[value_index]); variable_item_set_locked( - item, (app->notification->rgb_srv->settings->rgb_mod_installed == 0), "RGB MOD \nOFF!"); + item, + (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); //--- RGB BACKLIGHT END --- @@ -632,8 +726,8 @@ int32_t notification_settings_app(void* p) { 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) { + // Automaticaly switch_off debug_mode when user exit from settings with enabled rgb_backlight_installed + // if(app->notification->settings.rgb_backlight_installed) { // furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); // } From c66b332a7dd369b90e42cb66aaee7f0857749830 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Mon, 17 Mar 2025 23:56:39 +0700 Subject: [PATCH 029/125] refactor rgb_backlight --- .../services/rgb_backlight/rgb_backlight.c | 30 +- .../rgb_backlight/rgb_backlight_settings.c | 2 +- .../rgb_backlight/rgb_backlight_settings.h | 8 +- .../notification_settings_app.c | 287 ++++-------------- 4 files changed, 87 insertions(+), 240 deletions(-) diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index 9b25ded5b..f3d3cfb35 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -42,7 +42,7 @@ static const RGBBacklightColor colors[] = { {"Pink", 255, 0, 127}, {"Red", 255, 0, 0}, {"White", 254, 210, 200}, - {"Custom", 255, 255, 255}, + {"White1", 255, 255, 255}, }; uint8_t rgb_backlight_get_color_count(void) { @@ -54,19 +54,27 @@ const char* rgb_backlight_get_color_text(uint8_t index) { } // use RECORD for acces to rgb service instance and update current colors by static -void rgb_backlight_set_static_color(uint8_t index) { +void rgb_backlight_set_static_color(uint8_t index, uint8_t vd) { 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; + if(vd < SK6805_get_led_count()) { + uint8_t r = colors[index].red; + uint8_t g = colors[index].green; + uint8_t b = colors[index].blue; + SK6805_set_led_color(vd, r, g, b); + SK6805_update(); } + + //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); } diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.c b/applications/services/rgb_backlight/rgb_backlight_settings.c index 7c73ddf19..e2a2e5df7 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.c +++ b/applications/services/rgb_backlight/rgb_backlight_settings.c @@ -16,7 +16,7 @@ typedef struct { //Common settings uint8_t version; - uint8_t rgb_backlight_mode; + bool rgb_backlight_installed; float brightness; //static and custom colors mode settings diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.h b/applications/services/rgb_backlight/rgb_backlight_settings.h index 478048039..694161c2b 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.h +++ b/applications/services/rgb_backlight/rgb_backlight_settings.h @@ -6,14 +6,8 @@ typedef struct { //Common settings uint8_t version; - uint8_t rgb_backlight_mode; + uint8_t rgb_backlight_installed; float brightness; - - //static and custom colors mode settings - uint8_t static_color_index; - uint8_t custom_red; - uint8_t custom_green; - uint8_t custom_blue; // static gradient mode settings uint8_t static_vd1_index; diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index cc316e6aa..1a738b492 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -111,28 +111,20 @@ const bool vibro_value[VIBRO_COUNT] = {false, true}; // --- RGB BACKLIGHT --- -// #define RGB_BACKLIGHT_INSTALLED_COUNT 2 -// const char* const rgb_backlight_installed_text[RGB_BACKLIGHT_INSTALLED_COUNT] = { -// "OFF", -// "ON", -// }; -// const bool rgb_backlight_installed_value[RGB_BACKLIGHT_INSTALLED_COUNT] = {false, true}; - -#define RGB_BACKLIGHT_MODE_COUNT 4 -const char* const rgb_backlight_mode_text[RGB_BACKLIGHT_MODE_COUNT] = { - "OFF" - "OneColor", - 'Gradient', - "Rainbow", +#define RGB_BACKLIGHT_INSTALLED_COUNT 2 +const char* const rgb_backlight_installed_text[RGB_BACKLIGHT_INSTALLED_COUNT] = { + "OFF", + "ON", }; -const uint32_t rgb_backlight_mode_value[RGB_BACKLIGHT_MODE_COUNT] = {0, 1, 3, 4}; +const bool rgb_backlight_installed_value[RGB_BACKLIGHT_INSTALLED_COUNT] = {false, true}; -#define RGB_BACKLIGHT_RAINBOW_MODE_COUNT 2 +#define RGB_BACKLIGHT_RAINBOW_MODE_COUNT 3 const char* const rgb_backlight_rainbow_mode_text[RGB_BACKLIGHT_RAINBOW_MODE_COUNT] = { + "OFF", "Rainbow", "Wave", }; -const uint32_t rgb_backlight_rainbow_mode_value[RGB_BACKLIGHT_RAINBOW_MODE_COUNT] = {1, 2}; +const uint32_t rgb_backlight_rainbow_mode_value[RGB_BACKLIGHT_RAINBOW_MODE_COUNT] = {0, 1, 2}; #define RGB_BACKLIGHT_RAINBOW_SPEED_COUNT 20 const char* const rgb_backlight_rainbow_speed_text[RGB_BACKLIGHT_RAINBOW_SPEED_COUNT] = { @@ -238,68 +230,25 @@ static void vibro_changed(VariableItem* item) { //--- RGB BACKLIGHT --- -// static void rgb_backlight_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_backlight_installed_text[index]); -// app->notification->rgb_srv->settings->rgb_backlight_installed = rgb_backlight_installed_value[index]; -// rgb_backlight_settings_save(app->notification->rgb_srv->settings); -// // Lock/Unlock all rgb settings depent from rgb_backlight_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\nOFF!"); -// } else { -// variable_item_set_locked(t_item, false, "RGB\nOFF!"); -// } -// } - -//TODO по умолчанию все пункты ВЫКЛ, когда включаем РГБ установлен, то разблокируем только -// переключатель режима РГБ и в зависимости от его значения остальные пункты -// когда переключталь РГБ выключен, то выключаем все пункты меню. -// } - -static void rgb_backlight_mode_changed(VariableItem* item) { +static void rgb_backlight_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_backlight_mode_text[index]); - app->notification->rgb_srv->settings->rgb_backlight_mode = rgb_backlight_mode_value[index]; + variable_item_set_current_value_text(item, rgb_backlight_installed_text[index]); + app->notification->rgb_srv->settings->rgb_backlight_installed = rgb_backlight_installed_value[index]; rgb_backlight_settings_save(app->notification->rgb_srv->settings); - - // Lock/Unlock rgb settings depent from selected mode + // Lock/Unlock all rgb settings depent from rgb_backlight_installed switch int slide = 0; if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { slide = 1; } - - VariableItem* t_item = variable_item_list_get(app->variable_item_list_rgb, i); - - switch(index) { - // OneColor - case 0: - break; - // Gradient - case 1: - break; - // Rainbow - case 2: - break; - default: - break; + 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\nOFF!"); + } else { + variable_item_set_locked(t_item, false, "RGB\nOFF!"); + } } - - // 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_backlight_rainbow_changed(VariableItem* item) { @@ -312,20 +261,6 @@ static void rgb_backlight_rainbow_changed(VariableItem* item) { 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); @@ -356,9 +291,8 @@ static void rgb_backlight_rainbow_step_changed(VariableItem* item) { rgb_backlight_settings_save(app->notification->rgb_srv->settings); } -// Set rgb_backlight colors static and custom -static void color_changed(VariableItem* item) { +static void vd1_color_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -370,72 +304,26 @@ static void color_changed(VariableItem* item) { rgb_backlight_settings_save(app->notification->rgb_srv->settings); } -static void color_set_custom_red(VariableItem* item) { +static void vd2_color_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - // Update all current colors with selected customs and save changed custom color to settings - app->notification->rgb_srv->current_red = index; - app->notification->rgb_srv->current_green = app->notification->rgb_srv->settings->custom_green; - app->notification->rgb_srv->current_blue = app->notification->rgb_srv->settings->custom_blue; - - app->notification->rgb_srv->settings->custom_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)); + 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_green(VariableItem* item) { + +static void vd3_color_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - // Update all current colors with selected customs and save changed custom color to settings - app->notification->rgb_srv->current_red = app->notification->rgb_srv->settings->custom_red; - app->notification->rgb_srv->current_green = index; - app->notification->rgb_srv->current_blue = app->notification->rgb_srv->settings->custom_blue; - - app->notification->rgb_srv->settings->custom_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); - - // Update all current colors with selected customs and save changed custom color to settings - app->notification->rgb_srv->current_red = app->notification->rgb_srv->settings->custom_red; - app->notification->rgb_srv->current_green = app->notification->rgb_srv->settings->custom_green; - app->notification->rgb_srv->current_blue = index; - - app->notification->rgb_srv->settings->custom_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)); + 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); } @@ -547,106 +435,63 @@ static NotificationAppSettings* alloc_settings(void) { } //--- 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 + // set callback for exit from rgb_settings_menu view_set_previous_callback(view_rgb, notification_app_rgb_settings_exit); // // Show rgb_backlight_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_BACKLIGHT_INSTALLED_COUNT, - // rgb_backlight_installed_changed, - // app); - // value_index = value_index_bool( - // app->notification->rgb_srv->settings->rgb_backlight_installed, - // rgb_backlight_installed_value, - // RGB_BACKLIGHT_INSTALLED_COUNT); - // variable_item_set_current_value_index(item, value_index); - // variable_item_set_current_value_text(item, rgb_backlight_installed_text[value_index]); - // } - - // Show rgb_backlight_mode_swith only in Debug mode or when rgb_mode is not OFF. - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) || - (app->notification->rgb_srv->settings->rgb_backlight_mode > 0)) { - item = variable_item_list_add( - app->variable_item_list_rgb, - "RGB MODE", - RGB_BACKLIGHT_MODE_COUNT, - rgb_backlight_mode_changed, - app); - value_index = value_index_uint32( - app->notification->rgb_srv->settings->rgb_backlight_mode, - rgb_backlight_mode_value, - RGB_BACKLIGHT_MODE_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, rgb_backlight_mode_text[value_index]); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + item = variable_item_list_add( + app->variable_item_list_rgb, + "RGB backlight installed", + RGB_BACKLIGHT_INSTALLED_COUNT, + rgb_backlight_installed_changed, + app); + value_index = value_index_bool( + app->notification->rgb_srv->settings->rgb_backlight_installed, + rgb_backlight_installed_value, + RGB_BACKLIGHT_INSTALLED_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_backlight_installed_text[value_index]); } - // Static Colors settings + // vd1 color item = variable_item_list_add( app->variable_item_list_rgb, - "LCD Color", + "VD1 Color", rgb_backlight_get_color_count(), - color_changed, + vd1_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_backlight_installed == 0), - "RGB MOD \nOFF!"); - temp_item = item; - - // Custom Color - REFACTOR THIS + // vd2 color 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; + app->variable_item_list_rgb, + "VD2 Color", + rgb_backlight_get_color_count(), + vd2_color_changed, + app); + value_index = app->notification->rgb_srv->settings->static_color_index; 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_backlight_installed == 0), - "RGB MOD \nOFF!"); - + variable_item_set_current_value_text(item, rgb_backlight_get_color_text(value_index)); + + // vd 3 color 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; + app->variable_item_list_rgb, + "VD3 Color", + rgb_backlight_get_color_count(), + vd3_color_changed, + app); + value_index = app->notification->rgb_srv->settings->static_color_index; 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_backlight_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_backlight_installed == 0), - "RGB MOD \nOFF!"); - - // Rainbow (based on Willy-JL idea) settings + variable_item_set_current_value_text(item, rgb_backlight_get_color_text(value_index)); + + // Rainbow mode item = variable_item_list_add( app->variable_item_list_rgb, "Rainbow mode", From a4d0c467f91e8e2bdbc3278ef6f8997bbe224a46 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Tue, 18 Mar 2025 18:41:50 +0700 Subject: [PATCH 030/125] End of static colors settings, next rainbow --- .../services/rgb_backlight/rgb_backlight.c | 173 +++++++----------- .../services/rgb_backlight/rgb_backlight.h | 18 +- .../rgb_backlight/rgb_backlight_settings.c | 21 +-- .../rgb_backlight/rgb_backlight_settings.h | 6 +- .../notification_settings_app.c | 149 +++++++++------ targets/f7/api_symbols.csv | 5 +- 6 files changed, 180 insertions(+), 192 deletions(-) diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index f3d3cfb35..323cc5d48 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -28,6 +28,20 @@ #define TAG "RGB_BACKLIGHT_SRV" +typedef struct { + char* name; + uint8_t red; + uint8_t green; + uint8_t blue; +} RGBBacklightColor; + +//use one type RGBBacklightColor for current_leds_settings and for static colors definition +static RGBBacklightColor current_led [] = { + {"LED0",255,60,0}, + {"LED1",255,60,0}, + {"LED2",255,60,0}, +}; + static const RGBBacklightColor colors[] = { {"Orange", 255, 60, 0}, {"Yellow", 255, 144, 0}, @@ -42,7 +56,7 @@ static const RGBBacklightColor colors[] = { {"Pink", 255, 0, 127}, {"Red", 255, 0, 0}, {"White", 254, 210, 200}, - {"White1", 255, 255, 255}, + {"OFF", 0, 0, 0}, }; uint8_t rgb_backlight_get_color_count(void) { @@ -54,47 +68,43 @@ const char* rgb_backlight_get_color_text(uint8_t index) { } // use RECORD for acces to rgb service instance and update current colors by static -void rgb_backlight_set_static_color(uint8_t index, uint8_t vd) { - RGBBacklightApp* app = furi_record_open(RECORD_RGB_BACKLIGHT); +void rgb_backlight_set_led_static_color(uint8_t led, uint8_t index) { + // RGBBacklightApp* app = furi_record_open(RECORD_RGB_BACKLIGHT); + // float brightness = app->settings->brightness; - if(vd < SK6805_get_led_count()) { + if(led < SK6805_get_led_count()) { uint8_t r = colors[index].red; uint8_t g = colors[index].green; uint8_t b = colors[index].blue; - SK6805_set_led_color(vd, r, g, b); - SK6805_update(); + + current_led[led].red = r; + current_led[led].green =g; + current_led[led].blue = b; + + SK6805_set_led_color(led, r, g, b); } - //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); + // 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); -} +// 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); - if(app->settings->rgb_backlight_mode > 0) { + + if(app->settings->rgb_backlight_installed) { 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); + uint8_t r = current_led[i].red * (brightness * 1.0f); + uint8_t g = current_led[i].green * (brightness * 1.0f); + uint8_t b = current_led[i].blue * (brightness * 1.0f); SK6805_set_led_color(i, r, g, b); } SK6805_update(); @@ -126,59 +136,14 @@ 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; + if (app->settings->rgb_backlight_installed) { + switch(app->settings->rainbow_mode) { + case 1: + break; + case 2: + break; + default: + break; } rgb_backlight_update(app->settings->brightness); } @@ -186,6 +151,7 @@ static void rainbow_timer_callback(void* context) { // if rainbow_mode is ..... do another effect // if(app->settings.rainbow_mode == ...) { // } + } int32_t rgb_backlight_srv(void* p) { @@ -194,7 +160,7 @@ int32_t rgb_backlight_srv(void* 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)); - + //define rainbow_timer and they callback app->rainbow_timer = furi_timer_alloc(rainbow_timer_callback, FuriTimerTypePeriodic, app); @@ -202,40 +168,33 @@ int32_t rgb_backlight_srv(void* p) { app->settings = malloc(sizeof(RGBBacklightSettings)); rgb_backlight_settings_load(app->settings); - // Init app variables - app->rainbow_stage = 1; - furi_record_create(RECORD_RGB_BACKLIGHT, app); - // if rgb mod installed - start rainbow or set static color from settings (default index = 0) - // - // TODO запуск сохраненного режима - if(app->settings->rgb_backlight_mode > 0) { - // 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 mode = 0 (rgb_backlight not installed) then set default static orange color (index=0) and light on default color - } else { - rgb_backlight_set_static_color(0); - for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { - uint8_t r = app->current_red * 1.0f; - uint8_t g = app->current_green * 1.0f; - uint8_t b = app->current_blue * 1.0f; - SK6805_set_led_color(i, r, g, b); + //if rgb_backlight_installed then start rainbow or set leds colors from saved settings (default index = 0) + if(app->settings->rgb_backlight_installed) { + if(app->settings->rainbow_mode > 0) { + // rainbow_timer_starter(app); + } else { + rgb_backlight_set_led_static_color (2,app->settings->led_2_color_index); + rgb_backlight_set_led_static_color (1,app->settings->led_1_color_index); + rgb_backlight_set_led_static_color (0,app->settings->led_0_color_index); + rgb_backlight_update (app->settings->brightness); } + // if rgb_backlight not installed then set default static orange color(index=0) to all leds (0-2) and force light on + } else { + rgb_backlight_set_led_static_color (2,0); + rgb_backlight_set_led_static_color (1,0); + rgb_backlight_set_led_static_color (0,0); SK6805_update(); } while(1) { // place for message queue and other future options - furi_delay_ms(5000); - if(app->settings->rgb_backlight_mode > 0) { - FURI_LOG_D(TAG, "Mod is enabled - serivce is running"); + furi_delay_ms (5000); + if(app->settings->rgb_backlight_installed) { + FURI_LOG_D(TAG, "RGB backlight enabled - serivce is running"); } else { - FURI_LOG_D(TAG, "Mod is DISABLED - serivce is running"); + FURI_LOG_D(TAG, "RGB backlight DISABLED - serivce is running"); } } return 0; diff --git a/applications/services/rgb_backlight/rgb_backlight.h b/applications/services/rgb_backlight/rgb_backlight.h index fd683bf16..0661886c5 100644 --- a/applications/services/rgb_backlight/rgb_backlight.h +++ b/applications/services/rgb_backlight/rgb_backlight.h @@ -26,20 +26,12 @@ 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; + // int16_t current_red; + // int16_t current_green; + // int16_t current_blue; RGBBacklightSettings* settings; @@ -48,8 +40,8 @@ typedef struct { #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 rgb_backlight_set_custom_color(uint8_t red, uint8_t green, uint8_t blue); +void rgb_backlight_set_led_static_color(uint8_t led, uint8_t index); void rainbow_timer_stop(RGBBacklightApp* app); void rainbow_timer_start(RGBBacklightApp* app); void rainbow_timer_starter(RGBBacklightApp* app); diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.c b/applications/services/rgb_backlight/rgb_backlight_settings.c index e2a2e5df7..4ca7140fd 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.c +++ b/applications/services/rgb_backlight/rgb_backlight_settings.c @@ -16,20 +16,14 @@ typedef struct { //Common settings uint8_t version; - bool rgb_backlight_installed; + uint8_t rgb_backlight_installed; float brightness; - - //static and custom colors mode settings - uint8_t static_color_index; - uint8_t custom_red; - uint8_t custom_green; - uint8_t custom_blue; - + // static gradient mode settings - uint8_t static_vd1_index; - uint8_t static_vd2_index; - uint8_t static_vd3_index; - + uint8_t led_2_color_index; + uint8_t led_1_color_index; + uint8_t led_0_color_index; + // rainbow mode setings uint32_t rainbow_mode; uint32_t rainbow_speed_ms; @@ -88,9 +82,6 @@ void rgb_backlight_settings_load(RGBBacklightSettings* settings) { settings->brightness = 1.0f; settings->rainbow_speed_ms = 100; settings->rainbow_step = 1; - settings->custom_red=255; - settings->custom_green = 255; - settings->custom_blue=255; rgb_backlight_settings_save(settings); } } diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.h b/applications/services/rgb_backlight/rgb_backlight_settings.h index 694161c2b..fe504879f 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.h +++ b/applications/services/rgb_backlight/rgb_backlight_settings.h @@ -10,9 +10,9 @@ typedef struct { float brightness; // static gradient mode settings - uint8_t static_vd1_index; - uint8_t static_vd2_index; - uint8_t static_vd3_index; + uint8_t led_2_color_index; + uint8_t led_1_color_index; + uint8_t led_0_color_index; // rainbow mode setings uint32_t rainbow_mode; diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 1a738b492..75f462ce4 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -16,7 +16,7 @@ typedef struct { VariableItemList* variable_item_list_rgb; } NotificationAppSettings; -static VariableItem* temp_item; +//static VariableItem* temp_item; static const NotificationSequence sequence_note_c = { &message_note_c5, @@ -236,12 +236,33 @@ static void rgb_backlight_installed_changed(VariableItem* item) { variable_item_set_current_value_text(item, rgb_backlight_installed_text[index]); app->notification->rgb_srv->settings->rgb_backlight_installed = rgb_backlight_installed_value[index]; rgb_backlight_settings_save(app->notification->rgb_srv->settings); + + // In case of user playing with rgb_backlight_installed swith: + // if user swith_off rgb_backlight_installed then force set default orange color + if (index == 0) { + rgb_backlight_set_led_static_color (2,0); + rgb_backlight_set_led_static_color (1,0); + rgb_backlight_set_led_static_color (0,0); + SK6805_update(); + // if user swith_on rgb_backlight_installed then start rainbow if its ON or set saved static colors + } else { + + if (app->notification->rgb_srv->settings->rainbow_mode >0) { + rainbow_timer_starter (app->notification->rgb_srv); + } else { + rgb_backlight_set_led_static_color (2,app->notification->rgb_srv->settings->led_2_color_index); + rgb_backlight_set_led_static_color (1,app->notification->rgb_srv->settings->led_1_color_index); + rgb_backlight_set_led_static_color (0,app->notification->rgb_srv->settings->led_0_color_index); + rgb_backlight_update (app->notification->settings.display_brightness); + } + } + // Lock/Unlock all rgb settings depent from rgb_backlight_installed switch int slide = 0; if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { slide = 1; } - for(int i = slide; i < (slide + 7); i++) { + for(int i = slide; i < (slide + 6); 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\nOFF!"); @@ -251,6 +272,54 @@ static void rgb_backlight_installed_changed(VariableItem* item) { } } +static void led_2_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->led_2_color_index = index; + + rgb_backlight_set_led_static_color(2,index); + rgb_backlight_update(app->notification->rgb_srv->settings->brightness); + + // dont update display color if rainbow working + if (!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { + rgb_backlight_settings_save(app->notification->rgb_srv->settings); + } +} + +static void led_1_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->led_1_color_index = index; + + rgb_backlight_set_led_static_color(1,index); + rgb_backlight_settings_save(app->notification->rgb_srv->settings); + + // dont update display color if rainbow working + if (!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { + rgb_backlight_settings_save(app->notification->rgb_srv->settings); + } +} + +static void led_0_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->led_0_color_index = index; + + rgb_backlight_set_led_static_color(0,index); + rgb_backlight_settings_save(app->notification->rgb_srv->settings); + + // dont update display color if rainbow working + if (!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { + rgb_backlight_settings_save(app->notification->rgb_srv->settings); + } +} + static void rgb_backlight_rainbow_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -263,7 +332,9 @@ static void rgb_backlight_rainbow_changed(VariableItem* item) { // 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_set_led_static_color (2,app->notification->rgb_srv->settings->led_2_color_index); + rgb_backlight_set_led_static_color (1,app->notification->rgb_srv->settings->led_1_color_index); + rgb_backlight_set_led_static_color (0,app->notification->rgb_srv->settings->led_0_color_index); rgb_backlight_update(app->notification->rgb_srv->settings->brightness); } } @@ -292,42 +363,6 @@ static void rgb_backlight_rainbow_step_changed(VariableItem* item) { } -static void vd1_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 vd2_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 vd3_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); -} - // open rgb_settings_view if user press OK on first (index=0) menu string and (debug mode or rgb_backlight_installed is true) void variable_item_list_enter_callback(void* context, uint32_t index) { UNUSED(context); @@ -458,38 +493,50 @@ static NotificationAppSettings* alloc_settings(void) { variable_item_set_current_value_text(item, rgb_backlight_installed_text[value_index]); } - // vd1 color + // led_1 color item = variable_item_list_add( app->variable_item_list_rgb, - "VD1 Color", + "LED 1 Color", rgb_backlight_get_color_count(), - vd1_color_changed, + led_2_color_changed, app); - value_index = app->notification->rgb_srv->settings->static_color_index; + value_index = app->notification->rgb_srv->settings->led_2_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->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); - // vd2 color + // led_2 color item = variable_item_list_add( app->variable_item_list_rgb, - "VD2 Color", + "LED 2 Color", rgb_backlight_get_color_count(), - vd2_color_changed, + led_1_color_changed, app); - value_index = app->notification->rgb_srv->settings->static_color_index; + value_index = app->notification->rgb_srv->settings->led_1_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->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); - // vd 3 color + // led 3 color item = variable_item_list_add( app->variable_item_list_rgb, - "VD3 Color", + "LED 3 Color", rgb_backlight_get_color_count(), - vd3_color_changed, + led_0_color_changed, app); - value_index = app->notification->rgb_srv->settings->static_color_index; + value_index = app->notification->rgb_srv->settings->led_0_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->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); // Rainbow mode item = variable_item_list_add( diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index ce3992704..9cc8e15f6 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,83.1,, +Version,+,86.0,, 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,, @@ -3148,8 +3148,7 @@ 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_set_led_static_color,void,"uint8_t, uint8_t" Function,+,rgb_backlight_settings_load,void,RGBBacklightSettings* Function,+,rgb_backlight_settings_save,void,const RGBBacklightSettings* Function,+,rgb_backlight_update,void,float From a629118aaa7ee78220ccde21107dedc3f2db9a52 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Wed, 19 Mar 2025 00:46:00 +0700 Subject: [PATCH 031/125] Rainbow mode in progress --- .../services/rgb_backlight/rgb_backlight.c | 87 ++- .../services/rgb_backlight/rgb_backlight.h | 8 +- .../rgb_backlight/rgb_backlight_settings.c | 6 +- .../rgb_backlight/rgb_backlight_settings.h | 1 + .../notification_settings_app.c | 495 +++++++++--------- 5 files changed, 348 insertions(+), 249 deletions(-) diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index 323cc5d48..6f9940ad0 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -23,6 +23,7 @@ #include #include #include "rgb_backlight.h" +#include #define COLOR_COUNT (sizeof(colors) / sizeof(RGBBacklightColor)) @@ -87,14 +88,22 @@ void rgb_backlight_set_led_static_color(uint8_t led, uint8_t index) { // 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 and update current colors by custom value +void rgb_backlight_set_led_custom_color(uint8_t led, uint8_t red, uint8_t green, uint8_t blue) { + // RGBBacklightApp* app = furi_record_open(RECORD_RGB_BACKLIGHT); + // float brightness = app->settings->brightness; + + if(led < SK6805_get_led_count()) { + + current_led[led].red = red; + current_led[led].green = green; + current_led[led].blue = blue; + + SK6805_set_led_color(led, red, green, 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) { @@ -132,19 +141,77 @@ void rainbow_timer_starter(RGBBacklightApp* app) { } } } + +// HSV to RGB based on +// https://www.radiokot.ru/forum/viewtopic.php?p=3000181&ysclid=m88wvoz34w244644702 +// https://radiolaba.ru/microcotrollers/tsvetnaya-lampa.html#comment-1790 +// https://alexgyver.ru/lessons/arduino-rgb/?ysclid=m88voflppa24464916 +void hsv_to_rgb(uint8_t red, uint8_t green, uint8_t blue, uint16_t hue ,uint8_t sat ,uint8_t val) { + float r = 1.0f; + float g = 1.0f; + float b = 1.0f; + + float H = hue / 255.0f; + float S = sat / 255.0f; + float V = val / 255.0f; + + uint8_t i = trunc(H * 6); + float f = H * 6 - i; + float p = V * (1 - S); + float q = V * (1 - f * S); + float t = V * (1 - (1 - f) * S); + + switch(i) { + case 0: + r = V, g = t, b = p; + break; + case 1: + r = q, g = V, b = p; + break; + case 2: + r = p, g = V, b = t; + break; + case 3: + r = p, g = q, b = V; + break; + case 4: + r = t, g = p, b = V; + break; + case 5: + r = V, g = p, b = q; + break; + } + red = r * 255; + green = g * 255; + blue = b * 255; +} + + static void rainbow_timer_callback(void* context) { furi_assert(context); RGBBacklightApp* app = context; + uint8_t r = 0; + uint8_t g = 0; + uint8_t b = 0; - if (app->settings->rgb_backlight_installed) { + if(app->settings->rgb_backlight_installed) { switch(app->settings->rainbow_mode) { case 1: + for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { + hsv_to_rgb(r,g,b,app->rainbow_hue, app->settings->rainbow_saturation,app->settings->brightness*255); + FURI_LOG_D( + TAG, "rgb %d,%d,%d", r, g, b); + //rgb_backlight_set_led_custom_color (i,*r,*g,*b); + //SK6805_update(); + } + break; case 2: break; default: break; } + app->rainbow_hue++; rgb_backlight_update(app->settings->brightness); } @@ -168,6 +235,8 @@ int32_t rgb_backlight_srv(void* p) { app->settings = malloc(sizeof(RGBBacklightSettings)); rgb_backlight_settings_load(app->settings); + app->rainbow_hue = 1; + furi_record_create(RECORD_RGB_BACKLIGHT, app); //if rgb_backlight_installed then start rainbow or set leds colors from saved settings (default index = 0) diff --git a/applications/services/rgb_backlight/rgb_backlight.h b/applications/services/rgb_backlight/rgb_backlight.h index 0661886c5..e8b78f461 100644 --- a/applications/services/rgb_backlight/rgb_backlight.h +++ b/applications/services/rgb_backlight/rgb_backlight.h @@ -28,10 +28,10 @@ extern "C" { typedef struct { FuriTimer* rainbow_timer; - - // int16_t current_red; - // int16_t current_green; - // int16_t current_blue; + uint8_t rainbow_hue; + uint8_t rainbow_red; + uint8_t rainbow_green; + uint8_t rainbow_blue; RGBBacklightSettings* settings; diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.c b/applications/services/rgb_backlight/rgb_backlight_settings.c index 4ca7140fd..0b0388cae 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.c +++ b/applications/services/rgb_backlight/rgb_backlight_settings.c @@ -18,16 +18,17 @@ typedef struct { uint8_t version; uint8_t rgb_backlight_installed; float brightness; - + // static gradient mode settings uint8_t led_2_color_index; uint8_t led_1_color_index; uint8_t led_0_color_index; - + // rainbow mode setings uint32_t rainbow_mode; uint32_t rainbow_speed_ms; uint16_t rainbow_step; + uint8_t rainbow_saturation; } RGBBacklightSettingsPrevious; void rgb_backlight_settings_load(RGBBacklightSettings* settings) { @@ -82,6 +83,7 @@ void rgb_backlight_settings_load(RGBBacklightSettings* settings) { settings->brightness = 1.0f; settings->rainbow_speed_ms = 100; settings->rainbow_step = 1; + settings->rainbow_saturation = 255; rgb_backlight_settings_save(settings); } } diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.h b/applications/services/rgb_backlight/rgb_backlight_settings.h index fe504879f..7c6e08c95 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.h +++ b/applications/services/rgb_backlight/rgb_backlight_settings.h @@ -18,6 +18,7 @@ typedef struct { uint32_t rainbow_mode; uint32_t rainbow_speed_ms; uint16_t rainbow_step; + uint8_t rainbow_saturation; } RGBBacklightSettings; diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 75f462ce4..7e8536ee7 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -262,7 +262,7 @@ static void rgb_backlight_installed_changed(VariableItem* item) { if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { slide = 1; } - for(int i = slide; i < (slide + 6); i++) { + 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\nOFF!"); @@ -362,267 +362,294 @@ static void rgb_backlight_rainbow_step_changed(VariableItem* item) { rgb_backlight_settings_save(app->notification->rgb_srv->settings); } +static void rgb_backlight_rainbow_saturation_changed (VariableItem* item) { + NotificationAppSettings* app = variable_item_get_context(item); -// open rgb_settings_view if user press OK on first (index=0) menu string and (debug mode or rgb_backlight_installed is true) -void variable_item_list_enter_callback(void* context, uint32_t index) { - UNUSED(context); - NotificationAppSettings* app = context; + //saturation must be 1..255, so (0..254)+1 + uint8_t index = variable_item_get_current_value_index(item)+1; + char valtext[4] = {}; + snprintf(valtext, sizeof(valtext), "%d", index); + variable_item_set_current_value_text(item, valtext); + app->notification->rgb_srv->settings->rainbow_saturation = index; + 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_backlight_installed 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_backlight_installed) || - (furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug))) && - (index == 0)) { - view_dispatcher_switch_to_view(app->view_dispatcher, RGBViewId); + if(((app->notification->rgb_srv->settings->rgb_backlight_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; -} - -static NotificationAppSettings* alloc_settings(void) { - NotificationAppSettings* app = malloc(sizeof(NotificationAppSettings)); - app->notification = furi_record_open(RECORD_NOTIFICATION); - app->gui = furi_record_open(RECORD_GUI); - - app->variable_item_list = variable_item_list_alloc(); - View* view = variable_item_list_get_view(app->variable_item_list); - - 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_backlight_installed is active - if((app->notification->rgb_srv->settings->rgb_backlight_installed) || - (furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug))) { - item = variable_item_list_add(app->variable_item_list, "RGB settings", 0, NULL, app); + // 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 --- - item = variable_item_list_add( - app->variable_item_list, "LCD Contrast", CONTRAST_COUNT, contrast_changed, app); - value_index = - value_index_int32(app->notification->settings.contrast, contrast_value, CONTRAST_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, contrast_text[value_index]); + static uint32_t notification_app_settings_exit(void* context) { + UNUSED(context); + return VIEW_NONE; + } - item = variable_item_list_add( - app->variable_item_list, "LCD Backlight", BACKLIGHT_COUNT, backlight_changed, app); - value_index = value_index_float( - app->notification->settings.display_brightness, backlight_value, BACKLIGHT_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, backlight_text[value_index]); + static NotificationAppSettings* alloc_settings(void) { + NotificationAppSettings* app = malloc(sizeof(NotificationAppSettings)); + app->notification = furi_record_open(RECORD_NOTIFICATION); + app->gui = furi_record_open(RECORD_GUI); - item = variable_item_list_add( - app->variable_item_list, "Backlight Time", DELAY_COUNT, screen_changed, app); - value_index = value_index_uint32( - app->notification->settings.display_off_delay_ms, delay_value, DELAY_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, delay_text[value_index]); + app->variable_item_list = variable_item_list_alloc(); + View* view = variable_item_list_get_view(app->variable_item_list); - item = variable_item_list_add( - app->variable_item_list, "LED Brightness", BACKLIGHT_COUNT, led_changed, app); - value_index = value_index_float( - app->notification->settings.led_brightness, backlight_value, BACKLIGHT_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, backlight_text[value_index]); + 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_backlight_installed is active + if((app->notification->rgb_srv->settings->rgb_backlight_installed) || + (furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug))) { + item = variable_item_list_add(app->variable_item_list, "RGB settings", 0, NULL, app); + } + //--- RGB BACKLIGHT END --- - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { - item = variable_item_list_add(app->variable_item_list, "Volume", 1, NULL, app); - value_index = 0; - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, "Stealth"); - } else { item = variable_item_list_add( - app->variable_item_list, "Volume", VOLUME_COUNT, volume_changed, app); + app->variable_item_list, "LCD Contrast", CONTRAST_COUNT, contrast_changed, app); + value_index = value_index_int32( + app->notification->settings.contrast, contrast_value, CONTRAST_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, contrast_text[value_index]); + + item = variable_item_list_add( + app->variable_item_list, "LCD Backlight", BACKLIGHT_COUNT, backlight_changed, app); value_index = value_index_float( - app->notification->settings.speaker_volume, volume_value, VOLUME_COUNT); + app->notification->settings.display_brightness, backlight_value, BACKLIGHT_COUNT); variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, volume_text[value_index]); - } + variable_item_set_current_value_text(item, backlight_text[value_index]); - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { - item = variable_item_list_add(app->variable_item_list, "Vibro", 1, NULL, app); - value_index = 0; - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, "Stealth"); - } else { item = variable_item_list_add( - app->variable_item_list, "Vibro", VIBRO_COUNT, vibro_changed, app); - value_index = - value_index_bool(app->notification->settings.vibro_on, vibro_value, VIBRO_COUNT); + app->variable_item_list, "Backlight Time", DELAY_COUNT, screen_changed, app); + value_index = value_index_uint32( + app->notification->settings.display_off_delay_ms, delay_value, DELAY_COUNT); variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, vibro_text[value_index]); - } + variable_item_set_current_value_text(item, delay_text[value_index]); - //--- RGB BACKLIGHT --- + item = variable_item_list_add( + app->variable_item_list, "LED Brightness", BACKLIGHT_COUNT, led_changed, app); + value_index = value_index_float( + app->notification->settings.led_brightness, backlight_value, BACKLIGHT_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, backlight_text[value_index]); - app->variable_item_list_rgb = variable_item_list_alloc(); - View* view_rgb = variable_item_list_get_view(app->variable_item_list_rgb); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { + item = variable_item_list_add(app->variable_item_list, "Volume", 1, NULL, app); + value_index = 0; + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, "Stealth"); + } else { + item = variable_item_list_add( + app->variable_item_list, "Volume", VOLUME_COUNT, volume_changed, app); + value_index = value_index_float( + app->notification->settings.speaker_volume, volume_value, VOLUME_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, volume_text[value_index]); + } - // set callback for exit from rgb_settings_menu - view_set_previous_callback(view_rgb, notification_app_rgb_settings_exit); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { + item = variable_item_list_add(app->variable_item_list, "Vibro", 1, NULL, app); + value_index = 0; + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, "Stealth"); + } else { + item = variable_item_list_add( + app->variable_item_list, "Vibro", VIBRO_COUNT, vibro_changed, app); + value_index = + value_index_bool(app->notification->settings.vibro_on, vibro_value, VIBRO_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, vibro_text[value_index]); + } - // // Show rgb_backlight_Installed_Swith only in Debug mode - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + //--- 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 exit from rgb_settings_menu + view_set_previous_callback(view_rgb, notification_app_rgb_settings_exit); + + // // Show rgb_backlight_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 backlight installed", + RGB_BACKLIGHT_INSTALLED_COUNT, + rgb_backlight_installed_changed, + app); + value_index = value_index_bool( + app->notification->rgb_srv->settings->rgb_backlight_installed, + rgb_backlight_installed_value, + RGB_BACKLIGHT_INSTALLED_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_backlight_installed_text[value_index]); + } + + // led_1 color item = variable_item_list_add( app->variable_item_list_rgb, - "RGB backlight installed", - RGB_BACKLIGHT_INSTALLED_COUNT, - rgb_backlight_installed_changed, + "LED 1 Color", + rgb_backlight_get_color_count(), + led_2_color_changed, app); - value_index = value_index_bool( - app->notification->rgb_srv->settings->rgb_backlight_installed, - rgb_backlight_installed_value, - RGB_BACKLIGHT_INSTALLED_COUNT); + value_index = app->notification->rgb_srv->settings->led_2_color_index; variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, rgb_backlight_installed_text[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->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); + + // led_2 color + item = variable_item_list_add( + app->variable_item_list_rgb, + "LED 2 Color", + rgb_backlight_get_color_count(), + led_1_color_changed, + app); + value_index = app->notification->rgb_srv->settings->led_1_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->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); + + // led 3 color + item = variable_item_list_add( + app->variable_item_list_rgb, + "LED 3 Color", + rgb_backlight_get_color_count(), + led_0_color_changed, + app); + value_index = app->notification->rgb_srv->settings->led_0_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->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); + + // Rainbow mode + item = variable_item_list_add( + app->variable_item_list_rgb, + "Rainbow mode", + RGB_BACKLIGHT_RAINBOW_MODE_COUNT, + rgb_backlight_rainbow_changed, + app); + value_index = value_index_uint32( + app->notification->rgb_srv->settings->rainbow_mode, + rgb_backlight_rainbow_mode_value, + RGB_BACKLIGHT_RAINBOW_MODE_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_backlight_rainbow_mode_text[value_index]); + variable_item_set_locked( + item, + (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); + + item = variable_item_list_add( + app->variable_item_list_rgb, + "Rainbow speed", + RGB_BACKLIGHT_RAINBOW_SPEED_COUNT, + rgb_backlight_rainbow_speed_changed, + app); + value_index = value_index_uint32( + app->notification->rgb_srv->settings->rainbow_speed_ms, + rgb_backlight_rainbow_speed_value, + RGB_BACKLIGHT_RAINBOW_SPEED_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_backlight_rainbow_speed_text[value_index]); + variable_item_set_locked( + item, + (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); + + item = variable_item_list_add( + app->variable_item_list_rgb, + "Rainbow step", + RGB_BACKLIGHT_RAINBOW_STEP_COUNT, + rgb_backlight_rainbow_step_changed, + app); + value_index = value_index_uint32( + app->notification->rgb_srv->settings->rainbow_step, + rgb_backlight_rainbow_step_value, + RGB_BACKLIGHT_RAINBOW_SPEED_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_backlight_rainbow_step_text[value_index]); + variable_item_set_locked( + item, + (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); + + item = variable_item_list_add( + app->variable_item_list_rgb, + "Saturation", + 255, + rgb_backlight_rainbow_saturation_changed, + app); + value_index = app->notification->rgb_srv->settings->rainbow_saturation; + 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->rgb_backlight_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, MainViewId, view); + view_dispatcher_add_view(app->view_dispatcher, RGBViewId, view_rgb); + view_dispatcher_switch_to_view(app->view_dispatcher, MainViewId); + return app; } - - // led_1 color - item = variable_item_list_add( - app->variable_item_list_rgb, - "LED 1 Color", - rgb_backlight_get_color_count(), - led_2_color_changed, - app); - value_index = app->notification->rgb_srv->settings->led_2_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->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); - // led_2 color - item = variable_item_list_add( - app->variable_item_list_rgb, - "LED 2 Color", - rgb_backlight_get_color_count(), - led_1_color_changed, - app); - value_index = app->notification->rgb_srv->settings->led_1_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->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); - - // led 3 color - item = variable_item_list_add( - app->variable_item_list_rgb, - "LED 3 Color", - rgb_backlight_get_color_count(), - led_0_color_changed, - app); - value_index = app->notification->rgb_srv->settings->led_0_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->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); - - // Rainbow mode - item = variable_item_list_add( - app->variable_item_list_rgb, - "Rainbow mode", - RGB_BACKLIGHT_RAINBOW_MODE_COUNT, - rgb_backlight_rainbow_changed, - app); - value_index = value_index_uint32( - app->notification->rgb_srv->settings->rainbow_mode, - rgb_backlight_rainbow_mode_value, - RGB_BACKLIGHT_RAINBOW_MODE_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, rgb_backlight_rainbow_mode_text[value_index]); - variable_item_set_locked( - item, - (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); + static void free_settings(NotificationAppSettings * app) { + 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); - item = variable_item_list_add( - app->variable_item_list_rgb, - "Rainbow speed", - RGB_BACKLIGHT_RAINBOW_SPEED_COUNT, - rgb_backlight_rainbow_speed_changed, - app); - value_index = value_index_uint32( - app->notification->rgb_srv->settings->rainbow_speed_ms, - rgb_backlight_rainbow_speed_value, - RGB_BACKLIGHT_RAINBOW_SPEED_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, rgb_backlight_rainbow_speed_text[value_index]); - variable_item_set_locked( - item, - (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); + furi_record_close(RECORD_GUI); + furi_record_close(RECORD_NOTIFICATION); + free(app); + } - item = variable_item_list_add( - app->variable_item_list_rgb, - "Rainbow step", - RGB_BACKLIGHT_RAINBOW_STEP_COUNT, - rgb_backlight_rainbow_step_changed, - app); - value_index = value_index_uint32( - app->notification->rgb_srv->settings->rainbow_step, - rgb_backlight_rainbow_step_value, - RGB_BACKLIGHT_RAINBOW_SPEED_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, rgb_backlight_rainbow_step_text[value_index]); - variable_item_set_locked( - item, - (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); + int32_t notification_settings_app(void* p) { + UNUSED(p); + NotificationAppSettings* app = alloc_settings(); + view_dispatcher_run(app->view_dispatcher); + notification_message_save_settings(app->notification); - //--- RGB BACKLIGHT END --- + // Automaticaly switch_off debug_mode when user exit from settings with enabled rgb_backlight_installed + // if(app->notification->settings.rgb_backlight_installed) { + // furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); + // } - app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); - 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, 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); - furi_record_close(RECORD_NOTIFICATION); - free(app); -} - -int32_t notification_settings_app(void* p) { - UNUSED(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_backlight_installed - // if(app->notification->settings.rgb_backlight_installed) { - // furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); - // } - - free_settings(app); - return 0; -} + free_settings(app); + return 0; + } From 5eb38b786b72d28ef6d5a3e68e1c979f8b06207e Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Wed, 19 Mar 2025 18:53:02 +0700 Subject: [PATCH 032/125] RGB BACKLIGHT refactoring finished. - rgb_backlight by @Quen0n - rgb_backlight_settings and effects (like rainbow) idea by @Willy-JL For access to rgb backlight settings enable Debug mode and go to Settings-LCD and Notification-RGB backlight --- .../services/rgb_backlight/rgb_backlight.c | 219 +++--- .../services/rgb_backlight/rgb_backlight.h | 3 +- .../rgb_backlight/rgb_backlight_settings.c | 2 + .../rgb_backlight/rgb_backlight_settings.h | 7 +- .../notification_settings_app.c | 661 ++++++++++-------- 5 files changed, 475 insertions(+), 417 deletions(-) diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index 6f9940ad0..8d05e68de 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -37,10 +37,10 @@ typedef struct { } RGBBacklightColor; //use one type RGBBacklightColor for current_leds_settings and for static colors definition -static RGBBacklightColor current_led [] = { - {"LED0",255,60,0}, - {"LED1",255,60,0}, - {"LED2",255,60,0}, +static RGBBacklightColor current_led[] = { + {"LED0", 255, 60, 0}, + {"LED1", 255, 60, 0}, + {"LED2", 255, 60, 0}, }; static const RGBBacklightColor colors[] = { @@ -70,45 +70,83 @@ const char* rgb_backlight_get_color_text(uint8_t index) { // use RECORD for acces to rgb service instance and update current colors by static void rgb_backlight_set_led_static_color(uint8_t led, uint8_t index) { - // RGBBacklightApp* app = furi_record_open(RECORD_RGB_BACKLIGHT); - // float brightness = app->settings->brightness; - if(led < SK6805_get_led_count()) { uint8_t r = colors[index].red; uint8_t g = colors[index].green; uint8_t b = colors[index].blue; - - current_led[led].red = r; - current_led[led].green =g; + + current_led[led].red = r; + current_led[led].green = g; current_led[led].blue = b; SK6805_set_led_color(led, r, g, b); } - - // furi_record_close(RECORD_RGB_BACKLIGHT); } -// use RECORD for acces to rgb service instance and update current colors by custom value -void rgb_backlight_set_led_custom_color(uint8_t led, uint8_t red, uint8_t green, uint8_t blue) { - // RGBBacklightApp* app = furi_record_open(RECORD_RGB_BACKLIGHT); - // float brightness = app->settings->brightness; +// --- NOT USED IN CURRENT RELEASE, FOR FUTURE USAGE--- +// Update current colors by custom rgb value +// void rgb_backlight_set_led_custom_color(uint8_t led, uint8_t red, uint8_t green, uint8_t blue) { +// if(led < SK6805_get_led_count()) { +// current_led[led].red = red; +// current_led[led].green = green; +// current_led[led].blue = blue; +// SK6805_set_led_color(led, red, green, blue); +// } +// } +// --- NOT USED IN CURRENT RELEASE, FOR FUTURE USAGE--- - if(led < SK6805_get_led_count()) { +// HSV to RGB based on +// https://www.radiokot.ru/forum/viewtopic.php?p=3000181&ysclid=m88wvoz34w244644702 +// https://radiolaba.ru/microcotrollers/tsvetnaya-lampa.html#comment-1790 +// https://alexgyver.ru/lessons/arduino-rgb/?ysclid=m88voflppa24464916 +// led number (0-2), hue (0..255), sat (0..255), val (0...1) +void rgb_backlight_set_led_custom_hsv_color(uint8_t led, uint16_t hue, uint8_t sat, float V) { + //init value + float r = 1.0f; + float g = 1.0f; + float b = 1.0f; - current_led[led].red = red; - current_led[led].green = green; - current_led[led].blue = blue; + //from (0..255) to (0..1) + float H = hue / 255.0f; + float S = sat / 255.0f; - SK6805_set_led_color(led, red, green, blue); + uint8_t i = trunc(H * 6); + float f = H * 6 - i; + float p = V * (1 - S); + float q = V * (1 - f * S); + float t = V * (1 - (1 - f) * S); + + switch(i) { + case 0: + r = V, g = t, b = p; + break; + case 1: + r = q, g = V, b = p; + break; + case 2: + r = p, g = V, b = t; + break; + case 3: + r = p, g = q, b = V; + break; + case 4: + r = t, g = p, b = V; + break; + case 5: + r = V, g = p, b = q; + break; } - // furi_record_close(RECORD_RGB_BACKLIGHT); + //from (0..1) to (0..255) + current_led[led].red = r * 255; + current_led[led].green = g * 255; + current_led[led].blue = b * 255; } -// use RECORD for acces to rgb service instance, use current_* colors and update backlight +// use RECORD for acces to rgb service instance, set current_* colors to led and update backlight void rgb_backlight_update(float brightness) { RGBBacklightApp* app = furi_record_open(RECORD_RGB_BACKLIGHT); - + if(app->settings->rgb_backlight_installed) { for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { uint8_t r = current_led[i].red * (brightness * 1.0f); @@ -142,83 +180,56 @@ void rainbow_timer_starter(RGBBacklightApp* app) { } } -// HSV to RGB based on -// https://www.radiokot.ru/forum/viewtopic.php?p=3000181&ysclid=m88wvoz34w244644702 -// https://radiolaba.ru/microcotrollers/tsvetnaya-lampa.html#comment-1790 -// https://alexgyver.ru/lessons/arduino-rgb/?ysclid=m88voflppa24464916 -void hsv_to_rgb(uint8_t red, uint8_t green, uint8_t blue, uint16_t hue ,uint8_t sat ,uint8_t val) { - float r = 1.0f; - float g = 1.0f; - float b = 1.0f; - - float H = hue / 255.0f; - float S = sat / 255.0f; - float V = val / 255.0f; - - uint8_t i = trunc(H * 6); - float f = H * 6 - i; - float p = V * (1 - S); - float q = V * (1 - f * S); - float t = V * (1 - (1 - f) * S); - - switch(i) { - case 0: - r = V, g = t, b = p; - break; - case 1: - r = q, g = V, b = p; - break; - case 2: - r = p, g = V, b = t; - break; - case 3: - r = p, g = q, b = V; - break; - case 4: - r = t, g = p, b = V; - break; - case 5: - r = V, g = p, b = q; - break; - } - red = r * 255; - green = g * 255; - blue = b * 255; -} - - static void rainbow_timer_callback(void* context) { furi_assert(context); RGBBacklightApp* app = context; - uint8_t r = 0; - uint8_t g = 0; - uint8_t b = 0; if(app->settings->rgb_backlight_installed) { - switch(app->settings->rainbow_mode) { - case 1: - for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { - hsv_to_rgb(r,g,b,app->rainbow_hue, app->settings->rainbow_saturation,app->settings->brightness*255); - FURI_LOG_D( - TAG, "rgb %d,%d,%d", r, g, b); - //rgb_backlight_set_led_custom_color (i,*r,*g,*b); - //SK6805_update(); - } - - break; - case 2: - break; - default: - break; + app->rainbow_hue += app->settings->rainbow_step; + if(app->rainbow_hue > 254) { + app->rainbow_hue = 0; } - app->rainbow_hue++; + + uint8_t wide = app->settings->rainbow_wide; + + switch(app->settings->rainbow_mode) { + //rainbow mode + case 1: + for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { + rgb_backlight_set_led_custom_hsv_color( + i, + app->rainbow_hue, + app->settings->rainbow_saturation, + app->settings->brightness); + } + break; + + //wave mode + case 2: + uint16_t j = app->rainbow_hue + wide; + uint16_t k = app->rainbow_hue + wide * 2; + + if(app->rainbow_hue > (254 - wide)) { + j = j - 255; + } + if(app->rainbow_hue > (254 - wide * 2)) { + k = k - 255; + } + + rgb_backlight_set_led_custom_hsv_color( + 0, app->rainbow_hue, app->settings->rainbow_saturation, app->settings->brightness); + rgb_backlight_set_led_custom_hsv_color( + 1, j, app->settings->rainbow_saturation, app->settings->brightness); + rgb_backlight_set_led_custom_hsv_color( + 2, k, app->settings->rainbow_saturation, app->settings->brightness); + 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) { @@ -227,7 +238,7 @@ int32_t rgb_backlight_srv(void* 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)); - + //define rainbow_timer and they callback app->rainbow_timer = furi_timer_alloc(rainbow_timer_callback, FuriTimerTypePeriodic, app); @@ -242,24 +253,24 @@ int32_t rgb_backlight_srv(void* p) { //if rgb_backlight_installed then start rainbow or set leds colors from saved settings (default index = 0) if(app->settings->rgb_backlight_installed) { if(app->settings->rainbow_mode > 0) { - // rainbow_timer_starter(app); + rainbow_timer_starter(app); } else { - rgb_backlight_set_led_static_color (2,app->settings->led_2_color_index); - rgb_backlight_set_led_static_color (1,app->settings->led_1_color_index); - rgb_backlight_set_led_static_color (0,app->settings->led_0_color_index); - rgb_backlight_update (app->settings->brightness); + rgb_backlight_set_led_static_color(2, app->settings->led_2_color_index); + rgb_backlight_set_led_static_color(1, app->settings->led_1_color_index); + rgb_backlight_set_led_static_color(0, app->settings->led_0_color_index); + rgb_backlight_update(app->settings->brightness); } - // if rgb_backlight not installed then set default static orange color(index=0) to all leds (0-2) and force light on + // if rgb_backlight not installed then set default static orange color(index=0) to all leds (0-2) and force light on } else { - rgb_backlight_set_led_static_color (2,0); - rgb_backlight_set_led_static_color (1,0); - rgb_backlight_set_led_static_color (0,0); + rgb_backlight_set_led_static_color(2, 0); + rgb_backlight_set_led_static_color(1, 0); + rgb_backlight_set_led_static_color(0, 0); SK6805_update(); } while(1) { // place for message queue and other future options - furi_delay_ms (5000); + furi_delay_ms(5000); if(app->settings->rgb_backlight_installed) { FURI_LOG_D(TAG, "RGB backlight enabled - serivce is running"); } else { diff --git a/applications/services/rgb_backlight/rgb_backlight.h b/applications/services/rgb_backlight/rgb_backlight.h index e8b78f461..10aa9341f 100644 --- a/applications/services/rgb_backlight/rgb_backlight.h +++ b/applications/services/rgb_backlight/rgb_backlight.h @@ -28,7 +28,7 @@ extern "C" { typedef struct { FuriTimer* rainbow_timer; - uint8_t rainbow_hue; + uint16_t rainbow_hue; uint8_t rainbow_red; uint8_t rainbow_green; uint8_t rainbow_blue; @@ -40,6 +40,7 @@ typedef struct { #define RECORD_RGB_BACKLIGHT "rgb_backlight" void rgb_backlight_update(float brightness); +//not used now, for future use // void rgb_backlight_set_custom_color(uint8_t red, uint8_t green, uint8_t blue); void rgb_backlight_set_led_static_color(uint8_t led, uint8_t index); void rainbow_timer_stop(RGBBacklightApp* app); diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.c b/applications/services/rgb_backlight/rgb_backlight_settings.c index 0b0388cae..f612507e4 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.c +++ b/applications/services/rgb_backlight/rgb_backlight_settings.c @@ -29,6 +29,7 @@ typedef struct { uint32_t rainbow_speed_ms; uint16_t rainbow_step; uint8_t rainbow_saturation; + uint8_t rainbow_wide; } RGBBacklightSettingsPrevious; void rgb_backlight_settings_load(RGBBacklightSettings* settings) { @@ -84,6 +85,7 @@ void rgb_backlight_settings_load(RGBBacklightSettings* settings) { settings->rainbow_speed_ms = 100; settings->rainbow_step = 1; settings->rainbow_saturation = 255; + settings->rainbow_wide = 50; rgb_backlight_settings_save(settings); } } diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.h b/applications/services/rgb_backlight/rgb_backlight_settings.h index 7c6e08c95..3f3af005f 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.h +++ b/applications/services/rgb_backlight/rgb_backlight_settings.h @@ -8,17 +8,18 @@ typedef struct { uint8_t version; uint8_t rgb_backlight_installed; float brightness; - + // static gradient mode settings uint8_t led_2_color_index; uint8_t led_1_color_index; uint8_t led_0_color_index; - + // rainbow mode setings uint32_t rainbow_mode; uint32_t rainbow_speed_ms; uint16_t rainbow_step; - uint8_t rainbow_saturation; + uint8_t rainbow_saturation; + uint8_t rainbow_wide; } RGBBacklightSettings; diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 7e8536ee7..98efc54b7 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -134,21 +134,29 @@ const uint32_t rgb_backlight_rainbow_speed_value[RGB_BACKLIGHT_RAINBOW_SPEED_COU 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000}; -#define RGB_BACKLIGHT_RAINBOW_STEP_COUNT 10 +#define RGB_BACKLIGHT_RAINBOW_STEP_COUNT 3 const char* const rgb_backlight_rainbow_step_text[RGB_BACKLIGHT_RAINBOW_STEP_COUNT] = { "1", "2", "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", }; -const uint32_t rgb_backlight_rainbow_step_value[RGB_BACKLIGHT_RAINBOW_STEP_COUNT] = - {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; +const uint32_t rgb_backlight_rainbow_step_value[RGB_BACKLIGHT_RAINBOW_STEP_COUNT] = { + 1, + 2, + 3, +}; + +#define RGB_BACKLIGHT_RAINBOW_WIDE_COUNT 3 +const char* const rgb_backlight_rainbow_wide_text[RGB_BACKLIGHT_RAINBOW_WIDE_COUNT] = { + "1", + "2", + "3", +}; +const uint32_t rgb_backlight_rainbow_wide_value[RGB_BACKLIGHT_RAINBOW_WIDE_COUNT] = { + 30, + 40, + 50, +}; typedef enum { MainViewId, @@ -234,26 +242,29 @@ static void rgb_backlight_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_backlight_installed_text[index]); - app->notification->rgb_srv->settings->rgb_backlight_installed = rgb_backlight_installed_value[index]; + app->notification->rgb_srv->settings->rgb_backlight_installed = + rgb_backlight_installed_value[index]; rgb_backlight_settings_save(app->notification->rgb_srv->settings); - + // In case of user playing with rgb_backlight_installed swith: - // if user swith_off rgb_backlight_installed then force set default orange color - if (index == 0) { - rgb_backlight_set_led_static_color (2,0); - rgb_backlight_set_led_static_color (1,0); - rgb_backlight_set_led_static_color (0,0); + // if user swith_off rgb_backlight_installed then force set default orange color - defence from stupid. + if(index == 0) { + rgb_backlight_set_led_static_color(2, 0); + rgb_backlight_set_led_static_color(1, 0); + rgb_backlight_set_led_static_color(0, 0); SK6805_update(); - // if user swith_on rgb_backlight_installed then start rainbow if its ON or set saved static colors + // start rainbow (if its Enabled) or set saved static colors if user swith_on rgb_backlight_installed switch } else { - - if (app->notification->rgb_srv->settings->rainbow_mode >0) { - rainbow_timer_starter (app->notification->rgb_srv); + if(app->notification->rgb_srv->settings->rainbow_mode > 0) { + rainbow_timer_starter(app->notification->rgb_srv); } else { - rgb_backlight_set_led_static_color (2,app->notification->rgb_srv->settings->led_2_color_index); - rgb_backlight_set_led_static_color (1,app->notification->rgb_srv->settings->led_1_color_index); - rgb_backlight_set_led_static_color (0,app->notification->rgb_srv->settings->led_0_color_index); - rgb_backlight_update (app->notification->settings.display_brightness); + rgb_backlight_set_led_static_color( + 2, app->notification->rgb_srv->settings->led_2_color_index); + rgb_backlight_set_led_static_color( + 1, app->notification->rgb_srv->settings->led_1_color_index); + rgb_backlight_set_led_static_color( + 0, app->notification->rgb_srv->settings->led_0_color_index); + rgb_backlight_update(app->notification->settings.display_brightness); } } @@ -262,7 +273,7 @@ static void rgb_backlight_installed_changed(VariableItem* item) { if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { slide = 1; } - for(int i = slide; i < (slide + 7); i++) { + for(int i = slide; i < (slide + 8); 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\nOFF!"); @@ -279,13 +290,12 @@ static void led_2_color_changed(VariableItem* item) { variable_item_set_current_value_text(item, rgb_backlight_get_color_text(index)); app->notification->rgb_srv->settings->led_2_color_index = index; - rgb_backlight_set_led_static_color(2,index); - rgb_backlight_update(app->notification->rgb_srv->settings->brightness); - - // dont update display color if rainbow working - if (!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { - rgb_backlight_settings_save(app->notification->rgb_srv->settings); + //dont update screen color if rainbow timer working + if(!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { + rgb_backlight_set_led_static_color(2, index); + rgb_backlight_update(app->notification->rgb_srv->settings->brightness); } + rgb_backlight_settings_save(app->notification->rgb_srv->settings); } static void led_1_color_changed(VariableItem* item) { @@ -295,13 +305,13 @@ static void led_1_color_changed(VariableItem* item) { variable_item_set_current_value_text(item, rgb_backlight_get_color_text(index)); app->notification->rgb_srv->settings->led_1_color_index = index; - rgb_backlight_set_led_static_color(1,index); - rgb_backlight_settings_save(app->notification->rgb_srv->settings); - - // dont update display color if rainbow working - if (!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { - rgb_backlight_settings_save(app->notification->rgb_srv->settings); + //dont update screen color if rainbow timer working + if(!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { + rgb_backlight_set_led_static_color(1, index); + rgb_backlight_update(app->notification->rgb_srv->settings->brightness); } + + rgb_backlight_settings_save(app->notification->rgb_srv->settings); } static void led_0_color_changed(VariableItem* item) { @@ -311,13 +321,13 @@ static void led_0_color_changed(VariableItem* item) { variable_item_set_current_value_text(item, rgb_backlight_get_color_text(index)); app->notification->rgb_srv->settings->led_0_color_index = index; - rgb_backlight_set_led_static_color(0,index); - rgb_backlight_settings_save(app->notification->rgb_srv->settings); - - // dont update display color if rainbow working - if (!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { - rgb_backlight_settings_save(app->notification->rgb_srv->settings); + //dont update screen color if rainbow timer working + if(!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { + rgb_backlight_set_led_static_color(0, index); + rgb_backlight_update(app->notification->rgb_srv->settings->brightness); } + + rgb_backlight_settings_save(app->notification->rgb_srv->settings); } static void rgb_backlight_rainbow_changed(VariableItem* item) { @@ -332,9 +342,12 @@ static void rgb_backlight_rainbow_changed(VariableItem* item) { // restore saved rgb backlight settings if we switch_off rainbow mode if(app->notification->rgb_srv->settings->rainbow_mode == 0) { - rgb_backlight_set_led_static_color (2,app->notification->rgb_srv->settings->led_2_color_index); - rgb_backlight_set_led_static_color (1,app->notification->rgb_srv->settings->led_1_color_index); - rgb_backlight_set_led_static_color (0,app->notification->rgb_srv->settings->led_0_color_index); + rgb_backlight_set_led_static_color( + 2, app->notification->rgb_srv->settings->led_2_color_index); + rgb_backlight_set_led_static_color( + 1, app->notification->rgb_srv->settings->led_1_color_index); + rgb_backlight_set_led_static_color( + 0, app->notification->rgb_srv->settings->led_0_color_index); rgb_backlight_update(app->notification->rgb_srv->settings->brightness); } } @@ -362,294 +375,324 @@ static void rgb_backlight_rainbow_step_changed(VariableItem* item) { rgb_backlight_settings_save(app->notification->rgb_srv->settings); } -static void rgb_backlight_rainbow_saturation_changed (VariableItem* item) { +static void rgb_backlight_rainbow_saturation_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); - //saturation must be 1..255, so (0..254)+1 - uint8_t index = variable_item_get_current_value_index(item)+1; + //saturation must be 1..255, so we do (0..254)+1 + uint8_t index = variable_item_get_current_value_index(item) + 1; char valtext[4] = {}; snprintf(valtext, sizeof(valtext), "%d", index); variable_item_set_current_value_text(item, valtext); app->notification->rgb_srv->settings->rainbow_saturation = index; 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_backlight_installed 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_backlight_installed) || - (furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug))) && - (index == 0)) { - view_dispatcher_switch_to_view(app->view_dispatcher, RGBViewId); - } +static void rgb_backlight_rainbow_wide_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_rainbow_wide_text[index]); + app->notification->rgb_srv->settings->rainbow_wide = rgb_backlight_rainbow_wide_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); +} + +// open rgb_settings_view if user press OK on first (index=0) menu string and (debug mode or rgb_backlight_installed 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_backlight_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; +// 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; +} + +static NotificationAppSettings* alloc_settings(void) { + NotificationAppSettings* app = malloc(sizeof(NotificationAppSettings)); + app->notification = furi_record_open(RECORD_NOTIFICATION); + app->gui = furi_record_open(RECORD_GUI); + + app->variable_item_list = variable_item_list_alloc(); + View* view = variable_item_list_get_view(app->variable_item_list); + + 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_backlight_installed is active + if((app->notification->rgb_srv->settings->rgb_backlight_installed) || + (furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug))) { + item = variable_item_list_add(app->variable_item_list, "RGB settings", 0, NULL, app); } //--- RGB BACKLIGHT END --- - static uint32_t notification_app_settings_exit(void* context) { - UNUSED(context); - return VIEW_NONE; - } + item = variable_item_list_add( + app->variable_item_list, "LCD Contrast", CONTRAST_COUNT, contrast_changed, app); + value_index = + value_index_int32(app->notification->settings.contrast, contrast_value, CONTRAST_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, contrast_text[value_index]); - static NotificationAppSettings* alloc_settings(void) { - NotificationAppSettings* app = malloc(sizeof(NotificationAppSettings)); - app->notification = furi_record_open(RECORD_NOTIFICATION); - app->gui = furi_record_open(RECORD_GUI); + item = variable_item_list_add( + app->variable_item_list, "LCD Backlight", BACKLIGHT_COUNT, backlight_changed, app); + value_index = value_index_float( + app->notification->settings.display_brightness, backlight_value, BACKLIGHT_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, backlight_text[value_index]); - app->variable_item_list = variable_item_list_alloc(); - View* view = variable_item_list_get_view(app->variable_item_list); + item = variable_item_list_add( + app->variable_item_list, "Backlight Time", DELAY_COUNT, screen_changed, app); + value_index = value_index_uint32( + app->notification->settings.display_off_delay_ms, delay_value, DELAY_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, delay_text[value_index]); - VariableItem* item; - uint8_t value_index; + item = variable_item_list_add( + app->variable_item_list, "LED Brightness", BACKLIGHT_COUNT, led_changed, app); + value_index = value_index_float( + app->notification->settings.led_brightness, backlight_value, BACKLIGHT_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, backlight_text[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_backlight_installed is active - if((app->notification->rgb_srv->settings->rgb_backlight_installed) || - (furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug))) { - item = variable_item_list_add(app->variable_item_list, "RGB 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 = value_index_int32( - app->notification->settings.contrast, contrast_value, CONTRAST_COUNT); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { + item = variable_item_list_add(app->variable_item_list, "Volume", 1, NULL, app); + value_index = 0; variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, contrast_text[value_index]); - + variable_item_set_current_value_text(item, "Stealth"); + } else { item = variable_item_list_add( - app->variable_item_list, "LCD Backlight", BACKLIGHT_COUNT, backlight_changed, app); + app->variable_item_list, "Volume", VOLUME_COUNT, volume_changed, app); value_index = value_index_float( - app->notification->settings.display_brightness, backlight_value, BACKLIGHT_COUNT); + app->notification->settings.speaker_volume, volume_value, VOLUME_COUNT); variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, backlight_text[value_index]); - - item = variable_item_list_add( - app->variable_item_list, "Backlight Time", DELAY_COUNT, screen_changed, app); - value_index = value_index_uint32( - app->notification->settings.display_off_delay_ms, delay_value, DELAY_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, delay_text[value_index]); - - item = variable_item_list_add( - app->variable_item_list, "LED Brightness", BACKLIGHT_COUNT, led_changed, app); - value_index = value_index_float( - app->notification->settings.led_brightness, backlight_value, BACKLIGHT_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, backlight_text[value_index]); - - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { - item = variable_item_list_add(app->variable_item_list, "Volume", 1, NULL, app); - value_index = 0; - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, "Stealth"); - } else { - item = variable_item_list_add( - app->variable_item_list, "Volume", VOLUME_COUNT, volume_changed, app); - value_index = value_index_float( - app->notification->settings.speaker_volume, volume_value, VOLUME_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, volume_text[value_index]); - } - - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { - item = variable_item_list_add(app->variable_item_list, "Vibro", 1, NULL, app); - value_index = 0; - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, "Stealth"); - } else { - item = variable_item_list_add( - app->variable_item_list, "Vibro", VIBRO_COUNT, vibro_changed, app); - value_index = - value_index_bool(app->notification->settings.vibro_on, vibro_value, VIBRO_COUNT); - variable_item_set_current_value_index(item, value_index); - 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 exit from rgb_settings_menu - view_set_previous_callback(view_rgb, notification_app_rgb_settings_exit); - - // // Show rgb_backlight_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 backlight installed", - RGB_BACKLIGHT_INSTALLED_COUNT, - rgb_backlight_installed_changed, - app); - value_index = value_index_bool( - app->notification->rgb_srv->settings->rgb_backlight_installed, - rgb_backlight_installed_value, - RGB_BACKLIGHT_INSTALLED_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, rgb_backlight_installed_text[value_index]); - } - - // led_1 color - item = variable_item_list_add( - app->variable_item_list_rgb, - "LED 1 Color", - rgb_backlight_get_color_count(), - led_2_color_changed, - app); - value_index = app->notification->rgb_srv->settings->led_2_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->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); - - // led_2 color - item = variable_item_list_add( - app->variable_item_list_rgb, - "LED 2 Color", - rgb_backlight_get_color_count(), - led_1_color_changed, - app); - value_index = app->notification->rgb_srv->settings->led_1_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->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); - - // led 3 color - item = variable_item_list_add( - app->variable_item_list_rgb, - "LED 3 Color", - rgb_backlight_get_color_count(), - led_0_color_changed, - app); - value_index = app->notification->rgb_srv->settings->led_0_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->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); - - // Rainbow mode - item = variable_item_list_add( - app->variable_item_list_rgb, - "Rainbow mode", - RGB_BACKLIGHT_RAINBOW_MODE_COUNT, - rgb_backlight_rainbow_changed, - app); - value_index = value_index_uint32( - app->notification->rgb_srv->settings->rainbow_mode, - rgb_backlight_rainbow_mode_value, - RGB_BACKLIGHT_RAINBOW_MODE_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, rgb_backlight_rainbow_mode_text[value_index]); - variable_item_set_locked( - item, - (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); - - item = variable_item_list_add( - app->variable_item_list_rgb, - "Rainbow speed", - RGB_BACKLIGHT_RAINBOW_SPEED_COUNT, - rgb_backlight_rainbow_speed_changed, - app); - value_index = value_index_uint32( - app->notification->rgb_srv->settings->rainbow_speed_ms, - rgb_backlight_rainbow_speed_value, - RGB_BACKLIGHT_RAINBOW_SPEED_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, rgb_backlight_rainbow_speed_text[value_index]); - variable_item_set_locked( - item, - (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); - - item = variable_item_list_add( - app->variable_item_list_rgb, - "Rainbow step", - RGB_BACKLIGHT_RAINBOW_STEP_COUNT, - rgb_backlight_rainbow_step_changed, - app); - value_index = value_index_uint32( - app->notification->rgb_srv->settings->rainbow_step, - rgb_backlight_rainbow_step_value, - RGB_BACKLIGHT_RAINBOW_SPEED_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, rgb_backlight_rainbow_step_text[value_index]); - variable_item_set_locked( - item, - (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); - - item = variable_item_list_add( - app->variable_item_list_rgb, - "Saturation", - 255, - rgb_backlight_rainbow_saturation_changed, - app); - value_index = app->notification->rgb_srv->settings->rainbow_saturation; - 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->rgb_backlight_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, MainViewId, view); - view_dispatcher_add_view(app->view_dispatcher, RGBViewId, view_rgb); - view_dispatcher_switch_to_view(app->view_dispatcher, MainViewId); - return app; + variable_item_set_current_value_text(item, volume_text[value_index]); } - static void free_settings(NotificationAppSettings * app) { - 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); - furi_record_close(RECORD_NOTIFICATION); - free(app); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { + item = variable_item_list_add(app->variable_item_list, "Vibro", 1, NULL, app); + value_index = 0; + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, "Stealth"); + } else { + item = variable_item_list_add( + app->variable_item_list, "Vibro", VIBRO_COUNT, vibro_changed, app); + value_index = + value_index_bool(app->notification->settings.vibro_on, vibro_value, VIBRO_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, vibro_text[value_index]); } - int32_t notification_settings_app(void* p) { - UNUSED(p); - NotificationAppSettings* app = alloc_settings(); - view_dispatcher_run(app->view_dispatcher); - notification_message_save_settings(app->notification); + //--- RGB BACKLIGHT --- - // Automaticaly switch_off debug_mode when user exit from settings with enabled rgb_backlight_installed - // if(app->notification->settings.rgb_backlight_installed) { - // furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); - // } + app->variable_item_list_rgb = variable_item_list_alloc(); + View* view_rgb = variable_item_list_get_view(app->variable_item_list_rgb); - free_settings(app); - return 0; + // set callback for exit from rgb_settings_menu + view_set_previous_callback(view_rgb, notification_app_rgb_settings_exit); + + // // Show rgb_backlight_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 backlight installed", + RGB_BACKLIGHT_INSTALLED_COUNT, + rgb_backlight_installed_changed, + app); + value_index = value_index_bool( + app->notification->rgb_srv->settings->rgb_backlight_installed, + rgb_backlight_installed_value, + RGB_BACKLIGHT_INSTALLED_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_backlight_installed_text[value_index]); } + + // We (humans) are numbering LEDs from left to right as 1..3, but hardware have another order from right to left 2..0 + // led_1 color + item = variable_item_list_add( + app->variable_item_list_rgb, + "LED 1 Color", + rgb_backlight_get_color_count(), + led_2_color_changed, + app); + value_index = app->notification->rgb_srv->settings->led_2_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->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); + + // led_2 color + item = variable_item_list_add( + app->variable_item_list_rgb, + "LED 2 Color", + rgb_backlight_get_color_count(), + led_1_color_changed, + app); + value_index = app->notification->rgb_srv->settings->led_1_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->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); + + // led 3 color + item = variable_item_list_add( + app->variable_item_list_rgb, + "LED 3 Color", + rgb_backlight_get_color_count(), + led_0_color_changed, + app); + value_index = app->notification->rgb_srv->settings->led_0_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->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); + + // Rainbow mode + item = variable_item_list_add( + app->variable_item_list_rgb, + "Rainbow mode", + RGB_BACKLIGHT_RAINBOW_MODE_COUNT, + rgb_backlight_rainbow_changed, + app); + value_index = value_index_uint32( + app->notification->rgb_srv->settings->rainbow_mode, + rgb_backlight_rainbow_mode_value, + RGB_BACKLIGHT_RAINBOW_MODE_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_backlight_rainbow_mode_text[value_index]); + variable_item_set_locked( + item, + (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); + + item = variable_item_list_add( + app->variable_item_list_rgb, + "Rainbow speed", + RGB_BACKLIGHT_RAINBOW_SPEED_COUNT, + rgb_backlight_rainbow_speed_changed, + app); + value_index = value_index_uint32( + app->notification->rgb_srv->settings->rainbow_speed_ms, + rgb_backlight_rainbow_speed_value, + RGB_BACKLIGHT_RAINBOW_SPEED_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_backlight_rainbow_speed_text[value_index]); + variable_item_set_locked( + item, + (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); + + item = variable_item_list_add( + app->variable_item_list_rgb, + "Rainbow step", + RGB_BACKLIGHT_RAINBOW_STEP_COUNT, + rgb_backlight_rainbow_step_changed, + app); + value_index = value_index_uint32( + app->notification->rgb_srv->settings->rainbow_step, + rgb_backlight_rainbow_step_value, + RGB_BACKLIGHT_RAINBOW_STEP_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_backlight_rainbow_step_text[value_index]); + variable_item_set_locked( + item, + (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); + + item = variable_item_list_add( + app->variable_item_list_rgb, + "Saturation", + 255, + rgb_backlight_rainbow_saturation_changed, + app); + value_index = app->notification->rgb_srv->settings->rainbow_saturation; + 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->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); + + item = variable_item_list_add( + app->variable_item_list_rgb, + "Wave wide", + RGB_BACKLIGHT_RAINBOW_WIDE_COUNT, + rgb_backlight_rainbow_wide_changed, + app); + value_index = value_index_uint32( + app->notification->rgb_srv->settings->rainbow_wide, + rgb_backlight_rainbow_wide_value, + RGB_BACKLIGHT_RAINBOW_WIDE_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_backlight_rainbow_wide_text[value_index]); + variable_item_set_locked( + item, + (app->notification->rgb_srv->settings->rgb_backlight_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, 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, 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); + furi_record_close(RECORD_NOTIFICATION); + free(app); +} + +int32_t notification_settings_app(void* p) { + UNUSED(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_backlight_installed + // if(app->notification->settings.rgb_backlight_installed) { + // furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); + // } + + free_settings(app); + return 0; +} From f751b285322fb19ff9ac96cebf901c564f083810 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Wed, 19 Mar 2025 19:18:19 +0700 Subject: [PATCH 033/125] Reboot screen color cosmetic changes. --- applications/services/rgb_backlight/rgb_backlight.c | 6 +++--- .../notification_settings/notification_settings_app.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index 8d05e68de..f42a80dbe 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -38,9 +38,9 @@ typedef struct { //use one type RGBBacklightColor for current_leds_settings and for static colors definition static RGBBacklightColor current_led[] = { - {"LED0", 255, 60, 0}, - {"LED1", 255, 60, 0}, - {"LED2", 255, 60, 0}, + {"LED0", 0, 0, 0}, + {"LED1", 0, 0, 0}, + {"LED2", 0, 0, 0}, }; static const RGBBacklightColor colors[] = { diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 98efc54b7..f4d5c40bb 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -253,7 +253,7 @@ static void rgb_backlight_installed_changed(VariableItem* item) { rgb_backlight_set_led_static_color(1, 0); rgb_backlight_set_led_static_color(0, 0); SK6805_update(); - // start rainbow (if its Enabled) or set saved static colors if user swith_on rgb_backlight_installed switch + // start rainbow (if its Enabled) or set saved static colors if user swith_on rgb_backlight_installed switch } else { if(app->notification->rgb_srv->settings->rainbow_mode > 0) { rainbow_timer_starter(app->notification->rgb_srv); From dc7e96d1855f53878a28cfd905f367fd7609cd7c Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Fri, 21 Mar 2025 06:33:27 +0700 Subject: [PATCH 034/125] Code cleanup --- targets/f7/api_symbols.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 9cc8e15f6..c94a009ee 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,86.0,, +Version,+,83.2,, 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,, From f52c9855d62c93176e61d1a311203e18c623a4f9 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Sun, 23 Mar 2025 19:36:38 +0700 Subject: [PATCH 035/125] Cosmetic code changes and removing unused parts. --- .../services/rgb_backlight/rgb_backlight.c | 35 ++++-------- .../services/rgb_backlight/rgb_backlight.h | 52 ++++++++++++++++-- .../notification_settings_app.c | 54 ++++++++++++------- 3 files changed, 93 insertions(+), 48 deletions(-) diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index f42a80dbe..053654ec2 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -36,7 +36,7 @@ typedef struct { uint8_t blue; } RGBBacklightColor; -//use one type RGBBacklightColor for current_leds_settings and for static colors definition +// use one type RGBBacklightColor for current_leds_settings and for static colors definition static RGBBacklightColor current_led[] = { {"LED0", 0, 0, 0}, {"LED1", 0, 0, 0}, @@ -83,30 +83,18 @@ void rgb_backlight_set_led_static_color(uint8_t led, uint8_t index) { } } -// --- NOT USED IN CURRENT RELEASE, FOR FUTURE USAGE--- -// Update current colors by custom rgb value -// void rgb_backlight_set_led_custom_color(uint8_t led, uint8_t red, uint8_t green, uint8_t blue) { -// if(led < SK6805_get_led_count()) { -// current_led[led].red = red; -// current_led[led].green = green; -// current_led[led].blue = blue; -// SK6805_set_led_color(led, red, green, blue); -// } -// } -// --- NOT USED IN CURRENT RELEASE, FOR FUTURE USAGE--- - // HSV to RGB based on // https://www.radiokot.ru/forum/viewtopic.php?p=3000181&ysclid=m88wvoz34w244644702 // https://radiolaba.ru/microcotrollers/tsvetnaya-lampa.html#comment-1790 // https://alexgyver.ru/lessons/arduino-rgb/?ysclid=m88voflppa24464916 // led number (0-2), hue (0..255), sat (0..255), val (0...1) void rgb_backlight_set_led_custom_hsv_color(uint8_t led, uint16_t hue, uint8_t sat, float V) { - //init value + // init value float r = 1.0f; float g = 1.0f; float b = 1.0f; - //from (0..255) to (0..1) + // from (0..255) to (0..1) float H = hue / 255.0f; float S = sat / 255.0f; @@ -137,7 +125,7 @@ void rgb_backlight_set_led_custom_hsv_color(uint8_t led, uint16_t hue, uint8_t s break; } - //from (0..1) to (0..255) + // from (0..1) to (0..255) current_led[led].red = r * 255; current_led[led].green = g * 255; current_led[led].blue = b * 255; @@ -159,12 +147,12 @@ void rgb_backlight_update(float brightness) { furi_record_close(RECORD_RGB_BACKLIGHT); } -//start furi timer for rainbow +// 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 +// stop furi timer for rainbow void rainbow_timer_stop(RGBBacklightApp* app) { furi_timer_stop(app->rainbow_timer); } @@ -173,10 +161,6 @@ void rainbow_timer_stop(RGBBacklightApp* app) { void rainbow_timer_starter(RGBBacklightApp* app) { if((app->settings->rainbow_mode > 0) && (app->settings->rgb_backlight_installed)) { rainbow_timer_start(app); - } else { - if(furi_timer_is_running(app->rainbow_timer)) { - rainbow_timer_stop(app); - } } } @@ -239,7 +223,7 @@ int32_t rgb_backlight_srv(void* p) { // allocate memory and create RECORD for access to app structure from outside RGBBacklightApp* app = malloc(sizeof(RGBBacklightApp)); - //define rainbow_timer and they callback + // define rainbow_timer and they callback app->rainbow_timer = furi_timer_alloc(rainbow_timer_callback, FuriTimerTypePeriodic, app); // settings load or create default @@ -250,10 +234,10 @@ int32_t rgb_backlight_srv(void* p) { furi_record_create(RECORD_RGB_BACKLIGHT, app); - //if rgb_backlight_installed then start rainbow or set leds colors from saved settings (default index = 0) + // if rgb_backlight_installed then start rainbow or set leds colors from saved settings (default index = 0) if(app->settings->rgb_backlight_installed) { if(app->settings->rainbow_mode > 0) { - rainbow_timer_starter(app); + rainbow_timer_start(app); } else { rgb_backlight_set_led_static_color(2, app->settings->led_2_color_index); rgb_backlight_set_led_static_color(1, app->settings->led_1_color_index); @@ -269,7 +253,6 @@ int32_t rgb_backlight_srv(void* p) { } while(1) { - // place for message queue and other future options furi_delay_ms(5000); if(app->settings->rgb_backlight_installed) { FURI_LOG_D(TAG, "RGB backlight enabled - serivce is running"); diff --git a/applications/services/rgb_backlight/rgb_backlight.h b/applications/services/rgb_backlight/rgb_backlight.h index 10aa9341f..d6f8b5fce 100644 --- a/applications/services/rgb_backlight/rgb_backlight.h +++ b/applications/services/rgb_backlight/rgb_backlight.h @@ -32,21 +32,65 @@ typedef struct { uint8_t rainbow_red; uint8_t rainbow_green; uint8_t rainbow_blue; - RGBBacklightSettings* settings; - } RGBBacklightApp; #define RECORD_RGB_BACKLIGHT "rgb_backlight" +/** Update leds colors from current_led[i].color and selected bright + * + * @param brightness - Brightness 0..1 + * @return + */ void rgb_backlight_update(float brightness); -//not used now, for future use -// void rgb_backlight_set_custom_color(uint8_t red, uint8_t green, uint8_t blue); + +/** Set current_led[i].color for one led by static color index + * + * @param led - Led number (0..2) + * @param index - Static color index number + * @return + */ void rgb_backlight_set_led_static_color(uint8_t led, uint8_t index); + +/** Stop rainbow timer + * + * @param app - Instance of RGBBacklightApp from FURI RECORD + * @return + */ void rainbow_timer_stop(RGBBacklightApp* app); + +/** Start rainbow timer + * + * @param app - Instance of RGBBacklightApp from FURI RECORD + * @return + */ + +/** Start rainbow timer + * + * @param app - Instance of RGBBacklightApp from FURI RECORD + * @return + */ void rainbow_timer_start(RGBBacklightApp* app); + +/** Start rainbow timer only if all conditions meet (rgb_backlight_installed && rainbow ON) + * + * @param app - Instance of RGBBacklightApp from FURI RECORD + * @return + */ void rainbow_timer_starter(RGBBacklightApp* app); + +/** Get name of static color by index + * + * @param index - Static colors index number + * @return - color name + */ const char* rgb_backlight_get_color_text(uint8_t index); + +/** Get static colors count + * + * @param + * @return - colors count + */ uint8_t rgb_backlight_get_color_count(void); #ifdef __cplusplus diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index f4d5c40bb..dd2206dc2 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -16,8 +16,6 @@ typedef struct { VariableItemList* variable_item_list_rgb; } NotificationAppSettings; -//static VariableItem* temp_item; - static const NotificationSequence sequence_note_c = { &message_note_c5, &message_delay_100, @@ -126,13 +124,32 @@ const char* const rgb_backlight_rainbow_mode_text[RGB_BACKLIGHT_RAINBOW_MODE_COU }; const uint32_t rgb_backlight_rainbow_mode_value[RGB_BACKLIGHT_RAINBOW_MODE_COUNT] = {0, 1, 2}; -#define RGB_BACKLIGHT_RAINBOW_SPEED_COUNT 20 +#define RGB_BACKLIGHT_RAINBOW_SPEED_COUNT 10 const char* const rgb_backlight_rainbow_speed_text[RGB_BACKLIGHT_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"}; + "0.1s", + "0.2s", + "0.3s", + "0.4s", + "0.5s", + "0.6s", + "0.7", + "0.8", + "0.9", + "1s", +}; + const uint32_t rgb_backlight_rainbow_speed_value[RGB_BACKLIGHT_RAINBOW_SPEED_COUNT] = { - 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, - 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000}; + 100, + 200, + 300, + 400, + 500, + 600, + 700, + 800, + 900, + 1000, +}; #define RGB_BACKLIGHT_RAINBOW_STEP_COUNT 3 const char* const rgb_backlight_rainbow_step_text[RGB_BACKLIGHT_RAINBOW_STEP_COUNT] = { @@ -182,7 +199,7 @@ static void backlight_changed(VariableItem* item) { app->notification->settings.display_brightness = backlight_value[index]; //--- RGB BACKLIGHT --- - //set selected brightness to current rgb backlight service settings and save settings + // 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 --- @@ -247,13 +264,14 @@ static void rgb_backlight_installed_changed(VariableItem* item) { rgb_backlight_settings_save(app->notification->rgb_srv->settings); // In case of user playing with rgb_backlight_installed swith: - // if user swith_off rgb_backlight_installed then force set default orange color - defence from stupid. + // if user swith_off rgb_backlight_installed (but may be he have mod installed) + // then force set default orange color - defence from stupid. if(index == 0) { rgb_backlight_set_led_static_color(2, 0); rgb_backlight_set_led_static_color(1, 0); rgb_backlight_set_led_static_color(0, 0); SK6805_update(); - // start rainbow (if its Enabled) or set saved static colors if user swith_on rgb_backlight_installed switch + // start rainbow (if its Enabled) or set saved static colors if user swith_on rgb_backlight_installed switch } else { if(app->notification->rgb_srv->settings->rainbow_mode > 0) { rainbow_timer_starter(app->notification->rgb_srv); @@ -290,7 +308,7 @@ static void led_2_color_changed(VariableItem* item) { variable_item_set_current_value_text(item, rgb_backlight_get_color_text(index)); app->notification->rgb_srv->settings->led_2_color_index = index; - //dont update screen color if rainbow timer working + // dont update screen color if rainbow timer working if(!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { rgb_backlight_set_led_static_color(2, index); rgb_backlight_update(app->notification->rgb_srv->settings->brightness); @@ -305,7 +323,7 @@ static void led_1_color_changed(VariableItem* item) { variable_item_set_current_value_text(item, rgb_backlight_get_color_text(index)); app->notification->rgb_srv->settings->led_1_color_index = index; - //dont update screen color if rainbow timer working + // dont update screen color if rainbow timer working if(!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { rgb_backlight_set_led_static_color(1, index); rgb_backlight_update(app->notification->rgb_srv->settings->brightness); @@ -321,7 +339,7 @@ static void led_0_color_changed(VariableItem* item) { variable_item_set_current_value_text(item, rgb_backlight_get_color_text(index)); app->notification->rgb_srv->settings->led_0_color_index = index; - //dont update screen color if rainbow timer working + // dont update screen color if rainbow timer working if(!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { rgb_backlight_set_led_static_color(0, index); rgb_backlight_update(app->notification->rgb_srv->settings->brightness); @@ -360,7 +378,7 @@ static void rgb_backlight_rainbow_speed_changed(VariableItem* item) { app->notification->rgb_srv->settings->rainbow_speed_ms = rgb_backlight_rainbow_speed_value[index]; - //save settings and restart timer with new speed value + // 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); } @@ -378,7 +396,7 @@ static void rgb_backlight_rainbow_step_changed(VariableItem* item) { static void rgb_backlight_rainbow_saturation_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); - //saturation must be 1..255, so we do (0..254)+1 + // saturation must be 1..255, so we do (0..254)+1 uint8_t index = variable_item_get_current_value_index(item) + 1; char valtext[4] = {}; snprintf(valtext, sizeof(valtext), "%d", index); @@ -394,7 +412,7 @@ static void rgb_backlight_rainbow_wide_changed(VariableItem* item) { variable_item_set_current_value_text(item, rgb_backlight_rainbow_wide_text[index]); app->notification->rgb_srv->settings->rainbow_wide = rgb_backlight_rainbow_wide_value[index]; - //save settings and restart timer with new speed value + // 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); } @@ -442,7 +460,7 @@ static NotificationAppSettings* alloc_settings(void) { 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_backlight_installed is active + // Show RGB settings only when debug_mode or rgb_backlight_installed is active if((app->notification->rgb_srv->settings->rgb_backlight_installed) || (furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug))) { item = variable_item_list_add(app->variable_item_list, "RGB settings", 0, NULL, app); @@ -513,7 +531,7 @@ static NotificationAppSettings* alloc_settings(void) { // set callback for exit from rgb_settings_menu view_set_previous_callback(view_rgb, notification_app_rgb_settings_exit); - // // Show rgb_backlight_installed swith only in Debug mode + // Show rgb_backlight_installed swith only in Debug mode if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { item = variable_item_list_add( app->variable_item_list_rgb, From e196999b4a27f589ca8c97ecbab3a2ce736e0c18 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 24 Mar 2025 03:36:26 +0300 Subject: [PATCH 036/125] upd changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index adb257d38..6c89f8dd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ * SubGHz: **Fix Hollarm protocol with more verification** * SubGHz: **Fix GangQi protocol** (by @DoberBit and @mishamyte (who spent 2 weeks on this)) * SubGHz: **Came Atomo button hold simulation with full cycle** simulation (to allow proper pairing with receiver) -* System: **Сombining RGB Backlight mod** (by @quen0n) and original backlight support **in one firmware** (+ Rainbow effect (based on @Willy-JL idea)) (PR #877 | by @Dmitry422) - (**To enable RGB Backlight support go into Notifications settings with Debug mode - ON**) +* System: **Сombining RGB Backlight mod** (by @quen0n) and original backlight support **in one firmware** (+ Rainbow/Wave effect (based on @Willy-JL idea)) (PR #877 #881 | by @Dmitry422) - (**To enable RGB Backlight support go into Notifications settings with Debug mode - ON**) * OFW: LFRFID - **EM4305 support** * OFW: **Universal IR signal selection** * OFW: **BadUSB: Mouse control** From b792e094fb9003e0f4c131feac16ec8148c835c9 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 24 Mar 2025 05:08:29 +0300 Subject: [PATCH 037/125] bump version --- applications/services/rgb_backlight/rgb_backlight_settings.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.c b/applications/services/rgb_backlight/rgb_backlight_settings.c index f612507e4..681197284 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.c +++ b/applications/services/rgb_backlight/rgb_backlight_settings.c @@ -9,8 +9,8 @@ #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) // Current version number +#define RGB_BACKLIGHT_SETTINGS_VER_PREV (2) // Previous version number +#define RGB_BACKLIGHT_SETTINGS_VER (3) // Current version number //pervious settings must be copyed from previous rgb_backlight_settings.h file typedef struct { From 23d2bed66a4f96463a8bbf5c0f1b300cad6dac64 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Tue, 25 Mar 2025 15:52:38 +0700 Subject: [PATCH 038/125] Remove Rainbow timer bug (after last code cleanup) --- applications/services/rgb_backlight/rgb_backlight.c | 4 +++- .../notification_settings/notification_settings_app.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index 053654ec2..9dc60a5ec 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -154,7 +154,9 @@ void rainbow_timer_start(RGBBacklightApp* app) { // stop furi timer for rainbow void rainbow_timer_stop(RGBBacklightApp* app) { - furi_timer_stop(app->rainbow_timer); + if (furi_timer_is_running (app->rainbow_timer)){ + furi_timer_stop(app->rainbow_timer); + } } // if rgb_backlight_installed then apply rainbow colors to backlight and start/restart/stop rainbow_timer diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index dd2206dc2..2408d4e05 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -355,7 +355,6 @@ static void rgb_backlight_rainbow_changed(VariableItem* item) { variable_item_set_current_value_text(item, rgb_backlight_rainbow_mode_text[index]); app->notification->rgb_srv->settings->rainbow_mode = rgb_backlight_rainbow_mode_value[index]; - rainbow_timer_starter(app->notification->rgb_srv); rgb_backlight_settings_save(app->notification->rgb_srv->settings); // restore saved rgb backlight settings if we switch_off rainbow mode @@ -367,6 +366,9 @@ static void rgb_backlight_rainbow_changed(VariableItem* item) { rgb_backlight_set_led_static_color( 0, app->notification->rgb_srv->settings->led_0_color_index); rgb_backlight_update(app->notification->rgb_srv->settings->brightness); + rainbow_timer_stop (app->notification->rgb_srv); + } else { + rainbow_timer_starter(app->notification->rgb_srv); } } From ca2765a3fb1af0aa79410b163b1827ca1755c27b Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Tue, 25 Mar 2025 18:23:18 +0700 Subject: [PATCH 039/125] Small rgb_backlight settings menu changes --- .../rgb_backlight/rgb_backlight_settings.c | 4 +- .../rgb_backlight/rgb_backlight_settings.h | 1 + .../notification_settings_app.c | 68 +++++++++++++++++-- 3 files changed, 67 insertions(+), 6 deletions(-) diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.c b/applications/services/rgb_backlight/rgb_backlight_settings.c index 681197284..60361923f 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.c +++ b/applications/services/rgb_backlight/rgb_backlight_settings.c @@ -9,8 +9,8 @@ #define RGB_BACKLIGHT_SETTINGS_PATH INT_PATH(RGB_BACKLIGHT_SETTINGS_FILE_NAME) #define RGB_BACKLIGHT_SETTINGS_MAGIC (0x30) -#define RGB_BACKLIGHT_SETTINGS_VER_PREV (2) // Previous version number -#define RGB_BACKLIGHT_SETTINGS_VER (3) // Current version number +#define RGB_BACKLIGHT_SETTINGS_VER_PREV (3) // Previous version number +#define RGB_BACKLIGHT_SETTINGS_VER (4) // Current version number //pervious settings must be copyed from previous rgb_backlight_settings.h file typedef struct { diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.h b/applications/services/rgb_backlight/rgb_backlight_settings.h index 3f3af005f..5136a16ca 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.h +++ b/applications/services/rgb_backlight/rgb_backlight_settings.h @@ -10,6 +10,7 @@ typedef struct { float brightness; // static gradient mode settings + bool individual_led; uint8_t led_2_color_index; uint8_t led_1_color_index; uint8_t led_0_color_index; diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 2408d4e05..9a123e014 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -175,6 +175,16 @@ const uint32_t rgb_backlight_rainbow_wide_value[RGB_BACKLIGHT_RAINBOW_WIDE_COUNT 50, }; +#define RGB_BACKLIGHT_INDIVIDUAL_LED_COUNT 2 +const char* const rgb_backlight_individual_led_text[RGB_BACKLIGHT_INDIVIDUAL_LED_COUNT] = { + "OFF", + "ON", +}; +const bool rgb_backlight_individual_value[RGB_BACKLIGHT_INDIVIDUAL_LED_COUNT] = { + false, + true, +}; + typedef enum { MainViewId, RGBViewId, @@ -291,7 +301,7 @@ static void rgb_backlight_installed_changed(VariableItem* item) { if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { slide = 1; } - for(int i = slide; i < (slide + 8); i++) { + for(int i = slide; i < (slide + 9); 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\nOFF!"); @@ -301,6 +311,32 @@ static void rgb_backlight_installed_changed(VariableItem* item) { } } +static void individual_led_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_individual_led_text[index]); + app->notification->rgb_srv->settings->individual_led = index; + + // if individual led OFF - set led0 and led1 colors indexes as led2 index + if (index == 0) { + app->notification->rgb_srv->settings->led_1_color_index = app->notification->rgb_srv->settings->led_2_color_index; + app->notification->rgb_srv->settings->led_0_color_index = app->notification->rgb_srv->settings->led_2_color_index; + } + + // enable/disable led0 and led1 color settings + for(int i = 2; i < 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, "Individual\nleds OFF!"); + } else { + variable_item_set_locked(t_item, false, "Individual\nleds OFF!"); + } + } + rgb_backlight_update(app->notification->rgb_srv->settings->brightness); + //rgb_backlight_settings_save(app->notification->rgb_srv->settings); +} + static void led_2_color_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -550,6 +586,22 @@ static NotificationAppSettings* alloc_settings(void) { } // We (humans) are numbering LEDs from left to right as 1..3, but hardware have another order from right to left 2..0 + + // Individual led color switch + item = variable_item_list_add( + app->variable_item_list_rgb, + "Individual leds colors", + RGB_BACKLIGHT_INDIVIDUAL_LED_COUNT, + individual_led_changed, + app); + value_index = app->notification->rgb_srv->settings->individual_led; + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_backlight_individual_led_text[value_index]); + variable_item_set_locked( + item, + (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), + "RGB MOD \nOFF!"); + // led_1 color item = variable_item_list_add( app->variable_item_list_rgb, @@ -579,6 +631,10 @@ static NotificationAppSettings* alloc_settings(void) { item, (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), "RGB MOD \nOFF!"); + variable_item_set_locked( + item, + (!app->notification->rgb_srv->settings->individual_led), + "Individual\nleds OFF!"); // led 3 color item = variable_item_list_add( @@ -594,11 +650,15 @@ static NotificationAppSettings* alloc_settings(void) { item, (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), "RGB MOD \nOFF!"); + variable_item_set_locked( + item, + (!app->notification->rgb_srv->settings->individual_led), + "Individual\nleds OFF!"); // Rainbow mode item = variable_item_list_add( app->variable_item_list_rgb, - "Rainbow mode", + "Dynamic colors mode", RGB_BACKLIGHT_RAINBOW_MODE_COUNT, rgb_backlight_rainbow_changed, app); @@ -615,7 +675,7 @@ static NotificationAppSettings* alloc_settings(void) { item = variable_item_list_add( app->variable_item_list_rgb, - "Rainbow speed", + "Mode speed", RGB_BACKLIGHT_RAINBOW_SPEED_COUNT, rgb_backlight_rainbow_speed_changed, app); @@ -632,7 +692,7 @@ static NotificationAppSettings* alloc_settings(void) { item = variable_item_list_add( app->variable_item_list_rgb, - "Rainbow step", + "Colors step", RGB_BACKLIGHT_RAINBOW_STEP_COUNT, rgb_backlight_rainbow_step_changed, app); From 8df48988f54b49dad7213e2e910835adc5a8ab31 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Tue, 25 Mar 2025 22:34:03 +0700 Subject: [PATCH 040/125] Revert "Small rgb_backlight settings menu changes" This reverts commit ca2765a3fb1af0aa79410b163b1827ca1755c27b. --- .../rgb_backlight/rgb_backlight_settings.c | 4 +- .../rgb_backlight/rgb_backlight_settings.h | 1 - .../notification_settings_app.c | 68 ++----------------- 3 files changed, 6 insertions(+), 67 deletions(-) diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.c b/applications/services/rgb_backlight/rgb_backlight_settings.c index 60361923f..681197284 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.c +++ b/applications/services/rgb_backlight/rgb_backlight_settings.c @@ -9,8 +9,8 @@ #define RGB_BACKLIGHT_SETTINGS_PATH INT_PATH(RGB_BACKLIGHT_SETTINGS_FILE_NAME) #define RGB_BACKLIGHT_SETTINGS_MAGIC (0x30) -#define RGB_BACKLIGHT_SETTINGS_VER_PREV (3) // Previous version number -#define RGB_BACKLIGHT_SETTINGS_VER (4) // Current version number +#define RGB_BACKLIGHT_SETTINGS_VER_PREV (2) // Previous version number +#define RGB_BACKLIGHT_SETTINGS_VER (3) // Current version number //pervious settings must be copyed from previous rgb_backlight_settings.h file typedef struct { diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.h b/applications/services/rgb_backlight/rgb_backlight_settings.h index 5136a16ca..3f3af005f 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.h +++ b/applications/services/rgb_backlight/rgb_backlight_settings.h @@ -10,7 +10,6 @@ typedef struct { float brightness; // static gradient mode settings - bool individual_led; uint8_t led_2_color_index; uint8_t led_1_color_index; uint8_t led_0_color_index; diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 9a123e014..2408d4e05 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -175,16 +175,6 @@ const uint32_t rgb_backlight_rainbow_wide_value[RGB_BACKLIGHT_RAINBOW_WIDE_COUNT 50, }; -#define RGB_BACKLIGHT_INDIVIDUAL_LED_COUNT 2 -const char* const rgb_backlight_individual_led_text[RGB_BACKLIGHT_INDIVIDUAL_LED_COUNT] = { - "OFF", - "ON", -}; -const bool rgb_backlight_individual_value[RGB_BACKLIGHT_INDIVIDUAL_LED_COUNT] = { - false, - true, -}; - typedef enum { MainViewId, RGBViewId, @@ -301,7 +291,7 @@ static void rgb_backlight_installed_changed(VariableItem* item) { if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { slide = 1; } - for(int i = slide; i < (slide + 9); i++) { + for(int i = slide; i < (slide + 8); 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\nOFF!"); @@ -311,32 +301,6 @@ static void rgb_backlight_installed_changed(VariableItem* item) { } } -static void individual_led_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_individual_led_text[index]); - app->notification->rgb_srv->settings->individual_led = index; - - // if individual led OFF - set led0 and led1 colors indexes as led2 index - if (index == 0) { - app->notification->rgb_srv->settings->led_1_color_index = app->notification->rgb_srv->settings->led_2_color_index; - app->notification->rgb_srv->settings->led_0_color_index = app->notification->rgb_srv->settings->led_2_color_index; - } - - // enable/disable led0 and led1 color settings - for(int i = 2; i < 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, "Individual\nleds OFF!"); - } else { - variable_item_set_locked(t_item, false, "Individual\nleds OFF!"); - } - } - rgb_backlight_update(app->notification->rgb_srv->settings->brightness); - //rgb_backlight_settings_save(app->notification->rgb_srv->settings); -} - static void led_2_color_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -586,22 +550,6 @@ static NotificationAppSettings* alloc_settings(void) { } // We (humans) are numbering LEDs from left to right as 1..3, but hardware have another order from right to left 2..0 - - // Individual led color switch - item = variable_item_list_add( - app->variable_item_list_rgb, - "Individual leds colors", - RGB_BACKLIGHT_INDIVIDUAL_LED_COUNT, - individual_led_changed, - app); - value_index = app->notification->rgb_srv->settings->individual_led; - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, rgb_backlight_individual_led_text[value_index]); - variable_item_set_locked( - item, - (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); - // led_1 color item = variable_item_list_add( app->variable_item_list_rgb, @@ -631,10 +579,6 @@ static NotificationAppSettings* alloc_settings(void) { item, (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), "RGB MOD \nOFF!"); - variable_item_set_locked( - item, - (!app->notification->rgb_srv->settings->individual_led), - "Individual\nleds OFF!"); // led 3 color item = variable_item_list_add( @@ -650,15 +594,11 @@ static NotificationAppSettings* alloc_settings(void) { item, (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), "RGB MOD \nOFF!"); - variable_item_set_locked( - item, - (!app->notification->rgb_srv->settings->individual_led), - "Individual\nleds OFF!"); // Rainbow mode item = variable_item_list_add( app->variable_item_list_rgb, - "Dynamic colors mode", + "Rainbow mode", RGB_BACKLIGHT_RAINBOW_MODE_COUNT, rgb_backlight_rainbow_changed, app); @@ -675,7 +615,7 @@ static NotificationAppSettings* alloc_settings(void) { item = variable_item_list_add( app->variable_item_list_rgb, - "Mode speed", + "Rainbow speed", RGB_BACKLIGHT_RAINBOW_SPEED_COUNT, rgb_backlight_rainbow_speed_changed, app); @@ -692,7 +632,7 @@ static NotificationAppSettings* alloc_settings(void) { item = variable_item_list_add( app->variable_item_list_rgb, - "Colors step", + "Rainbow step", RGB_BACKLIGHT_RAINBOW_STEP_COUNT, rgb_backlight_rainbow_step_changed, app); From a9288da9ba7ffa0dadc025ccf5ac4778e66dd692 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Wed, 26 Mar 2025 08:11:52 +0700 Subject: [PATCH 041/125] RGB backlight bags and code cleanup --- .../notification_settings_app.c | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 2408d4e05..4e14d2012 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -261,16 +261,19 @@ static void rgb_backlight_installed_changed(VariableItem* item) { variable_item_set_current_value_text(item, rgb_backlight_installed_text[index]); app->notification->rgb_srv->settings->rgb_backlight_installed = rgb_backlight_installed_value[index]; - rgb_backlight_settings_save(app->notification->rgb_srv->settings); + + app->notification->rgb_srv->settings->brightness = + app->notification->settings.display_brightness; // In case of user playing with rgb_backlight_installed swith: // if user swith_off rgb_backlight_installed (but may be he have mod installed) - // then force set default orange color - defence from stupid. + // then force set default orange color and stop rainbow timer if(index == 0) { rgb_backlight_set_led_static_color(2, 0); rgb_backlight_set_led_static_color(1, 0); rgb_backlight_set_led_static_color(0, 0); SK6805_update(); + rainbow_timer_stop(app->notification->rgb_srv); // start rainbow (if its Enabled) or set saved static colors if user swith_on rgb_backlight_installed switch } else { if(app->notification->rgb_srv->settings->rainbow_mode > 0) { @@ -299,6 +302,8 @@ static void rgb_backlight_installed_changed(VariableItem* item) { variable_item_set_locked(t_item, false, "RGB\nOFF!"); } } + + rgb_backlight_settings_save(app->notification->rgb_srv->settings); } static void led_2_color_changed(VariableItem* item) { @@ -313,6 +318,7 @@ static void led_2_color_changed(VariableItem* item) { rgb_backlight_set_led_static_color(2, index); rgb_backlight_update(app->notification->rgb_srv->settings->brightness); } + rgb_backlight_settings_save(app->notification->rgb_srv->settings); } @@ -355,10 +361,8 @@ static void rgb_backlight_rainbow_changed(VariableItem* item) { variable_item_set_current_value_text(item, rgb_backlight_rainbow_mode_text[index]); app->notification->rgb_srv->settings->rainbow_mode = rgb_backlight_rainbow_mode_value[index]; - rgb_backlight_settings_save(app->notification->rgb_srv->settings); - - // restore saved rgb backlight settings if we switch_off rainbow mode - if(app->notification->rgb_srv->settings->rainbow_mode == 0) { + // restore saved rgb backlight settings if we switch_off effects + if(index == 0) { rgb_backlight_set_led_static_color( 2, app->notification->rgb_srv->settings->led_2_color_index); rgb_backlight_set_led_static_color( @@ -366,10 +370,12 @@ static void rgb_backlight_rainbow_changed(VariableItem* item) { rgb_backlight_set_led_static_color( 0, app->notification->rgb_srv->settings->led_0_color_index); rgb_backlight_update(app->notification->rgb_srv->settings->brightness); - rainbow_timer_stop (app->notification->rgb_srv); + rainbow_timer_stop(app->notification->rgb_srv); } else { rainbow_timer_starter(app->notification->rgb_srv); } + + rgb_backlight_settings_save(app->notification->rgb_srv->settings); } static void rgb_backlight_rainbow_speed_changed(VariableItem* item) { @@ -381,8 +387,8 @@ static void rgb_backlight_rainbow_speed_changed(VariableItem* item) { rgb_backlight_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); + rgb_backlight_settings_save(app->notification->rgb_srv->settings); } static void rgb_backlight_rainbow_step_changed(VariableItem* item) { @@ -404,6 +410,7 @@ static void rgb_backlight_rainbow_saturation_changed(VariableItem* item) { snprintf(valtext, sizeof(valtext), "%d", index); variable_item_set_current_value_text(item, valtext); app->notification->rgb_srv->settings->rainbow_saturation = index; + rgb_backlight_settings_save(app->notification->rgb_srv->settings); } @@ -414,9 +421,7 @@ static void rgb_backlight_rainbow_wide_changed(VariableItem* item) { variable_item_set_current_value_text(item, rgb_backlight_rainbow_wide_text[index]); app->notification->rgb_srv->settings->rainbow_wide = rgb_backlight_rainbow_wide_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); } // open rgb_settings_view if user press OK on first (index=0) menu string and (debug mode or rgb_backlight_installed is true) @@ -553,7 +558,7 @@ static NotificationAppSettings* alloc_settings(void) { // led_1 color item = variable_item_list_add( app->variable_item_list_rgb, - "LED 1 Color", + "Led 1 Color", rgb_backlight_get_color_count(), led_2_color_changed, app); @@ -568,7 +573,7 @@ static NotificationAppSettings* alloc_settings(void) { // led_2 color item = variable_item_list_add( app->variable_item_list_rgb, - "LED 2 Color", + "Led 2 Color", rgb_backlight_get_color_count(), led_1_color_changed, app); @@ -583,7 +588,7 @@ static NotificationAppSettings* alloc_settings(void) { // led 3 color item = variable_item_list_add( app->variable_item_list_rgb, - "LED 3 Color", + "Led 3 Color", rgb_backlight_get_color_count(), led_0_color_changed, app); @@ -595,10 +600,10 @@ static NotificationAppSettings* alloc_settings(void) { (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), "RGB MOD \nOFF!"); - // Rainbow mode + // Efects item = variable_item_list_add( app->variable_item_list_rgb, - "Rainbow mode", + "Effects", RGB_BACKLIGHT_RAINBOW_MODE_COUNT, rgb_backlight_rainbow_changed, app); @@ -615,7 +620,7 @@ static NotificationAppSettings* alloc_settings(void) { item = variable_item_list_add( app->variable_item_list_rgb, - "Rainbow speed", + " . Speed", RGB_BACKLIGHT_RAINBOW_SPEED_COUNT, rgb_backlight_rainbow_speed_changed, app); @@ -632,7 +637,7 @@ static NotificationAppSettings* alloc_settings(void) { item = variable_item_list_add( app->variable_item_list_rgb, - "Rainbow step", + " . Color step", RGB_BACKLIGHT_RAINBOW_STEP_COUNT, rgb_backlight_rainbow_step_changed, app); @@ -649,7 +654,7 @@ static NotificationAppSettings* alloc_settings(void) { item = variable_item_list_add( app->variable_item_list_rgb, - "Saturation", + " . Saturation", 255, rgb_backlight_rainbow_saturation_changed, app); @@ -665,7 +670,7 @@ static NotificationAppSettings* alloc_settings(void) { item = variable_item_list_add( app->variable_item_list_rgb, - "Wave wide", + " . Wave wide", RGB_BACKLIGHT_RAINBOW_WIDE_COUNT, rgb_backlight_rainbow_wide_changed, app); From c86b6e4b56e9af8a3975f2fc1856caa306745929 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Wed, 26 Mar 2025 10:43:45 +0700 Subject: [PATCH 042/125] Bump settings for new auto recreation after update --- applications/services/rgb_backlight/rgb_backlight_settings.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.c b/applications/services/rgb_backlight/rgb_backlight_settings.c index 681197284..b76c6598a 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.c +++ b/applications/services/rgb_backlight/rgb_backlight_settings.c @@ -9,8 +9,8 @@ #define RGB_BACKLIGHT_SETTINGS_PATH INT_PATH(RGB_BACKLIGHT_SETTINGS_FILE_NAME) #define RGB_BACKLIGHT_SETTINGS_MAGIC (0x30) -#define RGB_BACKLIGHT_SETTINGS_VER_PREV (2) // Previous version number -#define RGB_BACKLIGHT_SETTINGS_VER (3) // Current version number +#define RGB_BACKLIGHT_SETTINGS_VER_PREV (4) // Previous version number +#define RGB_BACKLIGHT_SETTINGS_VER (5) // Current version number //pervious settings must be copyed from previous rgb_backlight_settings.h file typedef struct { From 77865586e13b2bd2d6c2352e2062949ef341d3cf Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Wed, 26 Mar 2025 18:51:36 +0700 Subject: [PATCH 043/125] Start working with "Night Shift" option --- .../services/notification/notification_app.h | 3 + .../notification_settings_app.c | 90 +++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 798b01ab6..7ee421b31 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -45,6 +45,9 @@ typedef struct { uint32_t display_off_delay_ms; int8_t contrast; bool vibro_on; + float night_shift; + uint32_t night_shift_start; + uint32_t night_shift_end; } NotificationSettings; struct NotificationApp { diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 4e14d2012..435a0087c 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -182,6 +182,66 @@ typedef enum { // --- RGB BACKLIGHT END --- + // --- NIGHT SHIFT --- + #define NIGHT_SHIFT_COUNT 7 + const char* const night_shift_text[NIGHT_SHIFT_COUNT] = { + "OFF", + "5%", + "10%" + "15%", + "20%", + "25%", + "30%" + + }; + const float night_shift_value[NIGHT_SHIFT_COUNT] = { + 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, + }; + + #define NIGHT_SHIFT_START_COUNT 14 + const char* const night_shift_start_text[NIGHT_SHIFT_START_COUNT] = { + "17:00", + "17:30", + "18:00" + "18:30", + "19:00", + "19:30", + "20:00", + "20:30", + "21:00", + "21:30", + "22:00", + "22:30", + "23:00", + "23:30", + }; + const uint32_t night_shift_start_value[NIGHT_SHIFT_START_COUNT] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + + #define NIGHT_SHIFT_END_COUNT 14 + const char* const night_shift_end_text[NIGHT_SHIFT_END_COUNT] = { + "05:00", + "05:30", + "06:00" + "06:30", + "07:00", + "07:30", + "08:00", + "08:30", + "09:00", + "09:30", + "10:00", + "10:30", + "11:00", + "11:30", + }; + const uint32_t night_shift_end_value[NIGHT_SHIFT_END_COUNT] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + + // --- NIGHT SHIFT END --- + static void contrast_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -443,6 +503,11 @@ static uint32_t notification_app_rgb_settings_exit(void* context) { } //--- RGB BACKLIGHT END --- +// --- NIGHT SHIFT --- + + +// --- NIGHT SHIFT END --- + static uint32_t notification_app_settings_exit(void* context) { UNUSED(context); return VIEW_NONE; @@ -495,6 +560,31 @@ static NotificationAppSettings* alloc_settings(void) { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, delay_text[value_index]); + // --- NIGHT SHIFT --- + item = variable_item_list_add( + app->variable_item_list, "Night Shift", NIGHT_SHIFT_COUNT, night_shift_changed, app); + value_index = value_index_float( + app->notification->settings.night_shift, night_shift_value, NIGHT_SHIFT_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, night_shift_text[value_index]); + + item = variable_item_list_add( + app->variable_item_list, " . Start", NIGHT_SHIFT_START_COUNT, night_shift_start_changed, app); + value_index = value_index_uint32( + app->notification->settings.night_shift_start, night_shift_start_value, NIGHT_SHIFT_START_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, night_shift_start_text[value_index]); + + item = variable_item_list_add( + app->variable_item_list, " . End", NIGHT_SHIFT_END_COUNT, night_shift_end_changed, app); + value_index = value_index_uint32( + app->notification->settings.night_shift_end, night_shift_end_value, NIGHT_SHIFT_END_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, night_shift_end_text[value_index]); + + // --- NIGHT SHIFT END--- + + item = variable_item_list_add( app->variable_item_list, "LED Brightness", BACKLIGHT_COUNT, led_changed, app); value_index = value_index_float( From cd28f7d23223e8dfe675190c0cc09c7e5b5f7f82 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Fri, 28 Mar 2025 01:14:57 +0700 Subject: [PATCH 044/125] current working, need find and remove 1 bug --- .../services/notification/notification_app.c | 85 ++++++- .../services/notification/notification_app.h | 7 +- .../services/rgb_backlight/rgb_backlight.c | 13 +- .../services/rgb_backlight/rgb_backlight.h | 3 + .../rgb_backlight/rgb_backlight_settings.c | 1 + .../rgb_backlight/rgb_backlight_settings.h | 2 +- .../notification_settings_app.c | 233 +++++++++++++----- 7 files changed, 264 insertions(+), 80 deletions(-) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index cf03d4389..3eca2fd2d 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -33,6 +33,51 @@ static uint8_t notification_settings_get_display_brightness(NotificationApp* app static uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value); static uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app); +// --- NIGHT SHIFT --- + +void night_shift_timer_start(NotificationApp* app) { + if(app->settings.night_shift != 1) { + furi_timer_start(app->night_shift_timer, furi_ms_to_ticks(2000)); + } +} + +void night_shift_timer_stop(NotificationApp* app) { + if(furi_timer_is_running(app->night_shift_timer)) { + furi_timer_stop(app->night_shift_timer); + } +} + +// every callback time we check current time and current night_shift_settings value +void night_shift_timer_callback(void* context) { + furi_assert(context); + NotificationApp* app = context; + DateTime current_date_time; + + // save current night_shift; + // float old_night_shift = app->current_night_shift; + + // take system time and convert to minutes + furi_hal_rtc_get_datetime(¤t_date_time); + uint32_t time = current_date_time.hour * 60 + current_date_time.minute; + + // if current time not in night_shift range then current_night_shift = 1 else = settings value; + // set values to stock and rgb backlights + if((time > app->settings.night_shift_end) && (time < app->settings.night_shift_start)) { + app->current_night_shift = 1.0f; + app->rgb_srv->current_night_shift = 1.0f; + } else { + app->current_night_shift = app->settings.night_shift; + app->rgb_srv->current_night_shift = app->settings.night_shift; + } + + // // if night shift was changed then update stock and rgb backlight to new value + // if(old_night_shift != app->current_night_shift) { + // notification_message(app, &sequence_display_backlight_on); + // } +} + +// --- NIGHT SHIFT END --- + void notification_message_save_settings(NotificationApp* app) { NotificationAppMessage m = { .type = SaveSettingsMessage, .back_event = furi_event_flag_alloc()}; @@ -129,7 +174,11 @@ static void notification_reset_notification_layer( } if(reset_mask & reset_display_mask) { if(!float_is_equal(display_brightness_set, app->settings.display_brightness)) { - furi_hal_light_set(LightBacklight, app->settings.display_brightness * 0xFF); + // --- NIGHT SHIFT --- + furi_hal_light_set( + LightBacklight, + app->settings.display_brightness * 0xFF * app->current_night_shift); + // --- NIGHT SHIFT END--- } furi_timer_start(app->display_timer, notification_settings_display_off_delay_ticks(app)); } @@ -214,15 +263,17 @@ static void notification_process_notification_message( // if on - switch on and start timer // if off - switch off and stop timer // on timer - switch off + // --- NIGHT SHIFT --- if(notification_message->data.led.value > 0x00) { notification_apply_notification_led_layer( &app->display, - notification_message->data.led.value * display_brightness_setting); + notification_message->data.led.value * display_brightness_setting * + app->current_night_shift); 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); - + // --- NIGHT SHIFT END --- } else { reset_mask &= ~reset_display_mask; notification_reset_notification_led_layer(&app->display); @@ -238,10 +289,12 @@ static void notification_process_notification_message( case NotificationMessageTypeLedDisplayBacklightEnforceOn: furi_check(app->display_led_lock < UINT8_MAX); app->display_led_lock++; + // --- NIGHT SHIFT --- if(app->display_led_lock == 1) { notification_apply_internal_led_layer( &app->display, - notification_message->data.led.value * display_brightness_setting); + notification_message->data.led.value * display_brightness_setting * + app->current_night_shift); } break; case NotificationMessageTypeLedDisplayBacklightEnforceAuto: @@ -250,8 +303,10 @@ static void notification_process_notification_message( if(app->display_led_lock == 0) { notification_apply_internal_led_layer( &app->display, - notification_message->data.led.value * display_brightness_setting); + notification_message->data.led.value * display_brightness_setting * + app->current_night_shift); } + // --- NIGHT SHIFT END --- } else { FURI_LOG_E(TAG, "Incorrect BacklightEnforce use"); } @@ -559,6 +614,17 @@ static NotificationApp* notification_app_alloc(void) { furi_pubsub_subscribe(app->event_record, input_event_callback, app); notification_message(app, &sequence_display_backlight_on); + // --- NIGHT SHIFT --- + app->rgb_srv = furi_record_open(RECORD_RGB_BACKLIGHT); + app->rgb_srv->current_night_shift = 1.0f; + app->current_night_shift = 1.0f; + app->settings.night_shift = 1.0f; + app->settings.night_shift_start = 1020; + app->settings.night_shift_end = 300; + app->night_shift_timer = + furi_timer_alloc(night_shift_timer_callback, FuriTimerTypePeriodic, app); + // --- NIGHT SHIFT END --- + return app; } @@ -582,6 +648,13 @@ static void notification_apply_settings(NotificationApp* app) { } notification_apply_lcd_contrast(app); + + // --- NIGHT SHIFT --- + // if night_shift_enabled start timer for controlling current_night_shift multiplicator value depent from current time + if(app->settings.night_shift != 1) { + night_shift_timer_start(app); + } + // --- NIGHT SHIFT END --- } static void notification_init_settings(NotificationApp* app) { @@ -600,7 +673,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 7ee421b31..0d4404fa5 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -34,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 { @@ -61,6 +61,11 @@ struct NotificationApp { NotificationSettings settings; RGBBacklightApp* rgb_srv; + + FuriTimer* night_shift_timer; + float current_night_shift; }; void notification_message_save_settings(NotificationApp* app); +void night_shift_timer_start(NotificationApp* app); +void night_shift_timer_stop(NotificationApp* app); diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index 9dc60a5ec..8862ac154 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -137,9 +137,9 @@ void rgb_backlight_update(float brightness) { if(app->settings->rgb_backlight_installed) { for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { - uint8_t r = current_led[i].red * (brightness * 1.0f); - uint8_t g = current_led[i].green * (brightness * 1.0f); - uint8_t b = current_led[i].blue * (brightness * 1.0f); + uint8_t r = current_led[i].red * brightness; + uint8_t g = current_led[i].green * brightness; + uint8_t b = current_led[i].blue * brightness; SK6805_set_led_color(i, r, g, b); } SK6805_update(); @@ -154,7 +154,7 @@ void rainbow_timer_start(RGBBacklightApp* app) { // stop furi timer for rainbow void rainbow_timer_stop(RGBBacklightApp* app) { - if (furi_timer_is_running (app->rainbow_timer)){ + if(furi_timer_is_running(app->rainbow_timer)) { furi_timer_stop(app->rainbow_timer); } } @@ -214,7 +214,7 @@ static void rainbow_timer_callback(void* context) { break; } - rgb_backlight_update(app->settings->brightness); + rgb_backlight_update(app->settings->brightness * app->current_night_shift); } } @@ -233,6 +233,7 @@ int32_t rgb_backlight_srv(void* p) { rgb_backlight_settings_load(app->settings); app->rainbow_hue = 1; + app->current_night_shift = 1.0f; furi_record_create(RECORD_RGB_BACKLIGHT, app); @@ -244,7 +245,7 @@ int32_t rgb_backlight_srv(void* p) { rgb_backlight_set_led_static_color(2, app->settings->led_2_color_index); rgb_backlight_set_led_static_color(1, app->settings->led_1_color_index); rgb_backlight_set_led_static_color(0, app->settings->led_0_color_index); - rgb_backlight_update(app->settings->brightness); + rgb_backlight_update(app->settings->brightness * app->current_night_shift); } // if rgb_backlight not installed then set default static orange color(index=0) to all leds (0-2) and force light on } else { diff --git a/applications/services/rgb_backlight/rgb_backlight.h b/applications/services/rgb_backlight/rgb_backlight.h index d6f8b5fce..1be252dc1 100644 --- a/applications/services/rgb_backlight/rgb_backlight.h +++ b/applications/services/rgb_backlight/rgb_backlight.h @@ -33,6 +33,9 @@ typedef struct { uint8_t rainbow_green; uint8_t rainbow_blue; RGBBacklightSettings* settings; + // night_shift multiplicator for leds brightnes coming from Notificatoin app. + float current_night_shift; + } RGBBacklightApp; #define RECORD_RGB_BACKLIGHT "rgb_backlight" diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.c b/applications/services/rgb_backlight/rgb_backlight_settings.c index b76c6598a..17f6bb271 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.c +++ b/applications/services/rgb_backlight/rgb_backlight_settings.c @@ -30,6 +30,7 @@ typedef struct { uint16_t rainbow_step; uint8_t rainbow_saturation; uint8_t rainbow_wide; + } RGBBacklightSettingsPrevious; void rgb_backlight_settings_load(RGBBacklightSettings* settings) { diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.h b/applications/services/rgb_backlight/rgb_backlight_settings.h index 3f3af005f..b1e4a4a01 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.h +++ b/applications/services/rgb_backlight/rgb_backlight_settings.h @@ -20,7 +20,7 @@ typedef struct { uint16_t rainbow_step; uint8_t rainbow_saturation; uint8_t rainbow_wide; - + } RGBBacklightSettings; #ifdef __cplusplus diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 435a0087c..86176c8e5 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -182,65 +182,93 @@ typedef enum { // --- RGB BACKLIGHT END --- - // --- NIGHT SHIFT --- - #define NIGHT_SHIFT_COUNT 7 - const char* const night_shift_text[NIGHT_SHIFT_COUNT] = { - "OFF", - "5%", - "10%" - "15%", - "20%", - "25%", - "30%" +// --- NIGHT SHIFT --- +#define NIGHT_SHIFT_COUNT 7 +const char* const night_shift_text[NIGHT_SHIFT_COUNT] = + {"OFF", "-10%", "-20%", "-30%", "-40%", "-50%", "-60%" - }; - const float night_shift_value[NIGHT_SHIFT_COUNT] = { - 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, - }; +}; +const float night_shift_value[NIGHT_SHIFT_COUNT] = { + 1.0f, + 0.9f, + 0.8f, + 0.7f, + 0.6f, + 0.5f, + 0.4f, +}; - #define NIGHT_SHIFT_START_COUNT 14 - const char* const night_shift_start_text[NIGHT_SHIFT_START_COUNT] = { - "17:00", - "17:30", - "18:00" - "18:30", - "19:00", - "19:30", - "20:00", - "20:30", - "21:00", - "21:30", - "22:00", - "22:30", - "23:00", - "23:30", - }; - const uint32_t night_shift_start_value[NIGHT_SHIFT_START_COUNT] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }; +#define NIGHT_SHIFT_START_COUNT 14 +const char* const night_shift_start_text[NIGHT_SHIFT_START_COUNT] = { + "17:00", + "17:30", + "18:00", + "18:30", + "19:00", + "19:30", + "20:00", + "20:30", + "21:00", + "21:30", + "22:00", + "22:30", + "23:00", + "23:30", +}; +// values in minutes like 23:30 = 23*60+30=1410 +const uint32_t night_shift_start_value[NIGHT_SHIFT_START_COUNT] = { + 1020, + 1050, + 1080, + 1110, + 1140, + 1170, + 1200, + 1230, + 1260, + 1290, + 1320, + 1350, + 1380, + 1410, +}; - #define NIGHT_SHIFT_END_COUNT 14 - const char* const night_shift_end_text[NIGHT_SHIFT_END_COUNT] = { - "05:00", - "05:30", - "06:00" - "06:30", - "07:00", - "07:30", - "08:00", - "08:30", - "09:00", - "09:30", - "10:00", - "10:30", - "11:00", - "11:30", - }; - const uint32_t night_shift_end_value[NIGHT_SHIFT_END_COUNT] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }; +#define NIGHT_SHIFT_END_COUNT 14 +const char* const night_shift_end_text[NIGHT_SHIFT_END_COUNT] = { + "05:00", + "05:30", + "06:00", + "06:30", + "07:00", + "07:30", + "08:00", + "08:30", + "09:00", + "09:30", + "10:00", + "10:30", + "11:00", + "11:30", +}; +// values in minutes like 6:30 = 6*60+30=390 +const uint32_t night_shift_end_value[NIGHT_SHIFT_END_COUNT] = { + 300, + 330, + 360, + 390, + 410, + 440, + 470, + 500, + 530, + 560, + 590, + 620, + 650, + 680, +}; - // --- NIGHT SHIFT END --- +// --- NIGHT SHIFT END --- static void contrast_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); @@ -345,7 +373,9 @@ static void rgb_backlight_installed_changed(VariableItem* item) { 1, app->notification->rgb_srv->settings->led_1_color_index); rgb_backlight_set_led_static_color( 0, app->notification->rgb_srv->settings->led_0_color_index); - rgb_backlight_update(app->notification->settings.display_brightness); + rgb_backlight_update( + app->notification->settings.display_brightness * + app->notification->current_night_shift); } } @@ -376,7 +406,9 @@ static void led_2_color_changed(VariableItem* item) { // dont update screen color if rainbow timer working if(!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { rgb_backlight_set_led_static_color(2, index); - rgb_backlight_update(app->notification->rgb_srv->settings->brightness); + rgb_backlight_update( + app->notification->rgb_srv->settings->brightness * + app->notification->current_night_shift); } rgb_backlight_settings_save(app->notification->rgb_srv->settings); @@ -392,7 +424,9 @@ static void led_1_color_changed(VariableItem* item) { // dont update screen color if rainbow timer working if(!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { rgb_backlight_set_led_static_color(1, index); - rgb_backlight_update(app->notification->rgb_srv->settings->brightness); + rgb_backlight_update( + app->notification->rgb_srv->settings->brightness * + app->notification->current_night_shift); } rgb_backlight_settings_save(app->notification->rgb_srv->settings); @@ -408,7 +442,9 @@ static void led_0_color_changed(VariableItem* item) { // dont update screen color if rainbow timer working if(!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { rgb_backlight_set_led_static_color(0, index); - rgb_backlight_update(app->notification->rgb_srv->settings->brightness); + rgb_backlight_update( + app->notification->rgb_srv->settings->brightness * + app->notification->current_night_shift); } rgb_backlight_settings_save(app->notification->rgb_srv->settings); @@ -429,7 +465,9 @@ static void rgb_backlight_rainbow_changed(VariableItem* item) { 1, app->notification->rgb_srv->settings->led_1_color_index); rgb_backlight_set_led_static_color( 0, app->notification->rgb_srv->settings->led_0_color_index); - rgb_backlight_update(app->notification->rgb_srv->settings->brightness); + rgb_backlight_update( + app->notification->rgb_srv->settings->brightness * + app->notification->current_night_shift); rainbow_timer_stop(app->notification->rgb_srv); } else { rainbow_timer_starter(app->notification->rgb_srv); @@ -505,6 +543,60 @@ static uint32_t notification_app_rgb_settings_exit(void* context) { // --- NIGHT SHIFT --- +static void night_shift_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, night_shift_text[index]); + app->notification->settings.night_shift = night_shift_value[index]; + app->notification->current_night_shift = night_shift_value[index]; + app->notification->rgb_srv->current_night_shift = night_shift_value[index]; + + // force demo night_shift brightness ot rgb backlight and stock backlight + notification_message(app->notification, &sequence_display_backlight_on); + + int slide = 0; + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) || + (app->notification->rgb_srv->settings->rgb_backlight_installed)) { + slide = 1; + } + for(int i = 4 + slide; i < (6 + slide); i++) { + VariableItem* t_item = variable_item_list_get(app->variable_item_list, i); + if(index == 0) { + variable_item_set_locked(t_item, true, "Night shift\nOFF!"); + } else { + variable_item_set_locked(t_item, false, "Night shift\nOFF!"); + } + } + + if(night_shift_value[index] != 1) { + night_shift_timer_start(app->notification); + } else { + night_shift_timer_stop(app->notification); + } + + notification_message_save_settings(app->notification); +} + +static void night_shift_start_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, night_shift_start_text[index]); + app->notification->settings.night_shift_start = night_shift_start_value[index]; + + notification_message_save_settings(app->notification); +} + +static void night_shift_end_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, night_shift_end_text[index]); + app->notification->settings.night_shift_end = night_shift_end_value[index]; + + notification_message_save_settings(app->notification); +} // --- NIGHT SHIFT END --- @@ -562,28 +654,37 @@ static NotificationAppSettings* alloc_settings(void) { // --- NIGHT SHIFT --- item = variable_item_list_add( - app->variable_item_list, "Night Shift", NIGHT_SHIFT_COUNT, night_shift_changed, app); + app->variable_item_list, "Night shift", NIGHT_SHIFT_COUNT, night_shift_changed, app); value_index = value_index_float( app->notification->settings.night_shift, night_shift_value, NIGHT_SHIFT_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, night_shift_text[value_index]); item = variable_item_list_add( - app->variable_item_list, " . Start", NIGHT_SHIFT_START_COUNT, night_shift_start_changed, app); + app->variable_item_list, + " . Start", + NIGHT_SHIFT_START_COUNT, + night_shift_start_changed, + app); value_index = value_index_uint32( - app->notification->settings.night_shift_start, night_shift_start_value, NIGHT_SHIFT_START_COUNT); + app->notification->settings.night_shift_start, + night_shift_start_value, + NIGHT_SHIFT_START_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, night_shift_start_text[value_index]); - + variable_item_set_locked( + item, (app->notification->settings.night_shift == 1), "Night shift \nOFF!"); + item = variable_item_list_add( app->variable_item_list, " . End", NIGHT_SHIFT_END_COUNT, night_shift_end_changed, app); value_index = value_index_uint32( app->notification->settings.night_shift_end, night_shift_end_value, NIGHT_SHIFT_END_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, night_shift_end_text[value_index]); - - // --- NIGHT SHIFT END--- + variable_item_set_locked( + item, (app->notification->settings.night_shift == 1), "Night shift \nOFF!"); + // --- NIGHT SHIFT END--- item = variable_item_list_add( app->variable_item_list, "LED Brightness", BACKLIGHT_COUNT, led_changed, app); From 31b7c4a34fd22c1cedc9c2ed9f98235eb6f3b49c Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Fri, 28 Mar 2025 13:48:32 +0700 Subject: [PATCH 045/125] Night shift done. --- .../services/notification/notification_app.c | 12 +++++++----- applications/services/rgb_backlight/rgb_backlight.c | 6 +++--- .../services/rgb_backlight/rgb_backlight_settings.c | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 3eca2fd2d..b5a95b4a3 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -53,7 +53,8 @@ void night_shift_timer_callback(void* context) { NotificationApp* app = context; DateTime current_date_time; - // save current night_shift; + // IN DEVELOPMENT + // // save current night_shift; // float old_night_shift = app->current_night_shift; // take system time and convert to minutes @@ -70,6 +71,7 @@ void night_shift_timer_callback(void* context) { app->rgb_srv->current_night_shift = app->settings.night_shift; } + // IN DEVELOPMENT // // if night shift was changed then update stock and rgb backlight to new value // if(old_night_shift != app->current_night_shift) { // notification_message(app, &sequence_display_backlight_on); @@ -177,7 +179,7 @@ static void notification_reset_notification_layer( // --- NIGHT SHIFT --- furi_hal_light_set( LightBacklight, - app->settings.display_brightness * 0xFF * app->current_night_shift); + app->settings.display_brightness * 0xFF * app->current_night_shift * 1.0f); // --- NIGHT SHIFT END--- } furi_timer_start(app->display_timer, notification_settings_display_off_delay_ticks(app)); @@ -268,7 +270,7 @@ static void notification_process_notification_message( notification_apply_notification_led_layer( &app->display, notification_message->data.led.value * display_brightness_setting * - app->current_night_shift); + app->current_night_shift * 1.0f); reset_mask |= reset_display_mask; //start rgb_mod_rainbow_timer when display backlight is ON and all corresponding settings is ON too @@ -294,7 +296,7 @@ static void notification_process_notification_message( notification_apply_internal_led_layer( &app->display, notification_message->data.led.value * display_brightness_setting * - app->current_night_shift); + app->current_night_shift * 1.0f); } break; case NotificationMessageTypeLedDisplayBacklightEnforceAuto: @@ -304,7 +306,7 @@ static void notification_process_notification_message( notification_apply_internal_led_layer( &app->display, notification_message->data.led.value * display_brightness_setting * - app->current_night_shift); + app->current_night_shift * 1.0f); } // --- NIGHT SHIFT END --- } else { diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index 8862ac154..916357b89 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -137,9 +137,9 @@ void rgb_backlight_update(float brightness) { if(app->settings->rgb_backlight_installed) { for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { - uint8_t r = current_led[i].red * brightness; - uint8_t g = current_led[i].green * brightness; - uint8_t b = current_led[i].blue * brightness; + uint8_t r = current_led[i].red * brightness * 1.0f; + uint8_t g = current_led[i].green * brightness * 1.0f; + uint8_t b = current_led[i].blue * brightness * 1.0f; SK6805_set_led_color(i, r, g, b); } SK6805_update(); diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.c b/applications/services/rgb_backlight/rgb_backlight_settings.c index 17f6bb271..baa573a77 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.c +++ b/applications/services/rgb_backlight/rgb_backlight_settings.c @@ -30,7 +30,7 @@ typedef struct { uint16_t rainbow_step; uint8_t rainbow_saturation; uint8_t rainbow_wide; - + } RGBBacklightSettingsPrevious; void rgb_backlight_settings_load(RGBBacklightSettings* settings) { From 3e9bb38cd759deb1df7b9168f7f80a05458b7ee1 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 28 Mar 2025 14:01:54 +0300 Subject: [PATCH 046/125] just in case --- applications/services/notification/notification_app.c | 3 +++ applications/services/rgb_backlight/rgb_backlight.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index b5a95b4a3..b50017963 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -37,6 +37,9 @@ static uint32_t notification_settings_display_off_delay_ticks(NotificationApp* a void night_shift_timer_start(NotificationApp* app) { if(app->settings.night_shift != 1) { + if(furi_timer_is_running(app->night_shift_timer)) { + furi_timer_stop(app->night_shift_timer); + } furi_timer_start(app->night_shift_timer, furi_ms_to_ticks(2000)); } } diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index 916357b89..22628e3af 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -149,6 +149,9 @@ void rgb_backlight_update(float brightness) { // start furi timer for rainbow void rainbow_timer_start(RGBBacklightApp* app) { + if(furi_timer_is_running(app->rainbow_timer)) { + furi_timer_stop(app->rainbow_timer); + } furi_timer_start(app->rainbow_timer, furi_ms_to_ticks(app->settings->rainbow_speed_ms)); } From 82489cf8eb017e52fe3a06351230e132b890addb Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 28 Mar 2025 14:02:12 +0300 Subject: [PATCH 047/125] fmt --- applications/services/notification/notification_app.h | 2 +- applications/services/rgb_backlight/rgb_backlight_settings.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 0d4404fa5..2ef84ba95 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -47,7 +47,7 @@ typedef struct { bool vibro_on; float night_shift; uint32_t night_shift_start; - uint32_t night_shift_end; + uint32_t night_shift_end; } NotificationSettings; struct NotificationApp { diff --git a/applications/services/rgb_backlight/rgb_backlight_settings.h b/applications/services/rgb_backlight/rgb_backlight_settings.h index b1e4a4a01..3f3af005f 100644 --- a/applications/services/rgb_backlight/rgb_backlight_settings.h +++ b/applications/services/rgb_backlight/rgb_backlight_settings.h @@ -20,7 +20,7 @@ typedef struct { uint16_t rainbow_step; uint8_t rainbow_saturation; uint8_t rainbow_wide; - + } RGBBacklightSettings; #ifdef __cplusplus From 17db4dcdacba111ed7501465f52a20c10c531be3 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 28 Mar 2025 14:03:10 +0300 Subject: [PATCH 048/125] upd changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c89f8dd7..72d4dcb03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * SubGHz: **Fix Hollarm protocol with more verification** * SubGHz: **Fix GangQi protocol** (by @DoberBit and @mishamyte (who spent 2 weeks on this)) * SubGHz: **Came Atomo button hold simulation with full cycle** simulation (to allow proper pairing with receiver) +* System: **Night Shift Feature** (dimming backlight in selected time interval) (PR #885 | by @Dmitry422) * System: **Сombining RGB Backlight mod** (by @quen0n) and original backlight support **in one firmware** (+ Rainbow/Wave effect (based on @Willy-JL idea)) (PR #877 #881 | by @Dmitry422) - (**To enable RGB Backlight support go into Notifications settings with Debug mode - ON**) * OFW: LFRFID - **EM4305 support** * OFW: **Universal IR signal selection** From 65b1b943d1e9bc3b38f05140e0e8889fb8921438 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 28 Mar 2025 14:05:47 +0300 Subject: [PATCH 049/125] GUI: Fix widget text scroll with 256+ lines [ci skip] by Willy-JL in OFW PR 4160 --- .../gui/modules/widget_elements/widget_element_text_scroll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c b/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c index 4c9c39dff..491ffc6bc 100644 --- a/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c +++ b/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c @@ -19,8 +19,8 @@ typedef struct { uint8_t width; uint8_t height; FuriString* text; - uint8_t scroll_pos_total; - uint8_t scroll_pos_current; + uint16_t scroll_pos_total; + uint16_t scroll_pos_current; bool text_formatted; } WidgetElementTextScrollModel; From 0c5cab9f1ae60079f56ac7f8e3a87fca97da88ef Mon Sep 17 00:00:00 2001 From: doomwastaken Date: Fri, 28 Mar 2025 14:09:32 +0300 Subject: [PATCH 050/125] added new doom animation, updated manifests, re-enabled some animations --- .../external/L1_Doom_128x64/frame_0.png | Bin 0 -> 1495 bytes .../external/L1_Doom_128x64/frame_1.png | Bin 0 -> 1502 bytes .../external/L1_Doom_128x64/frame_10.png | Bin 0 -> 973 bytes .../external/L1_Doom_128x64/frame_11.png | Bin 0 -> 1070 bytes .../external/L1_Doom_128x64/frame_12.png | Bin 0 -> 1138 bytes .../external/L1_Doom_128x64/frame_13.png | Bin 0 -> 1069 bytes .../external/L1_Doom_128x64/frame_14.png | Bin 0 -> 1065 bytes .../external/L1_Doom_128x64/frame_15.png | Bin 0 -> 898 bytes .../external/L1_Doom_128x64/frame_16.png | Bin 0 -> 930 bytes .../external/L1_Doom_128x64/frame_17.png | Bin 0 -> 937 bytes .../external/L1_Doom_128x64/frame_18.png | Bin 0 -> 931 bytes .../external/L1_Doom_128x64/frame_19.png | Bin 0 -> 923 bytes .../external/L1_Doom_128x64/frame_2.png | Bin 0 -> 1498 bytes .../external/L1_Doom_128x64/frame_20.png | Bin 0 -> 1159 bytes .../external/L1_Doom_128x64/frame_21.png | Bin 0 -> 1284 bytes .../external/L1_Doom_128x64/frame_22.png | Bin 0 -> 1165 bytes .../external/L1_Doom_128x64/frame_23.png | Bin 0 -> 1306 bytes .../external/L1_Doom_128x64/frame_24.png | Bin 0 -> 1159 bytes .../external/L1_Doom_128x64/frame_25.png | Bin 0 -> 1307 bytes .../external/L1_Doom_128x64/frame_26.png | Bin 0 -> 1069 bytes .../external/L1_Doom_128x64/frame_27.png | Bin 0 -> 1131 bytes .../external/L1_Doom_128x64/frame_28.png | Bin 0 -> 1101 bytes .../external/L1_Doom_128x64/frame_29.png | Bin 0 -> 1035 bytes .../external/L1_Doom_128x64/frame_3.png | Bin 0 -> 1558 bytes .../external/L1_Doom_128x64/frame_30.png | Bin 0 -> 909 bytes .../external/L1_Doom_128x64/frame_31.png | Bin 0 -> 736 bytes .../external/L1_Doom_128x64/frame_32.png | Bin 0 -> 1169 bytes .../external/L1_Doom_128x64/frame_33.png | Bin 0 -> 1212 bytes .../external/L1_Doom_128x64/frame_34.png | Bin 0 -> 1269 bytes .../external/L1_Doom_128x64/frame_35.png | Bin 0 -> 1237 bytes .../external/L1_Doom_128x64/frame_36.png | Bin 0 -> 1288 bytes .../external/L1_Doom_128x64/frame_37.png | Bin 0 -> 1206 bytes .../external/L1_Doom_128x64/frame_38.png | Bin 0 -> 1240 bytes .../external/L1_Doom_128x64/frame_4.png | Bin 0 -> 1487 bytes .../external/L1_Doom_128x64/frame_5.png | Bin 0 -> 1161 bytes .../external/L1_Doom_128x64/frame_6.png | Bin 0 -> 1181 bytes .../external/L1_Doom_128x64/frame_7.png | Bin 0 -> 1138 bytes .../external/L1_Doom_128x64/frame_8.png | Bin 0 -> 1193 bytes .../external/L1_Doom_128x64/frame_9.png | Bin 0 -> 1201 bytes .../dolphin/external/L1_Doom_128x64/meta.txt | 14 + assets/dolphin/external/manifest.txt | 243 ++++++++---------- 41 files changed, 118 insertions(+), 139 deletions(-) create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_0.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_1.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_10.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_11.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_12.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_13.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_14.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_15.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_16.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_17.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_18.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_19.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_2.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_20.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_21.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_22.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_23.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_24.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_25.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_26.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_27.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_28.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_29.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_3.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_30.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_31.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_32.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_33.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_34.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_35.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_36.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_37.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_38.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_4.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_5.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_6.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_7.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_8.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/frame_9.png create mode 100644 assets/dolphin/external/L1_Doom_128x64/meta.txt diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_0.png b/assets/dolphin/external/L1_Doom_128x64/frame_0.png new file mode 100644 index 0000000000000000000000000000000000000000..937996c8c0cc0f45cabedf1b348a94fc9cfc017e GIT binary patch literal 1495 zcmV;|1t|K7P)J_8;mhpEs~t; z_14ca0qZTjzJ0G z@pKB@j(_8E;rycj8^I|6P1OKddp>P{6kro1Bg5~A=STK@+CHrSp8bcLz=L-Mz=j=F zf+&7QCypnO-TxavD{@vljS28EV1x`I1;FeaMaCGP0!;w`lB{RJr2r#FvkDuh5@D5E zSqeb=!F;kwpb{X{@Y0wk5rGS&s^;Y}KAs0$lMOKoc)cx3G(PQ%?@=Ld5ojq{<^7^T zbT$cC0*o+!bfGX2c9DQHel-b36re&0-UzVL_}qP0lRzrR;^T^WjVM6HJpK@1m+|TS zcPN2$&#JkMDnR5q>;Ap>UjkGHJQ3_70T=H?W1t9T6o9ModjQXa?>kir-W|AQ02V`2 zfC}fBRRBDW=QEexyxs+z;{AZtDquZ(#oA;j05?BsY;Nv&oM8p{1n=L8ECrDIS>wGF z;56?C>`o1tVE^)NaIKZ!{hu^d%raPsU%vZhLMzxz7>p=tGR3N zxuNd^tTbL$-s=JPTq|A(;m_9EYGfF>S9l9J)pIj|^W@4JKx_FifF$+Ocreb;7ec&< z>~G(O%u1lPhTJ`-6u=9sz=HdIBdY2E(zW#5bR8fA-|GFXU zBTE4yu?mm@6R0!>$V6nJ?tsh~fa~iW^JoG@-+G-|)#NZ+2grKXqX`h*CRWxAW>Jv^ z(7oS-twCURt-td90p33|#?OiYX6I5y09tvXsPfVZ65wZnplf#gj4UAI8A}zwBEiX- z0QPq3ff*#5Re-FuD~|yprOQ*G&6%sGkEmJZ+rSwt2?8sPoxPPvrPFN8WC58tIt$Q{ z8DHQrq-(PmKdJy#!R_q`pcx+8JqznGI`pduSiK5hJ?|`TLx9YM&{8RSzA9Vs8h@k~ z0`OdWGy$Ry<5^ToPFImZQh=HLUV8I~?@4hS0Wymm6x`c1&wVPCKq6~qipjk;rsE#> zH-bj1ZJw7TlJQ}&Rz&~Oe7Lp<>FD#&@gy9l03(PRAI@oGRm1yM&!bW^>J%cts>Sg_ zV?CV5{iMb8WE87n0B)XEMU}f&I!A4IO9h~dVO8yLU+(%H@G1a3)}Gx{!KAnq0X&9> zc2A_glL*l)fWC*YJl%^h0akAVoELl3JS(HX#6i>LE?2??LQD7$j2zFcc({gFIzG>Ra{auB)E))c2JA%YVA>8} z^Q?Rgj{a*#RV(fB^d2ri)bJ?4MsNx+B1PuP2RsU}37i6GD|lw5OZc5NU}0tE zfWHNjoOAP883Tj};9+f~{T)CnawAyVMc^U;4N9yS1vYnu$EjS=CkrM5M4YA-HclnN zDz%C#fRsH%G0XzIPV!c!B7IbXI-^Qnx{{-{0o8$mnL zvsK%aC$P%uZ|1iE&W@$OHwBn`gzv)2SSU*YJd1<7FZ4cu6`uX=Zm7%xJpGpyg0un) zZg)pyWC0N((0jL50`I!|TU)CDQfyPI02=P>{MPd802Z~y_S`W*ro$q(JQMW^$WQ>! zJkq}4`_Wkdm(PxHYE_d%Mi#)e8QGwHw{|!IB3Z|$kYKd}NH(_+AnPG0GSeh%6C=}Z zRvlnuA0Kll3j%4Ci=t|kW)h2*PcsQyp#YINEmZ*R0Z+^Xq?$UM&r+D|7(jXk4dq+F ziB6UvIYX-1&yZkN0kpPO932E&ki9377Nl4FFfXaOc zFk|03p){T2`d+aGjADSuwkJK8bPn(p|1-$5nyyR!Q>-gt305g-N4BCkZVT{0Tg|wV zhtJb?oZX7w6=>g*eL7yPtj^sloudolBMCq!V-&P`QplC?q^tPY^X%IB)|>=b5eI1f zx5hs_oVP^!ClEo)0;GC~6yQM{FOFA$k+fq-6UsRm+li)JvyjF*+OF`}tnq;cHvy_A zNOG=p4X$gFYFYIw6;6u*IATh6M%T4#TNS`l1=FreS%9^l)!Unvxp3Lbh$vA-_}JIN z@qTD^z83Y<_OpO7(tmJGBAsR#( z%vL)RdGHn*B7k+}&rGI8VK_;QsFFpFXTg!clHt(W0OwST9m)2RmqIOjwFRRZ!6$$^ z6Q7gPJ}TXm6eGpcGKAg(eo75Mn`f zx);UBL0t6CDTb5^ThifM5CBUgmc`x92aHINsRo?=Kc44c!il_~2LJ#707*qoM6N<$ Ef;{o8NB{r; literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_10.png b/assets/dolphin/external/L1_Doom_128x64/frame_10.png new file mode 100644 index 0000000000000000000000000000000000000000..a5c9befcf9309d9506662653cdc47b87ce7e11a7 GIT binary patch literal 973 zcmV;;12X)HP)!gDIjvHGzsT8k z0l*E4-1iOFbv=&dz2qHk{kZki;74sFs5?I$-;ag!0h9y4%IFAKCDX6wU{cx2fZ)N- zO$7+f(F%aiAHll5Xa(|!!?v+3~*ArxT7oR*aN-nMOD$4&(h!p$LB z_|a@i1t6?Y0EtbrI6(na1Hhy6Yje-c&e;l(oj`#d0Q33{IP=R9JBA*=&XG01pe=9j zj|S%nHNbHSKm!iX&Dk;foW^6M0yt6t%zfXgLC9r#DggLU016I1tw78gpu%bes0CVi z-b>E?GT+V$aBLr-wiBo=pk!g`SlI_4cyWHQ1>ot}5nJ9ACi?(RY5>mZGa5p8jB>Ad zt{rNCV-;WpIG9H7ITfG-ZVs*np#6cFc2QO6B^97^PU-8?_qC`Mqmt_^)^qD!K+B15 z&Rt!XV7Rr(K7eqpQ^`(X1-j)rl~jPn_@_G`AQj+2gsjJ;0-!OYIUgWD3jlz5Sx@@` z^k)x*R)CpVk3S>eobRP;8MX$PS?Ece>m>-nDS+j(zBY#k#}`5=fW`K%$GILG5JCZxIw2Im0vde11?j5bO$AT}2Vrq=%dXXSXD3hrJSTp( zORl5WTC14VIxhWL zn{c~;9_Q2X%4-(SY3g`dCvZP=w&CFA2-yda1`0l|++lDTPZa@wVXy+U#t)+ac#$O1 zS-xMnSEs?#+1oQqBM7`_ ze?c?od)D#m4oh4FwxZ0!F}nl+fQ_whSudTxsQ^-G*~vL4@a6N88mt0nSDGVu-}=>< zRke@6t>M2SaI~P%W;dsEc)AD9zp9O(8SI$-g&l1FR|9y;egI$DGlJ)JRqX?4a*Fc- veBX=P007uSLR)w%0y$g2FIjF~El`0^;F5g+ z-~mTG&jX*&=j*fFOUU5%kK0cV{J2Siy7SZVcC2tdfO7z>GWrIrN~T{=VOrYCfZ&0h zn+$L{Ud;e_eGhgOmDBq=TXbm9zAp&U0bfpJ?u>CTKft_|qD7H%Wa+!T91H8Hh0MI+XfUELbvayb=0Rl3>%-~A~ zAc({OHN7+#TftciUM{nf0U#y=aG)K46Fs-K0{YyEHNfi`fZA5O2VkEWU~or8 zGC%+Z0Qkv4s(^j>rt~+AaX#JL9ZQ9|>F>2$8#hD;S^$UN&>{0S%G?oX}!{ znqA%j+mi^%0M2&JSZlQ*A_E-R1>maPVwd+?EAU=OI#zW7$4vrz929{8sC;QZvIc0# ze*>i9)2ie22nMiHzE)n5$qjFIBN>3m^mab((+hTYEEw4ZfIsDHoEs$wu4aHTMx9xW z*YrlgwG7}*`B<(N5m?|l2AG}or{O9Fn3eTdKDJS_b~g)L!vLA}Jg#7X70#!@XFZN~ zvA`AI1+2_`Jc8A3;?5%=zYA~x)@hyg(Pvj5Q&%v+%Amjw)DDF3+SLJk1p{a^(K<({ z$+v7A?gq57anSVIOy#}43&78EzjNzqYq8U)<9as^Ka1sZGCA97x+P{=)dhs90W2>_ zGmXpEa^DNBASl=L*l4{AekK_J^t4Ik)u?*bnav#oIGbw>P-{nbGeC$*V1f0hz*a z<&D_jVFwr7*VF)3L~uUU?|DA2ssXkzzzC?E-2qTQZ5nykWPpbJ*7Z(!+jeCapw$r- zn*QG+D;a>uZe2&jh>cP*wOULI%mF|Z)Ans914PdL0xuS@CR1-9sEfds@KxCurSg}s z!cNKATHQ?s&{E6^nYj|P15`UQ*Q{e1AeuvG43TC7+Z$y+xxM?x0HX!P44mR{3hoQ5 z-QfJ|ItZGDh=U&uPGGHnUj{|Xet?*n)PqQSi}%rW4&aTG9ZnJTT|x%{K&;HM!gDe> o3*iHxAZiAkj$;DgR74NlKcnQmMLhC)i2wiq07*qoM6N<$f=QI&yZ`_I literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_12.png b/assets/dolphin/external/L1_Doom_128x64/frame_12.png new file mode 100644 index 0000000000000000000000000000000000000000..133374545beeab08a20c801467dee2404a503d0c GIT binary patch literal 1138 zcmV-&1daQNP)ob}AR+^- zI6G?q0g)I$3OuSyOE*dPtN{c>WB?Ad1DM%QugL(ghXH6yr*Z6P^-tw}69brzf=^%o z8j!O=K=*nwfTcZ;X8?^(6fFiAbrNQrWPpGSfCEs{V}=nV8F>E*3~>Cv25L~xmK@Og z9!yghc<6p4|Jrhx%%m*<06U7hs?dhQ{gKo;T0Ibq5+G18e}Nt3?pc z$Vdh-)Cpf{>(<(5ssCsqBm;EL(Ny=GZW6Gbs{*#3q0!eXnU3oMI3tWWk8AlbOGv{V zD`9z4Y9t+fUnB5~g*1N?_3yQzWR(z#@8%`nLVISC{(HNa;|R4Y~a z^fPWP{%%yaQFy#g0fIBYjDcIj7dp+OuM7NH@7&eh&D9K`rEkyqg0`-(!nF)AO8IpU zzL(@uJ*Bg`Hq(2SaUBD^DcZPqww1%G%oVa*xQYR+GE6GaMh(`h1w4Y`nmND@rXA4m2-m4b4f&q3oUt>UNLg-ltUcmsC&^TXXJZ?6?$zKgGI~IU_ z|3ioeMqdXzbmY#yq6^Swq;{Pocf?>^JF2Pr-^>kqGl^^F02%|f*yN4lTj$`jTJwrl z0mlH!usQ29S*Ux&4^3`1cx3>p8q^b8<#;SL> zR2b4V__KP?=~eG%7{C%?7yv;3(=L48$lkZ$0*~q=F#y+A;wyL7RSbZQq-6qp?heo( zXfXgq6b3MD1AB#wRg1N=Riips>cQ1E*D!z<5u8uYUojy1Y6h56lJF!Z)E4zT6?5JoBhu+9c27uVvFTp~`UNW^>%n=L+06m!Yy(<_Xa`snPv%qLF z%?5(H2y6*oot054{~kQ`>^WPjLz4lt6mvp`dcZ3{wSzLvI+g*VIMi}@N$viyU=b7kxgTKV`X>Y76-f`O`!H+nY$!4p3y7 zXp1T*kC!sG$2?HqNq~k<=N3;Oz|kC_j-Zk9v=9OK_m)!XI|_yi5Xo6^#IBe62q#1?u}rfUhDFfRCqLl6_i#rAz{R6_o%z&a3T0Z88TC z6qx`$ZE7kY+cO7H6qNv@LhX|Pf=&>i^evUM&eC#&BmmHE0$4J8WTT~?Rv)!V0vyT# zdLyhp!#bK!DmlWP|3|SvyPrtw2ZuEFb_vyVPEr)2zK(KS)Uc zMZN721?oPmd4Y$J?MZ-+5-nWs8C!p^Ext$O^OENrnvF>SZmi+V?`_Y&n;m1+E}|rW zDe`;UN$ty3Y~-Iu#~CRl-y{LZKO!Ytxa~WY1ZbR@t0E44P6ABIg8-vBLQAM$?$8qy zNCJSf+B*`p973`!2{52h0<4O9-oG?1zqgYDNdQ)7WuzgpaGQ4L0+MfDL4X~RCPhEL z$Ls8(z^e(cI?}ka(AkdcLVY9w3|jdna73IoRw27r>D2_-QPzK7*VVkFwn+ekdI+#f zTGp@CKV|1@2vFK+rL`WaU#@bFTOC*Gaw=%{^x7%4uWfid0eEDh?3-^O?Yu-|c+QLW z+j^fM)kSvmFmWj#n)_ zSG^I+XN?4W(QA8KzUe(qM-+wtb*bIw->rxWi})re(l&8K0))u{L<517PA`5f$%eb+ z0InOLWwd947Gd#=ylg=M^5`63RFM{+Xw7d1yK;ad1Q^w-4do@zdGh{VPk^Y4j^ug7 zJ^CqNwEw8`oa-yz1N8KJH_h7I3a0W-M0z)3Rrh}jM}xJ_ERRhPJ^G70H~q* zLgB5uEjm)9IiU4*|1H2;t?2#{l>}ca+Lb1_%l+vXcSIISjx>b}~ST z%K+2?d(J2whhvff{v#p-a5`}M;C+eS$pC<;3_x|OxbOSpL&uEt%^aYChzx+ZuB-Xc z$iQPVK#9!&Qa!59l3XDf0I-4qkjjzPsa{f0R^W91CI&EV1xIB7i}`zwP|v*>z;Zpe zX8?&l-1og}ir%7gNu=Z`K{CK(Xq|F29-V-Gmkbc73aEIJ{Yy|8fyzz>2*v>Dlr!|h z-U9tj`g}5gp2?h8luCQg_jI#f@X=O8bxH z9H5S$We80Pwi3rNz>KKxVbl;>jiVS~cGS~(q*%=Y$1p&|3_JpkU;t0!YZ5)0B(7qC zBl-ZVB43)5tYoI_0~mpuS7O+jl-6@^XE=fZJe{J|1R9N}PT+|n7(g0{+CD-{zGmUL zw(&?db(*I-qr9)L0_d~cIXA8~7CU^cXEdPCQn{Q=PPf+FBWCfc0>b0~nis@KNRc~y?3F{Bm)#VZKAvuRnOY9xov<(bBh5uwm^9lNAv*@+O2}ltC8^*xGhjU zxNEMz1uooZ+$c%&M199rl-DtMZ`334aDuB8yMGipQW}kCF`uQpH#%78 z!8!LaIe-=sjF0nM?$2I1z!C;{1C+Dc0V+_ZH}9GZ(2?J}UI}a6j;sQtb3}!t{@2J# z1_0T;>xg)x<0zPVC8h>y2f&H3e4EJtk)yxDiUqX6^wbf=NnlU7S2RY+{73N6b7XAk z++7BcQp^sK>5176Ds7od#<2_#&7d=yNV7rpjk2EH+I=v<+k|2Ub}=}D`@w28IQyD5 zf@UFN<41xWSnK1*plH!wO3X-lf=Fvi*U_{OV2zy(j)?j$p&g)|PQjn>506s^4eF~l<$P0RpEnAw8lhB#*U%ajbj6<%{XDBE3S zLR3sM0B5kZMSmjo$MY$^g5I z9~p5SASbf;QKy1e1FTx~MN74)sAd37^71l@86swZrU4MPd}%vpZ3GmP%?36Dlvo>~ zw~QPu3p_p&h7kR&_R0r34r45NDws%qbZlXS@*H6Ys)ZoS=;x;I-Zo~Z|$S8OIm>`DXx&wAK=z)7CM8KGU{=S}7W(Fcf7w_{RXV7d4W$ z5KIsO^9*1aB`Zx3#el<)gh?6M4%VLXnJvV~qh`qbZUd3`wB=y0>}yT<)uxodt^=$p z{jQ{^PLbp3eZys?U=NJeE@3w>$yNO@NpQrmX?Ek&yrPsron5kP?th@UiZcMhdJ&zvP;` zo%y#g%>df-pL7~nDLiTxFg1YHKyw#YC*q&!HUQe-z4gaxrx1;>g`ioYm+9P_*}@vY zl2&%{Hr;%X79_~@PAT3VTR$1#g;62Paxf~#01tSHU@7hm(0YYSa=qxnC)^s~ZB8Ej zK$N!d=m$bB4bUT2@4(NBc*H6okwXJ;1Z$aKcB)4dp9s_dnpM2g1iQ`gZ*&=8#Y>m@ z->DB8ub0gh9yRqRpgs^$6Da>MM9=?ou6^kIP9W02aaRAU(>;3h6M?P)TGXb8lGVa{ z!kqzfkOlS-{X}4EfGBtopXeB1dyWB=@f7_;#{jB$6Q8K_Tfv8SJc>_rGJpzR#U~>A Y1_VfqkSHR&0{{R307*qoM6N<$g5X(`u>b%7 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_16.png b/assets/dolphin/external/L1_Doom_128x64/frame_16.png new file mode 100644 index 0000000000000000000000000000000000000000..6aa7a7dd328af467ca5aa59a6739ef8f1c8d311d GIT binary patch literal 930 zcmV;T16}-yP)p1on1bv9e z5dhA~RpWUcv9fmOwc?>Eu_Z-|%fE)m^U%Zy;DwnjNN9*_hHs`sfL7rphlBXJt4xTB zY6NI$Y-!PR__|ypyiqfNa}G-Qm}`VLDhA+)ze@O+& zVuEG^Ad4S9Ut)Q8f(e=oU_pG3uWPG-arD^T1Z)FX65r#TYpzr3J$E(%%K$xL)bcWF zXTf8JmVr5TXuP=oyPBf99o!Q7;|-PzKEn|p6uW24wZx85plE=TQlh6aoC=-=iV=5< z0$Br~_5K<4L3-a=4DAJs;FB~hjjnA1sWh@Bk_OOh=#=O!MnH&6I}HOWd4L=>;kZW7 zG(m3)*(zPf!h0Gfm0rz##>ppW_QDf{_xy_h8oetNG|m;2p2bN(tsV}nGi?ay?Nzm5 zAq?3w*<~K^H3ZDw@oN#S)Yz#*sn&&=h5FSn$zD<`>%_#=DBVNAXan^Aes#m|wnF%e z0LT-nc+$91fYfs>Uq|m60%i)3+n1kNht`#frTd0#10W?xax;IeYvrxwTDoueBErAP z%Rysx(pzR20nkmLz6waKmo@(mW(4UIP2szvnt){h$z>e3JpbL)Z!|NN(x97Q+Mh(V z&K*)S|I&AQ>m*T54P+C%v@0bsX_U_N-NUONR3m`&ieYqlwNiN0D4=Qpt%h#hh`BvJ z&yqiil%OW&-5BD*x)@@SRaru7?PWFstfUlOtPM9WqzMT!+#$u;{LlWB5Dbbet6W30a_=k+=idk;}Nrf zM4$#Jt*u)(lyWAR9qJLqCjvA;O0bcJi%oFa7+(X*0J+{;+XO-i^{MBg_I{$tmqTmR z#0k#=#)+AdIk@GYNb%po(Hji?93y(~Cn^j9=;9OEs3SU1L%>d0=>0_304i7!pXeIk zc&-72vDEvCt^q``CO*+MfEX6VCn^}g+Ka5js`x}izx8vkrid*Ood5s;07*qoM6N<$ Ef@X@Ud;kCd literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_17.png b/assets/dolphin/external/L1_Doom_128x64/frame_17.png new file mode 100644 index 0000000000000000000000000000000000000000..edf9ee8ba37f0a0b41fdd2587bfe0132e3a4460e GIT binary patch literal 937 zcmV;a16KTrP)+ zL=0eA_>>b(Fl_+zTHniQCipk=VQ=CS{eCA)W1eBy03OAUoMeI_19%oca*7GM4RC_^ zkrPbNWdKX!OD*EOn}BTqOXBCun!&RPSO&1TElS5cI(}>4d4#ELU=G?0iNg2J-jeWM zvq1B4u;tWGG&U};VwVuj07QP$W=VXH#;6*=`s}~75y=1=vmPb0c*_E>Yk=O_pI@+$ z##`V~5W5rDD@^I09;c6M0$GZWgICu6TD#o#5KQ3Zv9b6rphhcLanIhuL*P-EdK}zC zE?5ZR=dbj?oZCe!OmLd9{xiUez@`htT=ZIByG+3C-veqTV6tBIEd>7QMI zc5UtHs}}6irPNVj@`p&?8QKQ+K3I_oWUDQyemL!TDG#cxq_=KdRYz|ENzu9{FU8FO4Mv5`kAqP$ zX#k0<<=j4y#go9C0b0UHojQ6KK4QuM9C1cd?<(QZFOQlrK<{Fe8+ff5k9Z151ZsfV z-nvJqnhCU1J)-zTfCeZDHWRqq1gF*b7Aym3o~qR@UA`FsDb<(yMVO7LFRYm6uo~K%f0YfNOvrP>pE`u@Zpn@*P;1{Y3XQaZ9iwK9QgS z&`-QBWn8~1b_bSbKM~kA&^p${Ct?`j&T1YO#V5KMKm@De6A^s@0XMFSuvu}Q00000 LNkvXXu0mjfZF;WB literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_18.png b/assets/dolphin/external/L1_Doom_128x64/frame_18.png new file mode 100644 index 0000000000000000000000000000000000000000..fede8a9bef6d808173b3e292a4328b3814a3508c GIT binary patch literal 931 zcmV;U16=%xP)_x_ zgs2S70FuETC3=q7murM?h8ZA)0403NHNrPT3{Vn(weTt22q&7r)Bv?;LKC0!JkOCP zFfjmPt#9E(6LcE@z1C|v%>@5?PToy?qTk=-vF|N38(`-sImrY~29SvFeeg~(f!Y8k zh#xt@1S$iZBz|Of6Nn9PqWF=WO&~JB&J(`V=~@PI(4xcIu)Ah~ssX&F{+qRAm}LNT zG-im$rswRK1&Rjn8vPO8|C8F?9){A)tkfzxf zl{YP~<<$VK^-_`=-$bt&0nH>km4U9ifkbVyYwiE<1a2JNkA$_Tmn$quPM^0Nv+sjVrJt=x1;I#Qh63Wb9>jyaZmA3#eQA=s5c-VUZt2^*UX>G0DiOiW` zcB)4dp9s(ZZ-VsTYJ82N0cH9w%GvTf}fdxwq`!S-*?i~=NSzHVA1>}PY?_NVA=d6FA$Ic@L+zD z2M9<2crri9Is|9{Jer?m83Gglo|Z-4G_?#YWidmNtX6?80G>;~2eDQF>#|q{ngD3e z{yT5!%X9@;F?qFC1*!mO&;BP-U`WSWuOi1PKnUUUTB#i5yPW;6$IHPhv%l4Dtv!yC zTiybO{hwZ+v;(!Z0`!7a`G;t=oSYL}y)}GCQ2uwz{Mjt&L2wEL zD*ztd2beuJ!M78HnTjV-pC5-xFRQJfm%mHk*fZ#ztM#7bIF=&+I`|~{J%d;E4YRy` z>W2mpjyxcOsxqKlncmarc{FW3zW`)+w487P>;YkBoX`6yIko^BCV@`@;MmsXY%gyo znZ^N?hP?vP5U}%t3^vO-g1fSk?DFcQ@lvY*X%a~7_^LotgUCI(vm|r{kVbCLNUq_+x>RfgjcAwY zWm0H^4Gn<_lZawS1vf!VW3i7p7Lr>=3}EQ6tOkV5w3Gz{suTqvw!p z9*5Kc&@*P%I4{O0sR96F&S>dfWxVtYLTUgQ*@VIbe&@Xf()LmSgaXi7TT?G6)gahi z>Lr>FAP|5j!)5|kLf~zT?+FFK&Rw0$y&+wBW$D z?@_3yg-Z<_CaX^0#Vk4d0R+wgD3S`MCW#sXEJ;K516%->NQ?OZ7XbIV05D5a_5)l1 xSf$N;0OYfRulmwxJ^)h%(DtRdrPX`@fL}C_p^wK}8Ych%002ovPDHLkV1nULmTCY1 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_2.png b/assets/dolphin/external/L1_Doom_128x64/frame_2.png new file mode 100644 index 0000000000000000000000000000000000000000..218fdedbe5dbf80882b89df9cd844684547dd739 GIT binary patch literal 1498 zcmV<01tt24P)#>wguUeNcz%x>)7UIbW0yGO&_CCVKra zz#)iGJ>0*u^5ObnfX&bpZz(^!@?Yv24+CriRtjC6oE-kfvf8zUhXFQ$Q|1_c?;d2O zmF>l20Gq%m4?rD3i2>+0t>1&k05(CQb52I1f31EGZuAJZJ<7Yw13~-=QaFf z9`agYR{k5n?dcjg>i5W+^^O1o;4mbMiaI_8UIrLryvS9;#Q+(lc?a^Xh7e@{>JL;w zWq?Y>|7rL!gb)J&s+mA!0Iy}zXQHxn0#3jRpC!rw(3k3YVi}-Y`D{lT2A2VsSm`zb z{5!&+6)f;453ob|xZP?e$7+*)aM>8OAs1~sTDO(~%;JRsb}9d*LyMTeYGcI~b(aBX zUo-e+fD`B!_hS_ka4fKb2`U(X-p}AxDtIMb??lHqGfamQK~>SfKU(1l*x?Uo=$M-- z26%b92lbQonY*5I=2F39e9r2Zl-unCR4{-PN=kKdvOlM-en2Kpj=+<4UEu&`^8olc zP2m=99|pZMq_cQj)@^_lKEN#}uzU5xUPC{p0u%$E6`8 z039qhcxyFyCzhjot3Q?SFhFJdQa#5Q05@3eygLJr(s8?;(3F2?tX>8M9Af|+yvYqL z@7c@YnzqBqbwOf)D&=$c-r_7EYQY{@;ph%ykc_p`!KC$YbFke2sP$)+ZcQjXB#9q!bKQT-IWO+30?-E*VfoQ4lu@B8Gtr;xNmv-r=*{?D1c)J zxYpPpW2|8V=uD1C?ExgkLz&0ZKgAF@NwtBcDrt}+a5 zo6$0$Ts>O3RhD`oq-tLTD#ITN%K`GHRINVmU^eXxLb^}uz~!0#zx8Y3o>*G*fbsnf z<%3e_hxVO&PU|n0qt31eSa$m>VV31$=Z8L{t$h5P)&`d+sDeey-Y7uw3p4}rGD6w_ zswc}@DOd)_|5|@xxMZWDL>pj?S5cE)arC7Rm-%1gINFw|oUVQ>BQb&29tK=*a{?_77w&f}ZPn_h;G9EF z;hf^Rs0d_eUD_O8*XI8Q0#+$my1!ca0Lch&->5A2EM4W&ecJXIn^VC%v0M27sSlFB zz!`<)8(3lSk|(35 A=Kufz literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_20.png b/assets/dolphin/external/L1_Doom_128x64/frame_20.png new file mode 100644 index 0000000000000000000000000000000000000000..efda32966d363c04d85345d37a0b943b37269516 GIT binary patch literal 1159 zcmV;21bF+2P)=Kfdq`yxe%1d`C|asP&4v6|L`a<$g( z_Tp>tiQYgp-1qvvT-W8a6CJz+VBo&*t$`_HGT~qJ2C9H+*z3BsDv=4V0uV486f}>Q3BzRrG0=y0VpXK1dd@&4EYoiq$9v= zc&?$T<0?QboZ093gj$Lz-K z)}sFX3C5)$i~t+@S+RIGXbRmqVe2GGW-yV#)< zcvP@zk3b#nl|atzpCP$r9)?-%Ygf;RMkxj025P(UTI5*83)EhMD7Y%X$?c~C3oNN0 z-fC}{TZ$$`2?d~L3)C@`wY27g=E?M~;6?z8+b>NcC2Ne(ELKJL50>Z%I*GC^KJ1tQ zoWjE`uHZrdt3zfzMS}aj^$F08G8!j3(6IpYe!*!Vh31POfm#-Tr9#mXH-p&OyM+sp4C~`7C_4a$c25JLKIjP{dSC9Y}A4Xz$s==tYzoOgdO1UF~ z^nKw^5NHwUOXj6^=}PC5)&o4S>LJ+eo2wYV2$0426UWLm`#+_h(8&xD!-I?8@LAtpeD zn@@!_g2v|Qb3x4_5cwj%Wty(w%!FDIW0z%6Ga5)eJUXe;5Fi?m{B!ylB)=V@r9xaB z^#p3MG~?}`ORyM5Ki_|Mavt|Az;(5xfU0ehU{I6DUP^G>73}4!GN9jX=)4(KjDi#j z&`A{W5JSEFt8rD0-cPTj3Etm1 zu{;i(C4{PzadIG!PzQ>C4x~@qxiN%iq0^Ik_3Ru#nB2*@TI|U~~D%k6~w%nhe z1{k0hC?(*BAP)(4(gYVMqX6#$ciEtJo{!+EdG~ADWsLy8C;&w-Ku(yus(%0j0d`)j z1UsGH2>g5ic(?7}BzyoP0d{nDC}8%x#R+R1AyorZCkZyc{2JdFgY1i-WeC)hsr#`+vR&$YKkFnwO&6cV@y5M>6i zq|2x+H5W;y{HeN>310oLcqq!1N@qUzyK8;Rg7o1UGb#)wOWiMyBzkqOu(vEelr9NI+B^LqEX zh^idSkzn+>=JbC|vY<8q7|)B#XH!9f zK^1TMc)aY4jcp@`1dzm=L`m zMGJox&?|7D%mhlHt@1^Tc>*FTtD|;U8&M`OQV81EentgwCwT8O^k6kWMDCtalUD!2 zJHN`nw16jr$Y~T(14L{rb@9WR$ic!tY;h-&LJO&BKnai$w?EK0OOm3_H);tEnlSu> z0NF(mPyf=>KdTxT4Jzc6!eT1k2#}fU*7PkEnDq4TXg2z+tRy72L=kVrpeT55=19F- zYk$^!zzmG;5ODLhW?x_B;3#;nWsNjOL}E&M`e$p2K6@&Sn7nECzoFNQ=2--3~C*9dC|=Q68C;QngZ1MlLqqXaD>K62&)Eo0q}m30Ky z*TVtUde7X3O9?@F&Ri{{@57q!SPAnlgaE_|-x?}nPLf5{TTX62Hb#aWNMQPrD1h}R z|JmU70*kehM!nYbLy?i2&uWq^|Cu;Tbx>-fHHfTz0O&~2KBFbE7t0B78oVT+`t1Lr zVDbT?>{|tMl7Uv>y?L@Yik765sTQyk`cvh}I%WVP0XG+|x!}f^JYy!nDlfMk7xU^X zX%md3vyx_8Xn@v}@86d^hrKUFOO`g0h(^1{X!{)j7Xc!)fHmh{Z6inERQpK%OA10B zl=K0zbMC85g=O6Ag3x8D1zWw@D0m5h&38sbLX8ob!_f9sQUh@CXo!`LB9*}M<_SE{ zh7e$N-g{-4)&lJE$0{sM1Z5$rOq+o|Dxe&{S)?%e006WdUA@6p%qEF6k&{gXb1eX4 zDHYf6fNI2@l{*M`0x{-R+guJaG?`S*_mM;N;R^YO5nQ6Cx>L3TvWO7&bMcm&IMnAA uP}QG_CW6ZeeBg}=Dw&IF&L9Ub5&i?q)~b|h&F*{v0000xLgbx9P)Yzj z@miv#?XBtBY4$Eb839m5mr+{^QeoVII4`6N0I&MhLWIX;^fYk1Bn_0Wr zSknLBgpue6vHJO+EROUTz#FUE#SBfr z*uhRb1Zvn?3Dm6q9+p+MgP760X7!8;IK~0Af!eISmpDf8g7hvyCbl`i%IcSb3oNA{ zK5A~ZjVd!WIEUtbS`6X&D2W|2Rv}db>uDkNoHzNq@awueC>=ohg4$C)k1_9nNEe{`6+1vi z3fH%fn9EbZiAv-E9<_VUCbcEqQQvogw+oE=8ajZ-hvhDQSPMB+`WI2KxdSAb7%PB? zyuCpaEJ+S^p6C)YNYijq0MUmcEB#AX|E|+OZ*VE66xze4Ujm5uFc#vagh^NbiQ7hV z%9#*W&KLd*0wW@QOTW@vy4L=z^?)51-65FG+u|5M0;obheqOS=E#pX6|8AG)tEbY8 zX{GG`!5yr^<38SOyWp%`LzZ>h;Mzq(;{Xw0eF+YOH88}Vl|NL1y$`hoPy~>$O$W7 z3NF~=fUktLXYun?se86}XNsi6t>DUnl4ci;XzG4|#tC*^3TY^RDRc)Yaxj_H3a2ny z{X0q3z$^f-7pl1Wxe}}9DjR^3f?ESq5e00kU?Lv+nuDq0WW zS<=B>FbSZ4ksU9Vc?h$D>Tyz82bf_+5E-j*8pQ&Aq|5#9DX2m^hRdBmNkDjN9v^{9@9MGzNJW5QjneOcN-p3Q16V|W f@s#bN+BWbP8(Bz1?ZwkI00000NkvXXu0mjf)>B$f3Gi@yW-nkD+;`hkUe`5fCAoMBpum0KqJTAHR)pFGNE&b|w1T~^ zYs)iwEkFZUpqzjUK?(_WvIG|x(!l8Eb~>DTtwr$M+VQ@2+UJ`E5WoVIgt@Ev2QU&~ z=Z$KyllErdjRD}>w?9ev01g7|80fS>`R^L1?2|(`3$O!8s5RoBwJxt#jGdIkMSu|- zlv1vY`L+4I^_iWpTnwN|xhPl!6A|QTB$NN3);H`vthar0^sv)5$)H43oNy3 z?X@<}Ev-U`k5!-}7p~0~v|}{y%9@XwXT`q4^>;1(7L(!oIjtUjRXfv4tP))R)QedS zktn;z!PXf-6eHZC^nQTqN?2J;=7M@{a+UNeN`_e^s4dUeoxu7sgJ;tEPnqvDQ2h(b z1yX9hnU;Xf0xZ?NUz1k;Z3RsQu-_M;p5ug{(bO6h6X18SbpTC~V<&jKh17G|!XE|l z3LF?e7@~o-%a`%a6JWIh7FWy7tEvQMr$3fCM|1#pL8QpVja796t>A=)&7`%Y+nW0n zU@H)<9!eI4wE!6h%U%5N7ILWckGpel3cNv~);*8}=#jSm_#6JS=9i?ymo)_Sa#2@^qb3;4NgY-0h+fmkbQoTfz6$oglmzotmgBJFI1 z2#{d~yfya~w1)ym0_mL;sWr`@D3*)?de__~;Y8=BNZ?VHC7VHbBO_vgQB9akE%R7{ z7BsDJ&-$0N01_gE=&k*DE~zpYE&eRg4xU~2&ae=@DsU}JFr)H^F|`oX3oSy-?qSq_ zbAjJTLZtndF|(Q6LNULRYv}oY{BQ2OMyHEz0<_q>DiI`%2xPUDzEMO-4+5!;uIegA zqgEPA$=5<2D^k8KTq@M`O52`-o=U2 QwEzGB07*qoM6N<$f=Kfdq`yxe%1d`C|asP&4v6|L`a<$g( z_Tp>tiQYgp-1qvvT-W8a6CJz+VBo&*t$`_HGT~qJ2C9H+*z3BsDv=4V0uV486f}>Q3BzRrG0=y0VpXK1dd@&4EYoiq$9v= zc&?$T<0?QboZ093gj$Lz-K z)}sFX3C5)$i~t+@S+RIGXbRmqVe2GGW-yV#)< zcvP@zk3b#nl|atzpCP$r9)?-%Ygf;RMkxj025P(UTI5*83)EhMD7Y%X$?c~C3oNN0 z-fC}{TZ$$`2?d~L3)C@`wY27g=E?M~;6?z8+b>NcC2Ne(ELKJL50>Z%I*GC^KJ1tQ zoWjE`uHZrdt3zfzMS}aj^$F08G8!j3(6IpYe!*!Vh31POfm#-Tr9#mXH-p&OyM+sp4C~`7C_4a$c25JLKIjP{dSC9Y}A4Xz$s==tYzoOgdO1UF~ z^nKw^5NHwUOXj6^=}PC5)&o4S>LJ+eo2wYV2$0426UWLm`#+_h(8&xD!-I?8@LAtpeD zn@@!_g2v|Qb3x4_5cwj%Wty(w%!FDIW0z%6Ga5)eJUXe;5Fi?m{B!ylB)=V@r9xaB z^#p3MG~?}`ORyM5Ki_|Mavt|Az;(5xfU0ehU{I6DUP^G>73}4!GN9jX=)4(KjDi#j z&`A{W5JSEFt8rD0-cPTj3Etm1 zujx7WZ$Qr&3gqbAXV&jT}v-f z5f>J;5m?P+tM3x;hQ80$0jB`Apsz z0O2I-jezM2IL*ziFk0_Z_9R7W3~&NTu#DK1SC`)lGXb991t|IP-=%l^cpfL6P1!6! zl5%b->&s|S$C{Z#7*5D>t-VQQ?@-Q)2Vl4w23lawpLk^mA5 z*LVSqyN^oIG@#~uGATq?Kvb~T=a48)o1*pkGcbBAEdS}`5cdLBimT8N=?cnH3MNAT ztpA({RS@V6_%tM`YGoR^P6!yU)>_jFY1x>T05eF7N!;_9*2=9_l?WFAv}~qEDxU)v zSW5SmB^#H;R3XF{K;6cUG+U59BUvkIK5CwdeT9#A0yBj2SpUkZ?|xM~(o0k^x{oZN z3sohe^~jQOu#p+Y9oOP&eE=d2q;g%)A{m>kLee|yB9Rz94_gP&3O44$)gxaIsQ!hf z-A&E6(-Ww_7l6T)PIqq%L;Jn}HI7q$L{saom;kR~>IPO(ss`3>AvG>q`5tJzEk!Vu z2as-1+vST`^9hi60Z*NSdRF8CqSGJEoOf37s=`}9nvrVh0X+FTo;xcLO`To6pV?JcQuJ&(_mkOS^(l*Y5`a z*c&~s4qQqI$sV*diAtT&8O*;T1|UxP)>M%Sk}R&?qAa{NCKMIORfL)VRV*LpyOy@> zEP~dgqZApWB-l-o?OzYKbO)(ohxZ`0X&+_vc?|gksz8BluWBJ$Nr*7yg^UZ(K?=!3C}CB#_0C| zIvK|w3T6UC3Ts`rTb3mN%)%_N?6PA|u@hTkfbl@^=aO;M=Tbyl9F~L22E6HJG+YFT zhy|=Q_X^fC117-?GcsoP14?EA*){jO+%G0UMylG^Sv|wf*$fgzMza=p31O)sda$zM z%6V-0#<7cL4xogkSmA2_=GxLOY#Wr z7(iO+7*UZBcN5mDz$hYw{eJ-z6l?LSMz7bUqXt<8Y=CMAG)(WP zm7O_2aI}%_$pDr}2IxT2JsAKHg#plL_kF9KkQ&RKCj$T?Fn}~?PY=q_*LAVke=-0d z3IkNkcDyezz|uZ|HK-`;(K(`huBS7_08jb=ob2oa80uw-o^i7e@S!SzLgoMrA~8VC z=AX`8b(gAw%mDyiw57@BE#^ZRZB@|T-#G{P90SbUZX^Tl$^f6t0XT;n?E`4X)$_~& z7BfIg&m1@-k5F?RkA_bM2*LmoFu8l1EK-h;3=p6SkbsGtg?{J+^%|8MXyqjXYzA&y zNCpVP0O*WVv|503f`|;TWgp-TxJ8uod!j$~45Ib{KKU)6H>Xw~YF{7Kqdt$@fVP=6 zdp$p!1H7HndP`{YgHrxE1vf`BfFNHx4##TrXrGy};M(oSivhOD0iG}k*P!9<v@~@WAn%z?B`u zm2;yGM>4={18}mXIjO2*CXQtQirM(v((?zIBslfG&J0sZX_j_l1b^t%}sSDTO5-EP|s@S zDdqpZ{hNsIL2?4@7jXJe@4&6ikqn?UJ{R@vwOM;NwGFh<%rOAP7AUX9k)6P&W!q?i z_ZGM=2ornC+n2mbqpe$pFy|I-`j+8?C-k){|Ph9}Ms|p_qYP433~aSgi(S zU-MrC%|OJ)j|Mxi){l=t(W1YUn341Zk=C|dN7FulHFh>QBI>(@c7Rf1Mb0QJJA<tzK$OuZAS#*udJ41BRs{qP z?A&62!|`bb!1s^h&6-r^+%j{x+mWKhb zJuARv_O1-DWfvfUbApx50eGEe_ZPZ=SLXmxSf!g|fSEafB)e*Wq^KG|K&Bc1s`=UA z1G~AdplSdCZ!!R_(mixi8C32UYJe>n0B0u6(3NaMpXCb-@W~oL(l7}Z%dz{@oN z3~e+UN51EDNUXCX1AL|iutEyRnLveSqcex90TOfpJz%Fq&(r`O_EDYMe$*VGBVW6R zL$A2ARQO)cAk83pwyg|;Z5Y5p;aCSp<#c9&V8#L^yk$x4ZyK;fF}<*({FP!w4zWeG(B)619(OFZ0%r`O|Mt5!f_0+ z!ud0WUaxb2^$|FV0ivAW`(6VbEw9Eg3=l>8)J}`MS@|A_Vt}i)`2Q0aRY_C302cjk z*ot)?F$b__;z;K8D)feO4 zbZc$uF*N|U)}p7i_DlAYjMvZ$0=OQTOyV`g0L@ODRGviDtIlrj7{J*qF@V%wzRdus z-Uf~y6h3atm11_t%t)*bQ0vItav#e8*&MoJh_o8m-Yomc?cEOscv?`b zz%CA_;9gk04bH#re-X3-83#WW?7&(-UIt~${?>A4(hM@~E#61hIe<5Ib~r`WXGt9Z xt>wy`QFu-US0Q}>0J3J#?${;(c18BU{RjQP7)HxT6_o%0002ovPDHLkV1j742wwmI literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_28.png b/assets/dolphin/external/L1_Doom_128x64/frame_28.png new file mode 100644 index 0000000000000000000000000000000000000000..e756f177eca42ebc14500853a7d3b82d399fd151 GIT binary patch literal 1101 zcmV-T1hV^yP)Gb^@g zL11y`76Cr4T?Dv22WZc%-xW{qi>6_M`9lIDBzMypK1SX7xG($VlXE(3XIl!P{x=rCm=Y!0U1VG)c1)r)>xF zbL9X(%0PhLI9J;h0SwAS08i%M>rWfM2q3hR0HcJem%V$``e;8gS7>Ds;72eqrrNfE<2?)S#w0^Jk(UTU{p1MVVL^(hY`Ka`epl4$d zK*&mfsL9e!1|Hir+Q{ccfP^_fi{LBv6X7f6QQt)XX{;lo*7~>R2%|Q$XMUt2fT83s zZ6$z=GPL(|+flpGJ{?hNeHQ_mk%q|Ub&)OFb7YStk0=5FtssCW@(}@0_RVdTpV4@l ziU2^71n@*YYU{Cg^qqVjsUkp7hx~%iU3Sk2oMqZvOjK9&)(6qRnbpW1PG0MUUHjeByBGO7&JqG=*Vy4{dy*D zHJPM7O@I}V&->-SpXWLJ;cZsh$4hN)UQd7>(ry7q^>^Bc#{L8WTAN2; zl2qW|NxL*6$oH_!%?<*j`S$_PWFTB3imY+8kg; znVe6w?v`*@4sZ(rrVL#a0a1!{P!Rz1`xHfP2d_T`%=DdA(a!nAJ%F{(rzyhbQ82YT z5q>u^BlrIpf(9GySyvZ9_ULbljMCXlHSgHwB(S&2Ry*e@3xH^!t)r;7+R!C{6)jJ4 z&>Lj&i1h! literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_29.png b/assets/dolphin/external/L1_Doom_128x64/frame_29.png new file mode 100644 index 0000000000000000000000000000000000000000..cf1f5278786c76be112118fd296403e554ba2982 GIT binary patch literal 1035 zcmV+m1oZofP)17(iyO8GyQl9)6!Ns1dZOf z#Q@2%ivfq2w z01$%#q~OX5?JZ_80K{g1)hGsl7z}`;bZfdc`@cmo0K{ehYg%VTF#yD1fKw<2fLIKG zDcuU|QBVv3XBhw+z-vtH5m5{Pdl^8wlV1f+{#zN~f&*^^^^=GYAf5)bKBLX#=>$jK z2f)xw7|WPl7_OgnVI?`1(z+&|_?j3%3%uK&28*k(>o^U;0MdDGtq0(b87iow7FBah zN%dT*K`I8|B5lrCmj0u9+}3}v)8KxT+`f%#Z*!1PS-?O(Rd11@sh`!m=_tiK5>hch z!;X}0WehOV*D60H18~&60;6N0hnB9TI;-JQGC+femp_$Z4cN4OENqyL0aifDAf%mY zab8WPqkSed14#0zdae)kn<_Q3v=}{e-}guRC@3uk=s@M=(ynTYJ$kk;`%f>cufyL* z`f%-)1t{cTNS8U33@RO?p2dBsd>(%&S=v&AVu1fx6+m*k)gvqLz%B-;e**)6TA$Ho z@^pd_3_wxkQ>x`Cd$xX74^7FfN!l0ypqL?T4B+kIvvODIVHrOq19*9OG&wWlreXm1 z=oST5l&+DHjsbQXWF|M?iCqkE{EeVh254ha@-2*X%0bfH1MC8Ilc?#xQ`eOD08j7L zx&E!LeQ-`Mq4n)$jP$YUInuk0zk>l>kANpiTMQ#T=ec`(8NFQXktX%y+S4#V|Lp9T z0H6QbS$4Vwm=#(br4RQT*Pmv9Fj;_hVtB#&_+pjeF?vU!+Nj^!`i6A(09tUAeYlZ(y2V)G1p>%f&90?<2a}+U@%5htYErg0C?B#Z+N1!w3*svRDUTo1M^kz=<;Lr z^=0(k-{3K4>pIS6Sn42f$PJK8NhNm^A^K=11$foNOmC^z&p}> zis-2yhgFgLEU5MS2m+r56f5vHqf>}72g<(gZv?Ht8+U(0blpE?XF86R0!3+#)*c4f3W)(QRU?dgx`u}VHbGM|{k1$@>My}#g4PNcAYzq~g?uBB z0cLr*h2Ne*R=`rx{~Lf6ISEmN7&$Id48YH+UR22V6i5uf+g2dN06j|c3LD>U2pR)u zg`Qb34WLr-n#_|7!3wmh;nDx9m_RiEYjM_?Y+sE6S3{eB*194wfL17~gct*4AG%_3 z-e$~%SCN}-1pK?jLQCoZJCx7oU7ZG5UN-YQ&OYz!{e7_^{xN`4Xn3^|(A=5(qsTBG zFALMyD!dF}_L-lNxyuMvBJ-S5MR3#zh)udn!Jn?6+2~~e%?MDARb1k2KV0xB*uerL z_4FQ$Fo33b%Lugip^E`N$@?u@otXtxFn}gE$_A~q_H&x|6IQYS8Uf$L6?K5f`uI94 z*OPu3^hw^&;pO17=IdpEs&)O&_I|Cpb|O|XVMdwwBav*y(tP9CI^G73BJj2tYO)i5zQ)7TiWH#y@P{{yz zPpSk;CFE@e5cPg;`BAy=Vg#dgfDD6L26Hq6^ah^qU<4IeK=xUs{?lRr>lZ9|rd7}R z4)H}r44}OU)MWDd0bv>gSPw^rG5ZH46-*$}X9X%5AbX5(Ol1J8?H#BZy{*z{E9wA} zO#IH*Esfh61Dr_JQZ&ssu8LiH7y#FTeIkZ|I64T7ppr!*Z`!Jkm@IwM80(&;d?{6Y zt2zKe+5l|JKvKj^hO(3|F^<-5!HU6-O9M5})B1T2*F&wAylPksAQf#acza^?JHi08 zO-4^>ZQLs(N~eA^gVZPk&^4_|>Z^_8z@U(DgaHt&nn5&LwiJhLnlY@%P&5XRl!#8i z?;#|aR-CZa0HW4g0Wa-ZZ44g$djTExvDRrZY`6|EV-u(zK%Ws<-jAEARVcM_GvF!O zTccH=%CP1~{FA7x^7(yfqgT`?BFB|v2tB#JHGj$gPOIEul?x$xnZ`D&pUq+bRCo|ug&T_jBze7M)=^kT zjJ7UKj@9lN$kr@?N8uW+MN=a0OpVayD&_OJy!Zw0qYU02EtYX?|5^}-GZHs0BT3lcmP-I_Il|V^AB|J~T zK3+N`<o78XI(MoQEs<(G=Z9Rph7$BPgC0U-xh62Z(W4*&oF07*qo IM6N<$f=ve6N&o-= literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_30.png b/assets/dolphin/external/L1_Doom_128x64/frame_30.png new file mode 100644 index 0000000000000000000000000000000000000000..1b16b867ad77265a1031c071b0cf4e7706c8af67 GIT binary patch literal 909 zcmV;819JR{P)`D(?E$M``m5O)SGHn9(BQ=l z1#pg)0vyi)N*(ui{oHInv;9lU(s2t`!Ia>@DIgSq2K&d&DL@)ox3j7og-`&8xKsfA ztfV|++fKA1zYq%G5SI#|9r>q~B65IGfN5MR0De|d-i>tp$N|0x1(?UB0^An)HLE#D zPyNEP7p!kvclg{1-<`5vIAc0#Y*8dGZHE=Klq=jTQNf*;%} z0DcYBn*~GFwc58{GqoMPEPT{v7OpC~Qh?Uvv?R6XJgQFXZ`^0f-vOMR0wme-$Z=d7 zIdD%eRR5furSyIJ9^m*lfu)XW%bBp$A(jasXZ(>W%^ayE99ID9SzN~Tb^Bg_`^ zl>;1C0PEx1ZBV|jRDk3E3*aVQqe~*`^W3>um22E6K=4E40F3&`0YU*j7MBXp>uaSf z?SHpDQhP%I91;ouc9E8I9{!xPFBD({*x4K#tnGEJ02Yy+Qu_YkP}+`Ep*8M|y?E?U zfJHlYjJ0zPE)_sKo3Eo?n_3k(_DITjoKS$tu`SUY)1?CR`jVDUB$uuEMGj!70H+pT z+lEkpg)vW~Jx?nIIQ~uG3b!nNL30yW1=Epl0$16+u~u1~FMef)0uW=o!iud{3h-nO zaC7tn=)4Ld2Wa&F8nZT!f(c(wuWUB)H-Xe(qj#3}WyuR0VRhb8Kh7Sp*-2n;msu{z zD;oe{udSSmBo18#;7ZF&i}DF@)`hDGqyp@`xS8elqhAY)%P=mK?|vnLs|m#}UR!jE z8|FZ*uloN2cJX5L7jCxwR}OGv^aI=xJsRBNU+hoSdw?B$%HjjuIhX4<0KnZ6%HftI jkm89A5bPs1fOGx<6Q7eF9sFVF00000NkvXXu0mjf)Y_bE literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_31.png b/assets/dolphin/external/L1_Doom_128x64/frame_31.png new file mode 100644 index 0000000000000000000000000000000000000000..cec7329b4d49b99143949f2bd171eb81e1d82a5c GIT binary patch literal 736 zcmV<60w4W}P)NJ-_U@QxY)(;%0p_olbM{2CN`S z3lUXPq}EEMls~`QIWUG>KW;rW_@~wq-5Vc)i8z!9saBZAIDMfv}DHY&!G@T%=0!Z5LxwfyBORS80D;C9tS+w1tbS` zfaE{{k^==u4iq3cUct0|7qA1#BJLhKmlI%Ph@8x&zD-*1x(WV@#w4dW4XOW9pFX3-dN5J3Ls?nF2l+Rpa2v7 z?Z#q`P=EnZjNj0908{QfOYA1mgrl*JG@HaQn>Z|NCHI#8RjmVP^DV|FiaVFk4nP!NLPtbO0y)Av0I&rPkevTvWXcg< SS}n@}0000)%Snp%*~*2J>G$^#Ge#Zr*W3zA7czU z<+`r>N?yxn_6sC)Nddf^6u`?#0lb_Pz{^Piyqpxk%Si#eoD{&z`ObcUMCZQcVr?lU zeD4&%;@tPGI=BiXB7}0~TELP(r*aXXo`W`C5u^YX13OZ3KD-9ndqj`|SP1M$4K4zB zM36ba0$9R5K3^S-KfOFA0Q|#RGS`!^^m?kTV9#HA7SNKRo(>M*7^%%#dwyl803>xr ze)LI5&bPDyjsVd}Fsu?7alUr$6gcOXQp`^5l>-bBK-Bpjo0IT3zEaz$wXM1fpw;;i z+ntH_++I0AcLDTpe#!`-#Rn+ z;+nEVwBF3UoQ2kBol4gn;J)t*M*?_MsvUNqxA#~3bZi{UEWpyyzSuyjH*0oQV0iK@ zekA{}MgVOn_)x}{8*4V+DPKkd87|A8S_g0PgqZ}N+^vKPq#s3`E? za_~wC*(&cb8fsY=J6MYVQI^~iCQS|BB8uyhH+y#953owZ!UT~zcPid7ed?aTk;8;_ z@1SLhv^&yNd7C|fUOd~Or1RE$?aGk-0G6^WH5PF%7eUKvtu=7Zg42$8>i`_X>Hs5p zpLf&4$s!oGCvf)S43`8(-{({jJhB!ryJ9Dme?4LTL=g<#6Zll}6j{iCj`w81r-|UP z9AK43!;Y`CmO^)>B?o|Q@R33+b%CW3dvEueotKOzveMbo^PvyL2++Fkuk~7~Dj0pv zj3{7T()KKScgq2^2C;5A!dQE^#ct=&U4I`wDByWb43E|Us6-5($A5biiWfbsqKK-0 zmY}dhsrQG!AGZl)SRH`FvrhmY7H4r4M(Vm-W}KPS-j>&mKWJ+uEz8GP4#w zSBDZb{Emx&T)RcHe{BC~DL5(u>ev-2yyNesVwWcepgLf^@6bJg(cWqmN((a+OUfZs zZlF~{sZZ)zoRCT>b2f$U9LjrQjRxGc@RK^v_4=Pe5I*??T5`Daw9kt*8ep`ZFSV_? z5Yz)r#ne3cDd&%VmgnA<1em&abT&|b`;;9)RFXG~+7P{mqOdJYAVsjkI_iX=E%L?YQTn?k)#=p8lS^G8l! zDchDIp|u^R3ZS*YdxIU~ai+(fx=s=Sw&{_x)O$@4z-o@iXg!m&kHRI4k`4UZD^&Q- z<+^_VUHqtw7(ZCD(O6YD6qKW+>YmmP*v3;arED_^oIrGjfNi980;Q98#b4-d6qq6C{PxG)u$^00000NkvXXu0mjfPBJ1) literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_33.png b/assets/dolphin/external/L1_Doom_128x64/frame_33.png new file mode 100644 index 0000000000000000000000000000000000000000..5ec336961252cb15c7d5c9a30172b1a2fcd6e723 GIT binary patch literal 1212 zcmV;t1Vj6YP)7wl3z!mYRLKLtHGEH01V;dqK@F)HA3uZdkBHz1U?Qj?EhG;R z5y6Q8CcxwF>2)wLJx1v^4J@U&RJ=RTTdlF48W`@)wsBJrfGfkfvdnbljZpVZ(b_B9 z^MPgp;Km*LVMh!>vTLU{JJ2)_AQ=T{6>-A5BdJeX4@oe)3B@!2_jrLX*N{@a z85hn~i2GeDJZgM6YN^p(gy8i6mIyxF&7K!WDtTQ$YXg?iCF5E{m6cCl9jSv2%>!tF zF+7VxS|Wt@d~dm{#ZV?db9Q&Rvv&Ny=!P92zv?bp54Gg zm&Wj>YXP;}i8A1FaQXBfCE{6D@&bT2vsV)XaBcF(13cYmk{7^nK_*|mf(U3Y=K@~K z1Jp8X2#|U?HaxzE^B5jh5dnv`TPPX>Nc+Op>1FWq7Q zj~7^(w|Id^VgS#}TQ+89x)GavEhTcNx?FlsZPR~nw0pL1!l*;6iY^9XGYXQAP0PpNYD-mb`9BmUWHqgZG zjR7cXjsw+>~+l-jCsWjYh4|EfLUnX7d2>U61~qK>U%|?ahu3mQuY#7^&Bg`NGq`NZG~2>=!b;m}&>4XwCOmX#S;c9BKrbuzevIV_;Aal%{;6k( aw9!9;EO^Zc39okm0000i8I~jkMNcU8m(fz6x3fko5F%3$WIeVS6wA*Kv9UK0;xc70*Tay-wJj2N=Nw zQPFrS6`dWDBU)mB)=}`XQte7mM@6e`)_q`b-rRC7Yb}5qt2+^-wbYT&7{V^fr-1Vp zlrfLW1H52ouh*;+_RK`iEJo30_B=5F#R6XpkSRNcZyzfSEpl$`UNnQVr~jv8kd<(D!p251I>lJ`jq==p%eQe((;WX(cI41fo>ECd58CA)WJUmt~0 zF@Sgt^wilo=7zPVQ3y;uSZD0n>08gTotY9Lj+9)V~>h-QKoz2oPQ4XAObUv5sUgF0?#IarDldIY_L5lC!C zu|b_5w&T`F{ZeyrhICz5?(YFsVuXQ8tfyrIt}pzh-g90L`@HbWDB$bR4$-}Lot7g{ z%Ldfir1xCx0QVKn0My2IP<{pFH7)ce$l$->8t|CCd4RgFCI442x6!PC6iq#^&?sM< zUB$-%x2B#vfS3xN0ZzCX!FeI~o`RGLhf0UujTOxu6IKRVZU8&Od$rZnLvR}^psUX< zH3W<_24D@iGSw11z;v%^Lmdgda#(r|{Iy)a6`D+`bW7-+dkF)yf}1Cz=SZ+#IV)

*>D>TB+UMxPa>e=f*ghzy+{YNVzsGV}eIVE323$2-IR{?}w0>p#Gf# frhm)~78(5mu62k2)5_9M00000NkvXXu0mjfQyfQ( literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_35.png b/assets/dolphin/external/L1_Doom_128x64/frame_35.png new file mode 100644 index 0000000000000000000000000000000000000000..fe9e9f81fd1b0cece9ce3dd1231cd0fe1f867760 GIT binary patch literal 1237 zcmV;`1SwtDh}i<|=11s2S^kLj!te zvt)egJ-i|~0_emm0;w%Fqz3i?_&W{o zmP9Zt1hg36+GZE5p@1_!w*Y#L-*e9$Xq~xH zIl$QrN(KtMwOS|j%XtFpg!)KiW&aRs zf$EKwDS_AZPcasSb@_%jYPe;bm#7@zUCQr|(W*|K$`|*7yN8OFfyW}yX0f#|?p{mZ zFUt71gj<&>+H!?5Dwm`@*?UA_^#Iyr{YnC<%?66BSlv_yK2dFnkR;gOhmZK|+!a8o$G7$D5ea{t>JT{}+|CEAfxM?WByBS~lO*qk`LWi`( zldf9{-42evw`G@X6kd<1t+1qiq(rfISMXl|QMKs^RyKSo-^aK-)O#Yl>{90eB3aq+ zUM$5kPhXH_&I3U1WIT>lY7!|qfVEiTjaN@3JDCp80ajwwf{}OjXBNNGasY4PB8#0X zhn_PQz0XL^0W6)5aCN(iAu}AN)&Y7t<+hO{*g*)R4$BP70X!Y!ws7`7O$gca$StR@cWWDh=4C;cW^E|$a)l>?a01K@2$ZpTX7()F@SIIz|SsNFxU4HN-vKYTC1 z`T%Rv=NYus6F$$5U@7t`AM63RzC-H(Q9D$%uZ#mGI|xC7n#J%tEDrd8Y5Ull{p0p& zrC{v`v@%l&5fcS_N9^M9xN*<)fk?(Ew2Hd^yle*5$`maI|zL-UZ7nnt~2rS-!dI#+~mphmXK@m_(#$9JWgqlql zZy8+@0UpQRI>3+|0Hgh=-M}jzh?c!mNFjmir>72ZUDy0S6bXOqu28>0OUkqgA8bPv z;kajcL+x|{+zC&yObdg!4VBQJq9=Lj|b00000NkvXXu0mjf)6zQq literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_36.png b/assets/dolphin/external/L1_Doom_128x64/frame_36.png new file mode 100644 index 0000000000000000000000000000000000000000..cc80bc5434c63f72a426e6f727156b26b8ae2ae6 GIT binary patch literal 1288 zcmV+j1^4=iP)^y!J_JaP>$+3}H-hvKp_X$NkP^_STm)!s@ER`(4grz@8&Wbpya!(IA;BR)B49&m z;39yB1V;lTfF<1H_GV!G=|w03@WYI#)o+Ex>#22vo}VfUfDeHuCbhj0IDBJBYc%Tl z4O0ogv5|Vfk<{fIAQ|7XCO880MuKUTK#%b~?cWH__*mIfpZMC*NHB!}l<}|YG8^}e zB!H;3vIgZ0%n`$jVFGZ*@9F0$m^oLA*Hgxxr2)=ikP$GVMd=n#6wtN^D@ku6(0k}G z%lk8d%T%JpDkthVkvFXl;7QG*JzzAa?HLbaS60%a0VMTr%?y61u%b=!=_wp%_!j0@ zKbO_}BQ!w$KfYYCquQ-$pLdH`5o)P1S5_@Ya(7GuZX3294t+S|;(_3gWpemC7&Wp) z4l1IxpVeB%lL3@sj{w@U+_C`cx$=xK$=%<`=cyxDK#^LSN4sYgtb2b$nmRy(XCmHf zM<22g7V8~M_7UQZ%#reTI1fpzS{zY|0v}F6&IFahtnw}{eS+=1|j)X4d9q~vVVlSxq5|A_#* zNZ|3x+2fY7zbGVSP}E$$?ks>az$zo)RCh--qKwL=rCtrd;g&i zf;15z3OkBAJ)jH<9li`<_wE?`I(~PV2yW>zQA_~Cg)ymwk9U4Ef4q$p8 z03RcIPo}to3~j;Tm{0S13S5|%uA#OEs*hf0F~1OE9Y6|K6cISBfxm-&L>~`Fje%27 zYG21|#W_jO`v4R^(jYycLR@=jN#Sc-gVe_pKp7o=hdo{+e6RY)*N2sYIb&<$&U(#L zfr*YI0yex90jN)IOuVkG-_WywNN>$v7w{T{s`5!>w`u^1NVV3Shd~)ILIQ8Pt3?Cu zUieA1b6$Td1mVUN;L@RtrCINml0@IUgEWTw*Q~Nj7Fy*5w&OGDPZ-_rHk;pkvc%Fbw2@~Sm+rMx7gFE_BMtT z4Y;V|jRZ#oZh*x|T9J$rk3Dsg?Gd2CEB>BZ5NfcLxh-45=sIkT08cOKjKWj+nk|-F zzgr@JByQdaO&3tt^r(MIH{1vic@TofktWx3|5IQ&+~FXliqbuBY>XoUH$W@fO28Qb yM<#s0#`T*<1X}TA?}yMLLHnHoR|M+WTK@r2MlI>x4$6=K0000$fX#6TusIF^Hpe~t0S;t54_~ak zuFHMxLxALXo<~%0C5VRzS2?|alz>WYd4PHj%2-Ko2#^d|k(~137$|Qc!685*U`0x3 zc>oIuP7II$8h4M+R|Vs(6+_a%=Xq3&-VxPWrL`U_xXSj<>uVkWJ{afLdQzCxf!#L- zH#fbOU-1e7s5Pkdl07NR%HWhw84NX_I0o>{VfYeYQNC5?ThLNIboE&Ilq|KiB9s7L z<$Gkm30U!X9;kVViUGn1(5w8OF)PCxA4SCgrx}z0Eo)#c4 zjhFW8F=}hY%|)6Rqat>1M7t^^>utpVT=cKa3~pRg=0Me(cT?7z&{#e^2e)3_rTkUA zRCV&?o!s(q@E_I~K+=OoPd}9MaVk>N6qv4X?9`?$lKaBHZv~zMX&)Ywj8N(?d}INh zzH*NXvU-JYC4n~vXq~fQXc~C31s4UwG@+6%~((!t*NSsvQ(!~m2B{u2YtoODj{vxzwZn&=;&OV;-7?O8^U#Ml2PQ;_Gw3=YhYKh!9Z+Nbx;D6tr0gx4#k*zN!w;>lr-Cm#*hY zKWAWi48VPyP%*;&TPuMYC9gn&sWE^TZ%r!Yx^XcByZPR__$;J~0W@AfLZpY_(!v$i zcMa0U0GTEiH>teOmemWCk{|}q+;}#$%3G->&?0q;7+{47q=3I)z~{2P7yi})pQGfd ztp@Pj|9lWa-4r)uA|@}=%V>&5nE^c&^&VUs-J=VrL$(_@!&2bOYVPe-yrzX31JmmS^I;ZtJ?*?*Up+)d8?FwR!6su37WZLssCR zw53?s+n~n5vBP=++8f}m9DW%n*ScnJ4MID9G+{V}*5lgZR%jg{aw1yFwz{aE6fWB` zPzwD=HSicF2i(_W0orH4@~?FRqtkV3C;g&kzvigrg5I(spW|BbT4KO6j=c=Ia zU0?SA83VFWun&TV^85pv(x;mSgYl|Ng8i$-7-eg^ujV!F{yVRrV@a9p)7!e z)L5%VjvL330Lw%)z3R255FoSSAtVdMa$dlWo>m6#Tf7c_=Bt#?e-|IYF3pWO841~m z13@W@i|jRI)66HlKPP+AzzOhX2v~;e6TqO5t16}m0<~Dl`Z;jQ(*}pswq9F{e?i-t Uz_Q-&rT_o{07*qoM6N<$g6}FMl>h($ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_38.png b/assets/dolphin/external/L1_Doom_128x64/frame_38.png new file mode 100644 index 0000000000000000000000000000000000000000..43e0f8c6938872fd8dc10338d77340cffbe9a38d GIT binary patch literal 1240 zcmV;}1Sk86P)=%>k`VItB_@twrH9!CxV;i<| zUDtgbw&gXu1BbaB1=yUU0Go3ZU~`TFY|c@D%{dCNIY$9D=P1DDyk~ddpmX1HvbK~G zZu=-ea_;+91zZ&*q6pTmEb5qGO!>e;lnzxyhjO+0we+pQiHPq z9wj(FKmsi09zU-F#-CmuSAdZo?TT1dJvAqA@J!bAc^Dbm0uo1bT(i=~?wm>CwsAupy z>eI_x@-#6P@B9eg51uot4hPf*Ehm8Kng`&_3+x>H#3Ht z>@Nbx4d)*&IIhn0JU}##<=WzCwKl(o#|MzMf*0pOMmrSYoNzP^aDp;2g<= zPS^VY&>8bK)SB}32z+<54~d)tQsuuafTzJH@&R0)VmD>rB84UH14P(0GLXiN7ekNx z0RIZ$_2x&f{>UwvRq_nrWmX%*gzXecegWlmv*^v7HmVNh$ z(9I%T%>wjHP>n{)_;Gmi032y800nhSDotDu6ZsTYt5)gd1AN^Gn(cj42ShFXS-}!e ztC>21mFh$huY_3>IioIs^fL1+D1ijEAcpt=xbe|=5>BvABy*Wr3AB?xie5f|dMPx^ zq+!8Vys6|Y&@tt)u8Uosk~)RaJ_$SX1@P=;a@ z(6VBzbvcd4*P}Q^iQYnbGBWTih>EtdyPXAS6QT){tB(aJA?3YSU;SP`1=gd!$L)4I z3(z_SU!d(#@aL!%(I%ip^JnD;Bs0&Ip|%IAjp1hj5sw|$ed6j^X0Q{>S{0^^p__HMnu=W9$AC?NHl*;25aBaY6D}seg8Ck6yrq;mhe29?dl#(M zK&q>y;yH)Be*bkNC}Vv5%TUf9j<_sgGWVSOzP@AlpNPr4SC8HXJZ)=Rf|d#Nj^hy@ zKzex=kA9RAXx_V2r>74f@rVVmbRvTy^hEQ>H6^fEgIbP@w5&{5fDH7s0u}*8%1|CW zwiFQ`F3puNuMm1$4a!6I;t_xr=Tl{*lyH>kzZ-a6c^pM54QnAf4lUiwmFW?!)wWXQ z0kYsdyXYYdOX7=C0m~#f17nQ$ zdW|t&M~p@52C%pmfb0%H`<2l}tx? z7@!HLYUcqVt?>vb(>3{r0U9AO04?M)Gacb!fF?*zwyOCG{JX2b+jw~J6UfP^%8%-G z%a4U6Kr2`>Ou@L07W$$z+J%iX_0dRP!HRZpJVKxJIkIO8OO)7^ix|Z zf>C6EXyj*1($1|9ht-j*vdhB&9NCQUivc>EPsiQO1X|Hm$pq2!du~ToK>i4TF6Z;{ zJC*}9W|b`w#^Y__%pmvQ?qPjF@VR$ALsw;hKi zjz81d3H;RTA0wXuw7JyowFST@JAaJaKETRcPIhi70#^;T@J`Fg?iv7%b@VPEy4IcA z)s%2|7eIp`@;(H8L-&H&g^tVv^_LTnWtr_*sOk=fSedLz1yVgL@Q5VPbxYx(@l z$C2c!pfSK|5J+}g0dZUaL?hS(YYWv83>pL6W!$NQ>z4Gk2S8@@dnVMolvFc;whLHU z^0Z!s_Ac!Kkdfsp&PPnMYYDK5)kwhJvDe)SKJkEM(wvt{QH!+W-88D_^o=N8f>j6b z`|S*{0-hC8Hq!!?#zY{f|mjKXY1WP1u#V@0J?kk+RM-DR;7PR``OwBpq_}v z1}njOJOgOiP2sKdPYDFc`C9SE-%p#12*LqS%>u}|=-#}KCREcUbs2XBhPKRT9Z*S+ zcHg?U^nHM=b#YP|{o$|*An&1yW%KUk&FTbtI)psfSL}c5uZ3HC=`no4TIKxd6#m0) zm!6w;S^9ag>j9N*{|g~jC&Wec0kWtV~mmi&0>wAymnFBq%9)? zl}CZF8~`4A$z%yBqrEgQ*`!t973_w#v)avmP`aOe4I=ku{V%`I*ZVgrpKtR2F2E&P?R zRagZLmqE~8_#Gh8HllK#{Zs}qfi@n+{Cw1Z4n;g;{XHH zgtiDS0x2Tc#R)DrSwIt*$U=OJ*qZcRL~yo%25JIFWbSDH07n2Mc3Hg^I5EIK;MMyU z@&S$j0D#`VF`g`l*9U>z{Jua^3)o>RN$miml*^)jZhkNQ%`QkO08Yw9K|;(7kxvpq zDgo5QONr*T*QRT`**gbm1V9yCdTl9ih4BR9tPm~$yy|BQDOv~M2;zyWA0SWwT)W3@ zM(svpald~Gxg3NDKw|eb8CLsw4^*E|6~%G^6!JO5NmI1azXz~m)$`w39N{s5HD>KPfZjRQynwNZO3arEK^?p=aNEOUUF)z3vM zu;jjYuer6hr3`{d?*QCvf!l^NmQ{aLKiSR|mI%OO^=s2e%@`P##i|VV2h-mOnu)SK zUM$W4X0c*h9F6ZT0I!G4l77vKAxZ>gTvGuQQZPBudz=TT^9#uZQmVfwCostZTB%U9 z#nq7B7odLEBH!XrYgJ5u$501>SxA*Yds;~S&YJvH_;cMIgbu)cK7Pfz<_X|r zVod>fTBDV6av?oz`Xd037o#DbOBi?c z@3?IgryL1k=6vB-5aR;^= zb@h~+G0l|SKe&TgSlq`OZ5J&omyo61Hd^gGA#nf=KAFhZptrY6$l4*e^r#L_UkI@z z-aAW}5k%|vz44^mQbf!#B>)S;yulR&=Nan#cqE7&4u{kNuqJ<%n0he;XYAeu&-%M; z$Ke!I7eaPe`CPPuJqq}_M@PoE?P%|g6iJFZftdwWRyJpj_&ZFzs4%nWQb<7x0YrmZ zfra#%)Dh}aPmKsxLM;HR2gk=%0YJE)Zq^0EPmHwl@ohpq$Mc zk>mqR{xvMCtpW4}F)HVJk%6;-EEPiYe+Or+3zQcxJ@&O6pZYBNeVG@6T6z7!53;=% zmmm<=!t2l847@lptbPE48$rETpjTBpg2(}rJAs^laQ8gk8W~nUfYBDf6#<4eO5Yt> btiRwJSI;U{*S+3j00000NkvXXu0mjf{QeJ7 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_6.png b/assets/dolphin/external/L1_Doom_128x64/frame_6.png new file mode 100644 index 0000000000000000000000000000000000000000..b724d0c2022023b0dd71af650d8ff26ff0d333e6 GIT binary patch literal 1181 zcmV;O1Y-M%P)d4cNvvC?l;_Y6&6nczl6A zrIfc^d@cS(FW@2;pXdebhW8x{=JPyGE78Fv00Zy)P7O>MlLrCb910E^!crxM~OfrVb*S8#d(*+WTs1(=mw8uL@@d+s$mAT0qXB^L&cVO9)z z3JKB?pfx<#(A4qLa&0Ghryvypu%^psECwnub~l_BQV;-o{c0mcssI#1oaX(d1QUQN z_i)T?-0WV|?@ur;1z`l>$bD-Jt$02HHs^_?2q8c2 ztKnjXN?@p9yKMqhxOW0M-rqvvWgdnZt!viLh{je5z)jR<3q_DfColr2xjZ%D#kAYWHCOxp5on-`%t~#TP51= zDYasfw%vb1fYw84oX4Ami=LEoj3o^ly>XV{C;%6q(WG2hAI9uq6x%t*+9A2r?hdLP z2+=gWb(OF}h~D+1`*FjPch2$2U@%Q!FOfb67Hs=nT}KaCGFU(VvnL-&imequs~*R? zZPb=4b&W75psdA1{!39HKo(i^XhN+dzV$s}29A7pDHH&{oc43>JX}z{U&A9?5@di1 z0W?%#wdd}+L9>Dp3B2XMlq3q!gLTiHTP0{AlM;xl04$DKGq+~eu%v>2miLAKHRts7 zb_}T%V1^Zi$l!f#?&B^0r6?01x+2gB8IjKrp$5x84a?w3JxI4{+vl3Pe6FlWs0aMyQ*1$u7?Sq~{1UCgt=mWS4W;XjT*NsN!J@2U4>Agll|CD#Z_V0Hp|iU`69 zpbtDX(Aev_EwEEVBsA?7dd~3~y370Cl0Zx?V~gv-JY@EP)rM4zM%(u|Nw; z>>sc7ZctkC7DNgMz*Y;`YcS7}8gDdCqvG)*>)UP$_VC3rF`!2j7ZTU@Ql~ejs(1PvV&;py>krxFiSg zDB=3+HQwc07>Nq)01~}>$R?>R-PzcuAngLsSW5?x_+z1iAKXUHsQlAt*qp$s5}OJ@ zqi(NI7E72-oo{rB6__#{6oB@o$jANQC=FC{Vxgqhp#U`g7*61^0mIJzjA^4f zPv=3uK%yK&=SQ!?V(%nIk10j-u z*RB$F1OeSYdmc3{S+6;MA_PnutROJoKgV17-99#woU_KP6bC6)Jzzw_ocSGt8gr4e<^_k;LT{}QO+|^ znl>}60$YL zKoyb4MhtfLudd4&{8EGjAh8yR&~t|vecLI{7s3G`w0rJSHMiC-ss(HT^s`>7B3M1M z#mXUO+p<}$zY^L3R_q9ZD%O$ZXAgcU!UC{xfz|U{I02h|gH+2H!edPlq7kG8cbj(h zU8h)oMLY#W76sSxM-{*+Y;6aB24VKmvtW_?y-G^8MPT+Gd5d=L_hefD(CO96sB{|r zmW7P(JVWeEASU;F9;UpE5laDB5wu7hrnKNh`!A)G{~G1|JJya8BLDyZ07*qoM6N<$ Ef~R`{ivR!s literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_8.png b/assets/dolphin/external/L1_Doom_128x64/frame_8.png new file mode 100644 index 0000000000000000000000000000000000000000..a18485d6f511e2e951800e13b367b46804f0145e GIT binary patch literal 1193 zcmV;a1XlZrP)E<*>SmOv{KF6XHu3gab{)B=6A z*6#M=Yw;)h0bb?Z35G04Ppby&iaTfPWZQ z@3)ZO+ADz88Xmt#JXsK5p9FI2`wmGj;Dk_8+5uK2m&g3v`d)g?DJUrbPRWHqLX3sT zCyAhx03h*FqPgR><=ScX&OsRgU`?0VSPWcYJb^ebqzhnN_0~p;)&V$zc;f1BEl~hm zyC27_#;xwf{rxHAa*!ebiQPjoyyE!`*ql!l#dZO7@;SswOSC?J1V+b#&wsKw(sKZB zSi{8%UBIJ*owy0qv9%K@S^W^2Rknke*>kP>85MAh14t9K)p##)%<={9S%OS#a{$Zg z=YmQsxgS32*{HBoK@jB~fLkqa$8hfDH6J!lwS9#x0*F}s+A>mej}e~DstV@^%by6c zWZ4lPcB}xb*bx?2_YW69)Js+=zpP@&5<$POs{lGFBRSbIE&|y8h2#J!HeZ$#xKsgD zDU@w-5YqDk*mV^79-CUba)R+5>LjoVsS;>+3$g3G$=`)v$K9LI0k|(H-R1MR=Mxa= z0@%E42goSl;P{AV`4&*3VmW|E@1C+rX-juD_fz2Q0<*cM4&d=&se>QdMh;f~MKo-l z08S-F3Lv6x?~o)*oK2l?bcq$XWjHE;=uHvJ{M^;QYd6pvRLRMObhGJ~03tq&hIlSv z+|_?#*yv8V5`txa;lCs>BGcE*%RQy5oln~j*n!y@g4J_t9OFj-RmdN&=d5nceYmTC zw@bk8DYs&>wB0}B1Xg&Q$6JL9%E~2VX~PCJE)o(4(BM;vd<|x?T|(9g$z?=$(0m}o zllbT=!6FFi`q}-YVJRc$FbTkeFe|hn1OCl<2Wd~@gv}wf0KCbU%xAIPSq>q67f3b~ zRJHAJ3@QO+t$Zp5TEfsQgO==5U}E5kAX6kIP6cxX#c6PORwA=G#uX38z>P176YM$^ z(oz0U=njk@eI#|2B#uN=Rl_*nE>a~>3&87zq~XMS9Cn>Fr&LqDz7WXe8y|#x~@$liNh-ZB|e{zNU-LaYWS5sfD@o4_PQ?7C92_d00BLr z9KlT>O$4Vn!3A#+$O04Di06pyNk2sd?-szICr~2uMEeJL1wi7I)f<5~2KWYEy-y(@ z;1vJ>(EB&WodxmuAW)m%H&|)`Cu}999Y9LCBHGvH_ttk#K}i8VrGcElL$%) zpeNo+wDx&#x^|kqYfwf2RMBPhECsDF?m%1=(glE5{cIt{>i`--+;Q~-Bnm)l_xKs< zIjJx0|KEjN4N?SPvHPBksQr8ds?EEKV!Hqu`5NM^DOziP1+ZiF<3Cv(=`lbwX15Co zO~BZ}PCNu^*jfp+to|OJRknke(YT~~Mg<(>0M1!j@;8EJqU;qD zi!*>(?AR8i{+A12)kjuIzh=ddC4$y(r~n!%n4IiAZUw0G3(Eyks=X{H2+0DtR4Cix zdRXrZQ15Z%M;vPHiV1KZ?jW!VsTO!o3#s>_$=`(^*WJPB0NM|1A*bO{OCG@KN`>O+y4_O+{j*J)rhxRg^1>tWLm0j!u95Aj;Uw5$Kb zZKFA*B!rpsh5v%U6_LKDUF|JhZ+qT)zz&S=5J=T0X+DsM7{^3z1>3A3Bl!x>frQ+kVxWJ zX9+Wc;NBngXWf=EVvZ>RL=ZL$X~MOF(0oI`A4`Hb;c&<;fN1i)sUj65d8}Sb7AKls z5KRo#Mc}#+Qf1}032y)Jq-((idt9H~JDjjIA#5a9yen){B4jOar%KNmGN|*4>mjzffq-G)ejJGBWM&0jH+s{ zAZj4wPM{_rJUx$(MupW65VQqoMS$Ur(oaVf>u(5)0X!nWc+z%JNd&(E;?-|NxisUV P00000NkvXXu0mjfXqO`W literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Doom_128x64/meta.txt b/assets/dolphin/external/L1_Doom_128x64/meta.txt new file mode 100644 index 000000000..838239623 --- /dev/null +++ b/assets/dolphin/external/L1_Doom_128x64/meta.txt @@ -0,0 +1,14 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 64 +Passive frames: 15 +Active frames: 24 +Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 +Active cycles: 1 +Frame rate: 2 +Duration: 3600 +Active cooldown: 7 + +Bubble slots: 0 \ No newline at end of file diff --git a/assets/dolphin/external/manifest.txt b/assets/dolphin/external/manifest.txt index 0b4b9a426..bd3050b51 100644 --- a/assets/dolphin/external/manifest.txt +++ b/assets/dolphin/external/manifest.txt @@ -10,9 +10,9 @@ Weight: 3 Name: L1_Laptop_128x51 Min butthurt: 0 -Max butthurt: 7 +Max butthurt: 9 Min level: 1 -Max level: 1 +Max level: 3 Weight: 3 Name: L1_Sleep_128x64 @@ -36,6 +36,20 @@ Min level: 1 Max level: 1 Weight: 3 +Name: L2_Furippa2_128x64 +Min butthurt: 0 +Max butthurt: 6 +Min level: 2 +Max level: 2 +Weight: 3 + +Name: L3_Furippa3_128x64 +Min butthurt: 0 +Max butthurt: 6 +Min level: 3 +Max level: 3 +Weight: 3 + Name: L1_Read_books_128x64 Min butthurt: 0 Max butthurt: 8 @@ -43,6 +57,13 @@ Min level: 1 Max level: 1 Weight: 3 +Name: L2_Hacking_pc_128x64 +Min butthurt: 0 +Max butthurt: 8 +Min level: 2 +Max level: 2 +Weight: 3 + Name: L1_Cry_128x64 Min butthurt: 8 Max butthurt: 13 @@ -57,20 +78,6 @@ Min level: 1 Max level: 3 Weight: 3 -Name: L1_Mad_fist_128x64 -Min butthurt: 9 -Max butthurt: 13 -Min level: 1 -Max level: 3 -Weight: 3 - -Name: L1_Mods_128x64 -Min butthurt: 0 -Max butthurt: 9 -Min level: 1 -Max level: 3 -Weight: 3 - Name: L1_Painting_128x64 Min butthurt: 0 Max butthurt: 7 @@ -78,145 +85,26 @@ Min level: 1 Max level: 3 Weight: 3 -Name: L1_Leaving_sad_128x64 -Min butthurt: 14 -Max butthurt: 14 -Min level: 1 -Max level: 3 -Weight: 3 - -Name: L1_Senpai_128x64 -Min butthurt: 0 -Max butthurt: 5 -Min level: 1 -Max level: 3 -Weight: 3 - -Name: L1_Kaiju_128x64 +Name: L1_Mods_128x64 Min butthurt: 0 Max butthurt: 10 Min level: 1 Max level: 3 Weight: 3 -Name: L1_My_dude_128x64 -Min butthurt: 0 -Max butthurt: 8 -Min level: 1 -Max level: 3 -Weight: 3 - -Name: L2_Wake_up_128x64 +Name: L1_Wake_up_128x64 Min butthurt: 0 Max butthurt: 12 Min level: 2 Max level: 3 -Weight: 3 - -Name: L2_Furippa2_128x64 -Min butthurt: 0 -Max butthurt: 6 -Min level: 2 -Max level: 2 -Weight: 3 - -Name: L2_Hacking_pc_128x64 -Min butthurt: 0 -Max butthurt: 8 -Min level: 2 -Max level: 2 -Weight: 3 - -Name: L2_Soldering_128x64 -Min butthurt: 0 -Max butthurt: 10 -Min level: 2 -Max level: 2 -Weight: 3 - -Name: L2_Dj_128x64 -Min butthurt: 0 -Max butthurt: 8 -Min level: 2 -Max level: 3 -Weight: 3 - -Name: L3_Furippa3_128x64 -Min butthurt: 0 -Max butthurt: 6 -Min level: 3 -Max level: 3 -Weight: 3 - -Name: L3_Hijack_radio_128x64 -Min butthurt: 0 -Max butthurt: 8 -Min level: 3 -Max level: 3 -Weight: 3 - -Name: L3_Lab_research_128x54 -Min butthurt: 0 -Max butthurt: 10 -Min level: 3 -Max level: 3 -Weight: 3 - -Name: L1_Sad_song_128x64 -Min butthurt: 8 -Max butthurt: 13 -Min level: 1 -Max level: 3 -Weight: 3 - -Name: L2_Coding_in_the_shell_128x64 -Min butthurt: 0 -Max butthurt: 12 -Min level: 2 -Max level: 3 -Weight: 3 - -Name: L2_Secret_door_128x64 -Min butthurt: 0 -Max butthurt: 12 -Min level: 2 -Max level: 3 -Weight: 3 - -Name: L3_Freedom_2_dolphins_128x64 -Min butthurt: 0 -Max butthurt: 12 -Min level: 3 -Max level: 3 -Weight: 3 - -Name: L1_Akira_128x64 -Min butthurt: 0 -Max butthurt: 8 -Min level: 1 -Max level: 3 -Weight: 3 - -Name: L3_Intruder_alert_128x64 -Min butthurt: 0 -Max butthurt: 12 -Min level: 3 -Max level: 3 -Weight: 3 - -Name: L1_Procrastinating_128x64 -Min butthurt: 0 -Max butthurt: 8 -Min level: 1 -Max level: 3 -Weight: 3 +Weight: 4 Name: L1_Happy_holidays_128x64 Min butthurt: 0 Max butthurt: 14 Min level: 1 Max level: 3 -Weight: 3 +Weight: 4 Name: L1_Sleigh_ride_128x64 Min butthurt: 0 @@ -225,6 +113,83 @@ Min level: 1 Max level: 3 Weight: 4 +Name: L1_Senpai_128x64 +Min butthurt: 0 +Max butthurt: 5 +Min level: 1 +Max level: 3 +Weight: 4 + +Name: L1_Kaiju_128x64 +Min butthurt: 0 +Max butthurt: 10 +Min level: 1 +Max level: 3 +Weight: 4 + +Name: L1_My_dude_128x64 +Min butthurt: 0 +Max butthurt: 8 +Min level: 1 +Max level: 3 +Weight: 4 + +Name: L1_Sad_song_128x64 +Min butthurt: 8 +Max butthurt: 13 +Min level: 1 +Max level: 3 +Weight: 4 + +Name: L2_Coding_in_the_shell_128x64 +Min butthurt: 0 +Max butthurt: 12 +Min level: 2 +Max level: 3 +Weight: 4 + +Name: L2_Secret_door_128x64 +Min butthurt: 0 +Max butthurt: 12 +Min level: 2 +Max level: 3 +Weight: 4 + +Name: L3_Freedom_2_dolphins_128x64 +Min butthurt: 0 +Max butthurt: 12 +Min level: 3 +Max level: 3 +Weight: 4 + +Name: L1_Akira_128x64 +Min butthurt: 0 +Max butthurt: 8 +Min level: 1 +Max level: 3 +Weight: 4 + +Name: L3_Intruder_alert_128x64 +Min butthurt: 0 +Max butthurt: 12 +Min level: 3 +Max level: 3 +Weight: 4 + +Name: L1_Procrastinating_128x64 +Min butthurt: 0 +Max butthurt: 8 +Min level: 1 +Max level: 3 +Weight: 4 + +Name: L1_Hackspace_128x64 +Min butthurt: 0 +Max butthurt: 12 +Min level: 1 +Max level: 3 +Weight: 4 + Name: L1_Showtime_128x64 Min butthurt: 0 Max butthurt: 10 From 6cc49765687089b92e3293db521f0bd860eb9e10 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 28 Mar 2025 14:10:16 +0300 Subject: [PATCH 051/125] NFC: Fix NDEF parser for MIFARE Classic [ci skip] by Willy-JL in OFW PR 4153 --- .../main/nfc/plugins/supported_cards/ndef.c | 61 +++++++++++-------- lib/nfc/helpers/nfc_data_generator.c | 36 +++-------- lib/toolbox/pretty_format.c | 8 ++- 3 files changed, 49 insertions(+), 56 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/ndef.c b/applications/main/nfc/plugins/supported_cards/ndef.c index fb2c4da48..06982e111 100644 --- a/applications/main/nfc/plugins/supported_cards/ndef.c +++ b/applications/main/nfc/plugins/supported_cards/ndef.c @@ -22,6 +22,7 @@ #include #include +#include #define TAG "NDEF" @@ -181,30 +182,34 @@ static bool ndef_get(Ndef* ndef, size_t pos, size_t len, void* buf) { // So the first 93 (31*3) data blocks correspond to 128 real blocks. // Last 128 blocks are 8 sectors: 15 data blocks, 1 sector trailer. // So the last 120 (8*15) data blocks correspond to 128 real blocks. - div_t small_sector_data_blocks = div(pos, MF_CLASSIC_BLOCK_SIZE); + const size_t real_block_data_offset = pos % MF_CLASSIC_BLOCK_SIZE; + size_t small_sector_data_blocks = pos / MF_CLASSIC_BLOCK_SIZE; size_t large_sector_data_blocks = 0; - if(small_sector_data_blocks.quot > 93) { - large_sector_data_blocks = small_sector_data_blocks.quot - 93; - small_sector_data_blocks.quot = 93; + if(small_sector_data_blocks > 93) { + large_sector_data_blocks = small_sector_data_blocks - 93; + small_sector_data_blocks = 93; } - div_t small_sectors = div(small_sector_data_blocks.quot, 3); - size_t real_block = small_sectors.quot * 4 + small_sectors.rem; - if(small_sectors.quot >= 16) { + const size_t small_sector_block_offset = small_sector_data_blocks % 3; + const size_t small_sectors = small_sector_data_blocks / 3; + size_t real_block = small_sectors * 4 + small_sector_block_offset; + if(small_sectors >= 16) { real_block += 4; // Skip MAD2 } if(large_sector_data_blocks) { - div_t large_sectors = div(large_sector_data_blocks, 15); - real_block += large_sectors.quot * 16 + large_sectors.rem; + const size_t large_sector_block_offset = large_sector_data_blocks % 15; + const size_t large_sectors = large_sector_data_blocks / 15; + real_block += large_sectors * 16 + large_sector_block_offset; } - const uint8_t* cur = &ndef->mfc.blocks[real_block].data[small_sector_data_blocks.rem]; + const uint8_t* cur = &ndef->mfc.blocks[real_block].data[real_block_data_offset]; while(len) { size_t sector_trailer = mf_classic_get_sector_trailer_num_by_block(real_block); const uint8_t* end = &ndef->mfc.blocks[sector_trailer].data[0]; - size_t chunk_len = MIN((size_t)(end - cur), len); + const size_t chunk_len = MIN((size_t)(end - cur), len); memcpy(buf, cur, chunk_len); + buf += chunk_len; len -= chunk_len; if(len) { @@ -244,7 +249,9 @@ static inline bool is_printable(char c) { static bool is_text(const uint8_t* buf, size_t len) { for(size_t i = 0; i < len; i++) { - if(!is_printable(buf[i])) return false; + if(!is_printable(buf[i]) && !(buf[i] == '\0' && i == len - 1)) { + return false; + } } return true; } @@ -260,7 +267,7 @@ static bool ndef_dump(Ndef* ndef, const char* prefix, size_t pos, size_t len, bo for(size_t i = 0; i < len; i++) { char c; if(!ndef_get(ndef, pos + i, 1, &c)) return false; - if(!is_printable(c)) { + if(!is_printable(c) && !(c == '\0' && i == len - 1)) { furi_string_left(ndef->output, string_prev); force_hex = true; break; @@ -268,14 +275,18 @@ static bool ndef_dump(Ndef* ndef, const char* prefix, size_t pos, size_t len, bo furi_string_push_back(ndef->output, c); } } - if(force_hex) { - for(size_t i = 0; i < len; i++) { - uint8_t b; - if(!ndef_get(ndef, pos + i, 1, &b)) return false; - furi_string_cat_printf(ndef->output, "%02X ", b); + if(!force_hex) { + furi_string_cat(ndef->output, "\n"); + } else { + uint8_t buf[4]; + for(size_t i = 0; i < len; i += sizeof(buf)) { + uint8_t buf_len = MIN(sizeof(buf), len - i); + if(!ndef_get(ndef, pos + i, buf_len, &buf)) return false; + pretty_format_bytes_hex_canonical( + ndef->output, 4, PRETTY_FORMAT_FONT_MONOSPACE, buf, buf_len); + furi_string_cat(ndef->output, "\n"); } } - furi_string_cat(ndef->output, "\n"); return true; } @@ -285,9 +296,7 @@ static void if(!force_hex && is_text(buf, len)) { furi_string_cat_printf(ndef->output, "%.*s", len, (const char*)buf); } else { - for(size_t i = 0; i < len; i++) { - furi_string_cat_printf(ndef->output, "%02X ", ((const uint8_t*)buf)[i]); - } + pretty_format_bytes_hex_canonical(ndef->output, 4, PRETTY_FORMAT_FONT_MONOSPACE, buf, len); } furi_string_cat(ndef->output, "\n"); } @@ -582,7 +591,7 @@ bool ndef_parse_record( NdefTnf tnf, const char* type, uint8_t type_len) { - FURI_LOG_D(TAG, "payload type: %.*s len: %hu", type_len, type, len); + FURI_LOG_D(TAG, "payload type: %.*s len: %hu pos: %zu", type_len, type, len, pos); if(!len) { furi_string_cat(ndef->output, "Empty\n"); return true; @@ -887,13 +896,13 @@ static bool ndef_mfc_parse(const NfcDevice* device, FuriString* parsed_data) { for(uint8_t mad = 0; mad < COUNT_OF(mads); mad++) { const size_t block = mads[mad].block; const size_t sector = mf_classic_get_sector_by_block(block); - if(sector_count <= sector) break; // Skip this MAD if not present + if(sector_count <= sector) continue; // Skip this MAD if not present // Check MAD key const MfClassicSectorTrailer* sector_trailer = mf_classic_get_sector_trailer_by_sector(data, sector); const uint64_t sector_key_a = bit_lib_bytes_to_num_be( sector_trailer->key_a.data, COUNT_OF(sector_trailer->key_a.data)); - if(sector_key_a != mad_key) return false; + if(sector_key_a != mad_key) continue; // Find NDEF AIDs for(uint8_t aid_index = 0; aid_index < mads[mad].aid_count; aid_index++) { const uint8_t* aid = &data->block[block].data[2 + aid_index * AID_SIZE]; @@ -917,7 +926,7 @@ static bool ndef_mfc_parse(const NfcDevice* device, FuriString* parsed_data) { data_size = 93 + (sector_count - 32) * 15; } else { data_size = sector_count * 3; - if(sector_count >= 16) { + if(sector_count > 16) { data_size -= 3; // Skip MAD2 } } diff --git a/lib/nfc/helpers/nfc_data_generator.c b/lib/nfc/helpers/nfc_data_generator.c index 7914c1f7f..2143f0f5f 100644 --- a/lib/nfc/helpers/nfc_data_generator.c +++ b/lib/nfc/helpers/nfc_data_generator.c @@ -392,37 +392,15 @@ static void nfc_generate_mf_classic(NfcDevice* nfc_device, uint8_t uid_len, MfCl mf_classic_set_block_read(mfc_data, 0, &mfc_data->block[0]); + // Set every block to 0x00 uint16_t block_num = mf_classic_get_total_block_num(type); - if(type == MfClassicType4k) { - // Set every block to 0x00 - for(uint16_t i = 1; i < block_num; i++) { - if(mf_classic_is_sector_trailer(i)) { - nfc_generate_mf_classic_sector_trailer(mfc_data, i); - } else { - memset(&mfc_data->block[i].data, 0x00, 16); - } - mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); - } - } else if(type == MfClassicType1k) { - // Set every block to 0x00 - for(uint16_t i = 1; i < block_num; i++) { - if(mf_classic_is_sector_trailer(i)) { - nfc_generate_mf_classic_sector_trailer(mfc_data, i); - } else { - memset(&mfc_data->block[i].data, 0x00, 16); - } - mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); - } - } else if(type == MfClassicTypeMini) { - // Set every block to 0x00 - for(uint16_t i = 1; i < block_num; i++) { - if(mf_classic_is_sector_trailer(i)) { - nfc_generate_mf_classic_sector_trailer(mfc_data, i); - } else { - memset(&mfc_data->block[i].data, 0x00, 16); - } - mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); + for(uint16_t i = 1; i < block_num; i++) { + if(mf_classic_is_sector_trailer(i)) { + nfc_generate_mf_classic_sector_trailer(mfc_data, i); + } else { + memset(&mfc_data->block[i].data, 0x00, MF_CLASSIC_BLOCK_SIZE); } + mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); } nfc_generate_mf_classic_block_0( diff --git a/lib/toolbox/pretty_format.c b/lib/toolbox/pretty_format.c index f8319b69d..496738c4d 100644 --- a/lib/toolbox/pretty_format.c +++ b/lib/toolbox/pretty_format.c @@ -36,11 +36,17 @@ void pretty_format_bytes_hex_canonical( } const size_t begin_idx = i; - const size_t end_idx = MIN(i + num_places, data_size); + const size_t wrap_idx = i + num_places; + const size_t end_idx = MIN(wrap_idx, data_size); for(size_t j = begin_idx; j < end_idx; j++) { furi_string_cat_printf(result, "%02X ", data[j]); } + if(end_idx < wrap_idx) { + for(size_t j = end_idx; j < wrap_idx; j++) { + furi_string_cat_printf(result, " "); + } + } furi_string_push_back(result, '|'); From bfe9f206500c9efa719cb49b0da10a5ed13451ea Mon Sep 17 00:00:00 2001 From: doomwastaken Date: Fri, 28 Mar 2025 14:11:22 +0300 Subject: [PATCH 052/125] added doom animation to manifest --- assets/dolphin/external/manifest.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/assets/dolphin/external/manifest.txt b/assets/dolphin/external/manifest.txt index bd3050b51..67c5c1eb6 100644 --- a/assets/dolphin/external/manifest.txt +++ b/assets/dolphin/external/manifest.txt @@ -141,6 +141,13 @@ Min level: 1 Max level: 3 Weight: 4 +Name: L1_Doom_128x64 +Min butthurt: 0 +Max butthurt: 13 +Min level: 1 +Max level: 3 +Weight: 4 + Name: L2_Coding_in_the_shell_128x64 Min butthurt: 0 Max butthurt: 12 From dd3a3a02c99fe4b77e9c524a61db7714370e7103 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 28 Mar 2025 14:13:31 +0300 Subject: [PATCH 053/125] NFC: Support DESFire Transaction MAC file type [ci skip] by Willy-JL in OFW PR 4159 --- .../mf_desfire/mf_desfire_render.c | 12 +++ lib/nfc/protocols/mf_desfire/mf_desfire.h | 6 ++ lib/nfc/protocols/mf_desfire/mf_desfire_i.c | 82 ++++++++++++++++--- .../mf_desfire/mf_desfire_poller_i.c | 2 +- 4 files changed, 89 insertions(+), 13 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c index 783cbb871..96e4a30f9 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c +++ b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c @@ -180,6 +180,9 @@ void nfc_render_mf_desfire_file_settings_data( case MfDesfireFileTypeCyclicRecord: type = "cyclic"; break; + case MfDesfireFileTypeTransactionMac: + type = "txn-mac"; + break; default: type = "unknown"; } @@ -237,6 +240,15 @@ void nfc_render_mf_desfire_file_settings_data( furi_string_cat_printf(str, "size %lu\n", record_size); furi_string_cat_printf(str, "num %lu max %lu\n", record_count, settings->record.max); break; + case MfDesfireFileTypeTransactionMac: + record_count = 0; + furi_string_cat_printf( + str, + "key opt %02X ver %02X\n", + settings->transaction_mac.key_option, + settings->transaction_mac.key_version); + furi_string_cat_printf(str, "cnt limit %lu\n", settings->transaction_mac.counter_limit); + break; } bool is_auth_required = true; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.h b/lib/nfc/protocols/mf_desfire/mf_desfire.h index fb50008db..ec60b336b 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.h @@ -97,6 +97,7 @@ typedef enum { MfDesfireFileTypeValue = 2, MfDesfireFileTypeLinearRecord = 3, MfDesfireFileTypeCyclicRecord = 4, + MfDesfireFileTypeTransactionMac = 5, } MfDesfireFileType; typedef enum { @@ -128,6 +129,11 @@ typedef struct { uint32_t max; uint32_t cur; } record; + struct { + uint8_t key_option; + uint8_t key_version; + uint32_t counter_limit; + } transaction_mac; }; } MfDesfireFileSettings; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c index d83a91ad1..eba9c4312 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c @@ -1,5 +1,7 @@ #include "mf_desfire_i.h" +#include + #define TAG "MfDesfire" #define BITS_IN_BYTE (8U) @@ -47,6 +49,10 @@ #define MF_DESFIRE_FFF_FILE_MAX_KEY "Max" #define MF_DESFIRE_FFF_FILE_CUR_KEY "Cur" +#define MF_DESFIRE_FFF_FILE_KEY_OPTION_KEY "Key Option" +#define MF_DESFIRE_FFF_FILE_KEY_VERSION_KEY "Key Version" +#define MF_DESFIRE_FFF_FILE_COUNTER_LIMIT_KEY "Counter Limit" + bool mf_desfire_version_parse(MfDesfireVersion* data, const BitBuffer* buf) { const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfDesfireVersion); @@ -168,12 +174,19 @@ bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer uint32_t cur : 3 * BITS_IN_BYTE; } MfDesfireFileSettingsRecord; + typedef struct FURI_PACKED { + uint8_t key_option; + uint8_t key_version; + uint8_t counter_limit[]; + } MfDesfireFileSettingsTransactionMac; + typedef struct FURI_PACKED { MfDesfireFileSettingsHeader header; union { MfDesfireFileSettingsData data; MfDesfireFileSettingsValue value; MfDesfireFileSettingsRecord record; + MfDesfireFileSettingsTransactionMac transaction_mac; }; } MfDesfireFileSettingsLayout; @@ -182,7 +195,7 @@ bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer const size_t data_size = bit_buffer_get_size_bytes(buf); const uint8_t* data_ptr = bit_buffer_get_data(buf); const size_t min_data_size = - sizeof(MfDesfireFileSettingsHeader) + sizeof(MfDesfireFileSettingsData); + sizeof(MfDesfireFileSettingsHeader) + sizeof(MfDesfireFileSettingsTransactionMac); if(data_size < min_data_size) { FURI_LOG_E( @@ -202,17 +215,11 @@ bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer if(file_settings_temp.type == MfDesfireFileTypeStandard || file_settings_temp.type == MfDesfireFileTypeBackup) { - memcpy( - &layout.data, - &data_ptr[sizeof(MfDesfireFileSettingsHeader)], - sizeof(MfDesfireFileSettingsData)); + memcpy(&layout.data, &data_ptr[bytes_processed], sizeof(MfDesfireFileSettingsData)); file_settings_temp.data.size = layout.data.size; bytes_processed += sizeof(MfDesfireFileSettingsData); } else if(file_settings_temp.type == MfDesfireFileTypeValue) { - memcpy( - &layout.value, - &data_ptr[sizeof(MfDesfireFileSettingsHeader)], - sizeof(MfDesfireFileSettingsValue)); + memcpy(&layout.value, &data_ptr[bytes_processed], sizeof(MfDesfireFileSettingsValue)); file_settings_temp.value.lo_limit = layout.value.lo_limit; file_settings_temp.value.hi_limit = layout.value.hi_limit; file_settings_temp.value.limited_credit_value = layout.value.limited_credit_value; @@ -222,13 +229,34 @@ bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer file_settings_temp.type == MfDesfireFileTypeLinearRecord || file_settings_temp.type == MfDesfireFileTypeCyclicRecord) { memcpy( - &layout.record, - &data_ptr[sizeof(MfDesfireFileSettingsHeader)], - sizeof(MfDesfireFileSettingsRecord)); + &layout.record, &data_ptr[bytes_processed], sizeof(MfDesfireFileSettingsRecord)); file_settings_temp.record.size = layout.record.size; file_settings_temp.record.max = layout.record.max; file_settings_temp.record.cur = layout.record.cur; bytes_processed += sizeof(MfDesfireFileSettingsRecord); + } else if(file_settings_temp.type == MfDesfireFileTypeTransactionMac) { + const bool has_counter_limit = (layout.header.comm & 0x20) != 0; + memcpy( + &layout.transaction_mac, + &data_ptr[bytes_processed], + sizeof(MfDesfireFileSettingsTransactionMac)); + file_settings_temp.transaction_mac.key_option = layout.transaction_mac.key_option; + file_settings_temp.transaction_mac.key_version = layout.transaction_mac.key_version; + if(!has_counter_limit) { + file_settings_temp.transaction_mac.counter_limit = 0; + } else { + // AES (4b) or LRP (2b) + const size_t counter_limit_size = (layout.transaction_mac.key_option & 0x02) ? 4 : + 2; + memcpy( + &layout.transaction_mac, + &data_ptr[bytes_processed], + sizeof(MfDesfireFileSettingsTransactionMac) + counter_limit_size); + file_settings_temp.transaction_mac.counter_limit = bit_lib_bytes_to_num_be( + layout.transaction_mac.counter_limit, counter_limit_size); + bytes_processed += counter_limit_size; + } + bytes_processed += sizeof(MfDesfireFileSettingsTransactionMac); } else { FURI_LOG_W(TAG, "Unknown file type: %02x", file_settings_temp.type); break; @@ -468,6 +496,21 @@ bool mf_desfire_file_settings_load( furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_CUR_KEY); if(!flipper_format_read_uint32(ff, furi_string_get_cstr(key), &data->record.cur, 1)) break; + } else if(data->type == MfDesfireFileTypeTransactionMac) { + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_KEY_OPTION_KEY); + if(!flipper_format_read_hex( + ff, furi_string_get_cstr(key), &data->transaction_mac.key_option, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_KEY_VERSION_KEY); + if(!flipper_format_read_hex( + ff, furi_string_get_cstr(key), &data->transaction_mac.key_version, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_COUNTER_LIMIT_KEY); + if(!flipper_format_read_uint32( + ff, furi_string_get_cstr(key), &data->transaction_mac.counter_limit, 1)) + break; } success = true; @@ -716,6 +759,21 @@ bool mf_desfire_file_settings_save( furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_CUR_KEY); if(!flipper_format_write_uint32(ff, furi_string_get_cstr(key), &data->record.cur, 1)) break; + } else if(data->type == MfDesfireFileTypeTransactionMac) { + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_KEY_OPTION_KEY); + if(!flipper_format_write_hex( + ff, furi_string_get_cstr(key), &data->transaction_mac.key_option, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_KEY_VERSION_KEY); + if(!flipper_format_write_hex( + ff, furi_string_get_cstr(key), &data->transaction_mac.key_version, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_COUNTER_LIMIT_KEY); + if(!flipper_format_write_uint32( + ff, furi_string_get_cstr(key), &data->transaction_mac.counter_limit, 1)) + break; } success = true; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c index 6d8dfda16..8b57fcc4c 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c @@ -468,7 +468,7 @@ MfDesfireError mf_desfire_poller_read_file_data_multi( file_type == MfDesfireFileTypeLinearRecord || file_type == MfDesfireFileTypeCyclicRecord) { error = mf_desfire_poller_read_file_records( - instance, file_id, 0, file_settings_cur->data.size, file_data); + instance, file_id, 0, file_settings_cur->record.size, file_data); } } From 1c080ecc63eefb9f150319012385fca4073882f7 Mon Sep 17 00:00:00 2001 From: doomwastaken Date: Fri, 28 Mar 2025 14:15:36 +0300 Subject: [PATCH 054/125] reverted manifest to original, new animation added --- assets/dolphin/external/manifest.txt | 167 ++++++++++++++++----------- 1 file changed, 101 insertions(+), 66 deletions(-) diff --git a/assets/dolphin/external/manifest.txt b/assets/dolphin/external/manifest.txt index 67c5c1eb6..e0240dd98 100644 --- a/assets/dolphin/external/manifest.txt +++ b/assets/dolphin/external/manifest.txt @@ -10,9 +10,9 @@ Weight: 3 Name: L1_Laptop_128x51 Min butthurt: 0 -Max butthurt: 9 +Max butthurt: 7 Min level: 1 -Max level: 3 +Max level: 1 Weight: 3 Name: L1_Sleep_128x64 @@ -36,20 +36,6 @@ Min level: 1 Max level: 1 Weight: 3 -Name: L2_Furippa2_128x64 -Min butthurt: 0 -Max butthurt: 6 -Min level: 2 -Max level: 2 -Weight: 3 - -Name: L3_Furippa3_128x64 -Min butthurt: 0 -Max butthurt: 6 -Min level: 3 -Max level: 3 -Weight: 3 - Name: L1_Read_books_128x64 Min butthurt: 0 Max butthurt: 8 @@ -57,13 +43,6 @@ Min level: 1 Max level: 1 Weight: 3 -Name: L2_Hacking_pc_128x64 -Min butthurt: 0 -Max butthurt: 8 -Min level: 2 -Max level: 2 -Weight: 3 - Name: L1_Cry_128x64 Min butthurt: 8 Max butthurt: 13 @@ -78,6 +57,20 @@ Min level: 1 Max level: 3 Weight: 3 +Name: L1_Mad_fist_128x64 +Min butthurt: 9 +Max butthurt: 13 +Min level: 1 +Max level: 3 +Weight: 3 + +Name: L1_Mods_128x64 +Min butthurt: 0 +Max butthurt: 9 +Min level: 1 +Max level: 3 +Weight: 3 + Name: L1_Painting_128x64 Min butthurt: 0 Max butthurt: 7 @@ -85,114 +78,149 @@ Min level: 1 Max level: 3 Weight: 3 -Name: L1_Mods_128x64 -Min butthurt: 0 -Max butthurt: 10 +Name: L1_Leaving_sad_128x64 +Min butthurt: 14 +Max butthurt: 14 Min level: 1 Max level: 3 Weight: 3 -Name: L1_Wake_up_128x64 -Min butthurt: 0 -Max butthurt: 12 -Min level: 2 -Max level: 3 -Weight: 4 - -Name: L1_Happy_holidays_128x64 -Min butthurt: 0 -Max butthurt: 14 -Min level: 1 -Max level: 3 -Weight: 4 - -Name: L1_Sleigh_ride_128x64 -Min butthurt: 0 -Max butthurt: 14 -Min level: 1 -Max level: 3 -Weight: 4 - Name: L1_Senpai_128x64 Min butthurt: 0 Max butthurt: 5 Min level: 1 Max level: 3 -Weight: 4 +Weight: 3 Name: L1_Kaiju_128x64 Min butthurt: 0 Max butthurt: 10 Min level: 1 Max level: 3 -Weight: 4 +Weight: 3 Name: L1_My_dude_128x64 Min butthurt: 0 Max butthurt: 8 Min level: 1 Max level: 3 -Weight: 4 +Weight: 3 + +Name: L2_Wake_up_128x64 +Min butthurt: 0 +Max butthurt: 12 +Min level: 2 +Max level: 3 +Weight: 3 + +Name: L2_Furippa2_128x64 +Min butthurt: 0 +Max butthurt: 6 +Min level: 2 +Max level: 2 +Weight: 3 + +Name: L2_Hacking_pc_128x64 +Min butthurt: 0 +Max butthurt: 8 +Min level: 2 +Max level: 2 +Weight: 3 + +Name: L2_Soldering_128x64 +Min butthurt: 0 +Max butthurt: 10 +Min level: 2 +Max level: 2 +Weight: 3 + +Name: L2_Dj_128x64 +Min butthurt: 0 +Max butthurt: 8 +Min level: 2 +Max level: 3 +Weight: 3 + +Name: L3_Furippa3_128x64 +Min butthurt: 0 +Max butthurt: 6 +Min level: 3 +Max level: 3 +Weight: 3 + +Name: L3_Hijack_radio_128x64 +Min butthurt: 0 +Max butthurt: 8 +Min level: 3 +Max level: 3 +Weight: 3 + +Name: L3_Lab_research_128x54 +Min butthurt: 0 +Max butthurt: 10 +Min level: 3 +Max level: 3 +Weight: 3 Name: L1_Sad_song_128x64 Min butthurt: 8 Max butthurt: 13 Min level: 1 Max level: 3 -Weight: 4 - -Name: L1_Doom_128x64 -Min butthurt: 0 -Max butthurt: 13 -Min level: 1 -Max level: 3 -Weight: 4 +Weight: 3 Name: L2_Coding_in_the_shell_128x64 Min butthurt: 0 Max butthurt: 12 Min level: 2 Max level: 3 -Weight: 4 +Weight: 3 Name: L2_Secret_door_128x64 Min butthurt: 0 Max butthurt: 12 Min level: 2 Max level: 3 -Weight: 4 +Weight: 3 Name: L3_Freedom_2_dolphins_128x64 Min butthurt: 0 Max butthurt: 12 Min level: 3 Max level: 3 -Weight: 4 +Weight: 3 Name: L1_Akira_128x64 Min butthurt: 0 Max butthurt: 8 Min level: 1 Max level: 3 -Weight: 4 +Weight: 3 Name: L3_Intruder_alert_128x64 Min butthurt: 0 Max butthurt: 12 Min level: 3 Max level: 3 -Weight: 4 +Weight: 3 Name: L1_Procrastinating_128x64 Min butthurt: 0 Max butthurt: 8 Min level: 1 Max level: 3 -Weight: 4 +Weight: 3 -Name: L1_Hackspace_128x64 +Name: L1_Happy_holidays_128x64 Min butthurt: 0 -Max butthurt: 12 +Max butthurt: 14 +Min level: 1 +Max level: 3 +Weight: 3 + +Name: L1_Sleigh_ride_128x64 +Min butthurt: 0 +Max butthurt: 14 Min level: 1 Max level: 3 Weight: 4 @@ -203,3 +231,10 @@ Max butthurt: 10 Min level: 1 Max level: 3 Weight: 4 + +Name: L1_Doom_128x64 +Min butthurt: 0 +Max butthurt: 13 +Min level: 1 +Max level: 3 +Weight: 4 From 2828ffb0f4a1c3ee8e4a05ad1accee6c1d9abb05 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 28 Mar 2025 14:18:34 +0300 Subject: [PATCH 055/125] add nfc apdu cli command back [ci skip] by leommxj in OFW PR 4133 --- applications/main/nfc/nfc_cli.c | 163 ++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index fae8ca933..ea686834f 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -3,15 +3,36 @@ #include #include #include +#include +#include +#include +#include +#include #include #define FLAG_EVENT (1 << 10) +#define NFC_MAX_BUFFER_SIZE (256) +#define NFC_BASE_PROTOCOL_MAX (3) +#define POLLER_DONE (1 << 0) +#define POLLER_ERR (1 << 1) +static NfcProtocol BASE_PROTOCOL[NFC_BASE_PROTOCOL_MAX] = { + NfcProtocolIso14443_4a, + NfcProtocolIso14443_4b, + NfcProtocolIso15693_3}; +typedef struct ApduContext { + BitBuffer* tx_buffer; + BitBuffer* rx_buffer; + bool ready; + FuriThreadId thread_id; +} ApduContext; + static void nfc_cli_print_usage(void) { printf("Usage:\r\n"); printf("nfc \r\n"); printf("Cmd list:\r\n"); + printf("\tapdu\t - Send APDU and print response \r\n"); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { printf("\tfield\t - turn field on\r\n"); } @@ -40,6 +61,144 @@ static void nfc_cli_field(Cli* cli, FuriString* args) { furi_hal_nfc_release(); } +static NfcCommand trx_callback(NfcGenericEvent event, void* context) { + furi_check(context); + ApduContext* apdu_context = (ApduContext*)context; + + if(apdu_context->ready) { + apdu_context->ready = false; + if(NfcProtocolIso14443_4a == event.protocol) { + Iso14443_4aError err = iso14443_4a_poller_send_block( + event.instance, apdu_context->tx_buffer, apdu_context->rx_buffer); + if(Iso14443_4aErrorNone == err) { + furi_thread_flags_set(apdu_context->thread_id, POLLER_DONE); + return NfcCommandContinue; + } else { + furi_thread_flags_set(apdu_context->thread_id, POLLER_ERR); + return NfcCommandStop; + } + } else if(NfcProtocolIso14443_4b == event.protocol) { + Iso14443_4bError err = iso14443_4b_poller_send_block( + event.instance, apdu_context->tx_buffer, apdu_context->rx_buffer); + if(Iso14443_4bErrorNone == err) { + furi_thread_flags_set(apdu_context->thread_id, POLLER_DONE); + return NfcCommandContinue; + } else { + furi_thread_flags_set(apdu_context->thread_id, POLLER_ERR); + return NfcCommandStop; + } + } else if(NfcProtocolIso15693_3 == event.protocol) { + Iso15693_3Error err = iso15693_3_poller_send_frame( + event.instance, + apdu_context->tx_buffer, + apdu_context->rx_buffer, + ISO15693_3_FDT_POLL_FC); + if(Iso15693_3ErrorNone == err) { + furi_thread_flags_set(apdu_context->thread_id, POLLER_DONE); + return NfcCommandContinue; + } else { + furi_thread_flags_set(apdu_context->thread_id, POLLER_ERR); + return NfcCommandStop; + } + } else { + // should never reach here + furi_crash("Unknown protocol"); + } + } else { + furi_delay_ms(100); + } + + return NfcCommandContinue; +} + +static void nfc_cli_apdu(Cli* cli, FuriString* args) { + UNUSED(cli); + Nfc* nfc = NULL; + NfcPoller* poller = NULL; + FuriString* data = furi_string_alloc(); + uint8_t* req_buffer = NULL; + uint8_t* resp_buffer = NULL; + size_t apdu_size = 0; + size_t resp_size = 0; + NfcProtocol current_protocol = NfcProtocolInvalid; + + do { + if(0 == args_get_first_word_length(args)) { + printf( + "Use like `nfc apdu 00a404000e325041592e5359532e444446303100 00a4040008a0000003010102` \r\n"); + break; + } + nfc = nfc_alloc(); + + printf("detecting tag\r\n"); + for(int i = 0; i < NFC_BASE_PROTOCOL_MAX; i++) { + poller = nfc_poller_alloc(nfc, BASE_PROTOCOL[i]); + bool is_detected = nfc_poller_detect(poller); + nfc_poller_free(poller); + if(is_detected) { + current_protocol = BASE_PROTOCOL[i]; + printf("detected tag:%d\r\n", BASE_PROTOCOL[i]); + break; + } + } + if(NfcProtocolInvalid == current_protocol) { + nfc_free(nfc); + printf("Can not find any tag\r\n"); + break; + } + poller = nfc_poller_alloc(nfc, current_protocol); + ApduContext* apdu_context = malloc(sizeof(ApduContext)); + apdu_context->tx_buffer = bit_buffer_alloc(NFC_MAX_BUFFER_SIZE); + apdu_context->rx_buffer = bit_buffer_alloc(NFC_MAX_BUFFER_SIZE); + apdu_context->ready = false; + apdu_context->thread_id = furi_thread_get_current_id(); + + nfc_poller_start(poller, trx_callback, apdu_context); + while(args_read_string_and_trim(args, data)) { + bit_buffer_reset(apdu_context->tx_buffer); + bit_buffer_reset(apdu_context->rx_buffer); + apdu_size = furi_string_size(data) / 2; + req_buffer = malloc(apdu_size); + + hex_chars_to_uint8(furi_string_get_cstr(data), req_buffer); + printf("Sending APDU:%s to Tag\r\n", furi_string_get_cstr(data)); + bit_buffer_copy_bytes(apdu_context->tx_buffer, req_buffer, apdu_size); + apdu_context->ready = true; + uint32_t flags = furi_thread_flags_wait(POLLER_DONE, FuriFlagWaitAny, 3000); + if(0 == (flags & POLLER_DONE)) { + printf("Error or Timeout"); + free(req_buffer); + break; + } + furi_assert(apdu_context->ready == false); + resp_size = bit_buffer_get_size_bytes(apdu_context->rx_buffer) * 2; + if(!resp_size) { + printf("No response\r\n"); + free(req_buffer); + continue; + } + resp_buffer = malloc(resp_size); + uint8_to_hex_chars( + bit_buffer_get_data(apdu_context->rx_buffer), resp_buffer, resp_size); + resp_buffer[resp_size] = 0; + printf("Response: %s\r\n", resp_buffer); + + free(req_buffer); + free(resp_buffer); + } + + nfc_poller_stop(poller); + nfc_poller_free(poller); + nfc_free(nfc); + + bit_buffer_free(apdu_context->tx_buffer); + bit_buffer_free(apdu_context->rx_buffer); + free(apdu_context); + } while(false); + + furi_string_free(data); +} + static void nfc_cli(Cli* cli, FuriString* args, void* context) { UNUSED(context); FuriString* cmd; @@ -50,6 +209,10 @@ static void nfc_cli(Cli* cli, FuriString* args, void* context) { nfc_cli_print_usage(); break; } + if(furi_string_cmp_str(cmd, "apdu") == 0) { + nfc_cli_apdu(cli, args); + break; + } if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { if(furi_string_cmp_str(cmd, "field") == 0) { nfc_cli_field(cli, args); From 0563697eab5567e624b1c4792e084071c88a2b25 Mon Sep 17 00:00:00 2001 From: doomwastaken Date: Fri, 28 Mar 2025 14:32:47 +0300 Subject: [PATCH 056/125] fixed metadata and images --- .../external/L1_Doom_128x64/frame_0.png | Bin 1495 -> 733 bytes .../external/L1_Doom_128x64/frame_1.png | Bin 1502 -> 757 bytes .../external/L1_Doom_128x64/frame_10.png | Bin 973 -> 498 bytes .../external/L1_Doom_128x64/frame_11.png | Bin 1070 -> 548 bytes .../external/L1_Doom_128x64/frame_12.png | Bin 1138 -> 578 bytes .../external/L1_Doom_128x64/frame_13.png | Bin 1069 -> 567 bytes .../external/L1_Doom_128x64/frame_14.png | Bin 1065 -> 558 bytes .../external/L1_Doom_128x64/frame_15.png | Bin 898 -> 488 bytes .../external/L1_Doom_128x64/frame_16.png | Bin 930 -> 496 bytes .../external/L1_Doom_128x64/frame_17.png | Bin 937 -> 498 bytes .../external/L1_Doom_128x64/frame_18.png | Bin 931 -> 497 bytes .../external/L1_Doom_128x64/frame_19.png | Bin 923 -> 492 bytes .../external/L1_Doom_128x64/frame_2.png | Bin 1498 -> 749 bytes .../external/L1_Doom_128x64/frame_20.png | Bin 1159 -> 621 bytes .../external/L1_Doom_128x64/frame_21.png | Bin 1284 -> 645 bytes .../external/L1_Doom_128x64/frame_22.png | Bin 1165 -> 612 bytes .../external/L1_Doom_128x64/frame_23.png | Bin 1306 -> 655 bytes .../external/L1_Doom_128x64/frame_24.png | Bin 1159 -> 621 bytes .../external/L1_Doom_128x64/frame_25.png | Bin 1307 -> 661 bytes .../external/L1_Doom_128x64/frame_26.png | Bin 1069 -> 561 bytes .../external/L1_Doom_128x64/frame_27.png | Bin 1131 -> 583 bytes .../external/L1_Doom_128x64/frame_28.png | Bin 1101 -> 592 bytes .../external/L1_Doom_128x64/frame_29.png | Bin 1035 -> 563 bytes .../external/L1_Doom_128x64/frame_3.png | Bin 1558 -> 757 bytes .../external/L1_Doom_128x64/frame_30.png | Bin 909 -> 532 bytes .../external/L1_Doom_128x64/frame_31.png | Bin 736 -> 389 bytes .../external/L1_Doom_128x64/frame_32.png | Bin 1169 -> 575 bytes .../external/L1_Doom_128x64/frame_33.png | Bin 1212 -> 602 bytes .../external/L1_Doom_128x64/frame_34.png | Bin 1269 -> 601 bytes .../external/L1_Doom_128x64/frame_35.png | Bin 1237 -> 623 bytes .../external/L1_Doom_128x64/frame_36.png | Bin 1288 -> 623 bytes .../external/L1_Doom_128x64/frame_37.png | Bin 1206 -> 580 bytes .../external/L1_Doom_128x64/frame_38.png | Bin 1240 -> 604 bytes .../external/L1_Doom_128x64/frame_4.png | Bin 1487 -> 739 bytes .../external/L1_Doom_128x64/frame_5.png | Bin 1161 -> 596 bytes .../external/L1_Doom_128x64/frame_6.png | Bin 1181 -> 618 bytes .../external/L1_Doom_128x64/frame_7.png | Bin 1138 -> 597 bytes .../external/L1_Doom_128x64/frame_8.png | Bin 1193 -> 610 bytes .../external/L1_Doom_128x64/frame_9.png | Bin 1201 -> 611 bytes 39 files changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_0.png b/assets/dolphin/external/L1_Doom_128x64/frame_0.png index 937996c8c0cc0f45cabedf1b348a94fc9cfc017e..974fda986836d451e417269256139d92264c407d 100644 GIT binary patch delta 721 zcmV;?0xtd63*7~f7=Hl(0002`twPcO00N{*L_t(|oK=!th>T$r$A9N}U(N3N*kLzq zN$+e?lFUX@$h=ERLMV6C$c-CvXOr@bi3{?PJ9oPzn_{FTW%2sDqlSFk*bGri*kxy! znVp&A;+7U`hSs_gy2Ac#Pj=)ce zv4rRsh#m6pK}1!3@Ic}P78+VY{Ra>`)Ln)48tT{gQP^`?X#bJchXH`OR_+rQ5N&jM zx~5`?{<9`_$e$MmiCo=Bi(>#Z)e|ai*G-9j=?ZJS27kQjG1WY*!DI$i!K($TW!Qnl z3#tZW0Ki!t)&Nh_s%6|cR^oqD4R8cnaFgNILm$;5`*Nu5X@EavC+Z_M*#Pg5pB6nD z{0e~{%tuZ~kwc8f48TOdbQ?oY;EbE_Hb&>p21)VBuaBNxUIb110fuov2NoSlB8Q{J zJE3B-_kSj!#}=Hcr+iO8wIGK-k7FnT%ck`vK+kv7js4u%mal;v$pwL-f<|MV*$U_h zuLl^=^3Ytxf|NE#+u~j?~WBdKZ`ZCQ4ESaQD0#e$e>+S{~ZAZyX8!o!lsh zd+}PTaSFvO$jR2->kO5U^aH&Ywj>&g7e3J4yJX-mgtQd>O9||400000NkvXXu0mjf D&hlF? delta 1489 zcmV;?1upvC1=kCZ7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000GvNkl(_e^ z|L*M}z>)A8p7sUfdXN8QO!h$@uIplr-+TXKeCPw741J=ca0qZTjzJ0G@pKB@j(_8E;rycj8^I|6 zP1OKddp>P{6kro1Bg5~A=STK@+CHrSp8bcLz=L-Mz=j=Ff+&7QCypnO-TxavD{@vl zjS28EV1x`I1%JTo97V<$p8`z*0Fta{!KDBrMzabVrxIb6T3HG}`@wv&NuUxS)9})m zClP@Qq^joSF+QFLT$2qk3wXUPN;E$0i|^qrL3B0=SOSbNe{`WR5q6P) zGk!G*Miihz3El{>()iqcSCc?0$KvCPd5tJQ#XSBHV1JkK>HT*ofppKRxr{16>>dd??hvu2xb(3tMPjP&x7wfRSMo6xMctqLsNhX=a^LhJdWoxm)*SH z1)SpjfYmBsJ$uF4WGDbPKWc1l?s%MG1^5K---#>*kosBUy%gXy?+5Ho4Xcr<09-$7 zyeS3vRDYwaM5Y2r<46R<6zcl`-BwD40k(7?U6^xXtxohybq3;8%G+tKT>jC#% zD_#iU&(_*%WEiiwUBTE4yu?mm@6R0!> z$V6nJ?tsh~fa~iW^JoG@-+G-|)#NZ+2grKXqX`h*CRWxAW>Jv^(7oS-twCURt-td9 z0p33|#?OiYX6I5y09tvXsPfVZ65wZnplf#gj4UAI8A}zwBEiX-0QPq3ff*#5Re-Fu zD}RpxBBjeypv{@9r;n&v=G(v-EC~WDjh(%fNTt(k%wz$XI64c^kQra#F{Ep=7eA^1 zRl)7;2%s4r+C2;FF*@|C2w1%eU_I|FZbN{~h0szddcG=K@fv@m76R~Gdo%%}593)> zOHNmjK~jL3{a$+Whwn*o904+m92DH!G=I;1DwIGXYi5ecy*8%f9``qbMyqX}mn4$$ zVX;<3|I&Q8wg~Cy^U(1m9H#&yh#DWxX=7Ex`&Q4RQZwolBEYJ}@j_!goX7p7#q?wp zt6~6do>oPbyH+|!ZFoxspo?Ku?Qmc2`W^5p06o^8-BZD&xD^3BhKF`fq`#90(SIy} zzK5_p-HR{*R&N8G7kkq@E2F^U(e~=+l;)^yQ+Q6Ewea9L1@P?U5j#6xfKI& zgp|h7+O4)B0%R>vqz>-wC-wJw%I+)xOFYe5G@^_u!tK8nj`u|^2=dexxH>_`+~^Oq zX>|b49Psmw)C^iXpb%sk1_wXfb$^_<(0bFkncJ@^5hSBaafUXB zuOfit{i}@+kVxPm2bUfLq)P3Aj@R0t0<2!BO6)Q|Kr@h}22vkN0&Q!6KDVd?WIzgt rb{e0~ff~va8_?^i^lL%lbzSX05MgtY=X?gZ00000NkvXXu0mjfr?0ya diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_1.png b/assets/dolphin/external/L1_Doom_128x64/frame_1.png index 9996dfd6740c5f568cd30f0e9ecd48e1b0c8e2eb..3a9a3a71a77cdfaf53541c616b9ce4c9b6bf9c95 100644 GIT binary patch delta 745 zcmV+Ba&N_kT|Q_|q0abb7SX0@9tj z&;lm={?X>W92n9TV1Dh-v?>N}s5W0KU%mxEZ385Ws)jZR8o-VN>|{%`0?s?{0Jeh3 z+*3ttyy^p8AjyJ;7}A;m_E=2ju2yjw(K+CRha~e_rXAHK;6?(IxuX?gqM8S$ZX(J2 zNP&c-S^=&lFn^iR^y&uq!bg(%fp6W!Yj6O+8?o77%;0Ver}kLcF&-ecK1-IGp}kpA z_{dn+53PdO?5+L$Db+gW8#8 z49Flr=Uc>PU0fgpFdv|Hw%EwfPM1aOco&dXEmbS>@EDR@srN&NDxHHM*00Ad_25i{ z+SKYgsEy})_j|~9xgY^))z`Xowj4qFr`|+ea?r!l*-t?(`W;^VSDq~7Krh8QfVirL zN8*($n18#U*|zmyYlmk6{c+FFo*@91f9eKg_|KpoeP7q6D(LlXU?{=ANB7Q^Kz_*i zz5z6rIOzwVm*Xj1KyZF}u@@;%XU|R2OQP#tMI={M24q!oq7bK z8eaSO-8T_=ke;6Z8k|tWu&sC}A}=RDpV$s&nfD)K&(z&kNB2AUOGZu~ztN>~W(C>VaJ8ICprxbgBzPM1T7}^{mn3+W@-< b7jL}>UAZp%UI*(&00000NkvXXu0mjf$0lk4 delta 1496 zcmV;}1tOsg7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000G$NklUEH?&-b%Yu9^s zfA;ne;7C{*=&yj908Bi!}-z5 z=In6F@F>7$j2zFcc({gFIzG>Ra{auB)E))c2JA%YVA>8}^Q?Rgj{a*#RV(fB z^d2ri)bJ?4MsNx+B1PuP2RsU}37i6GD|lw5OZc5NU}0tEfWHNjoOAP883Tj};9+f~ z{T)CnawAyVMStKT01Zm47zH+Wg~zE}(I*Qg0z{mq6*f*K!YZ|jDu9$dL@~?)yiW2~ zrXqb*f;yv0b~*c2$7YhC_bz7vuV0G_oDc1B9~CK%cRZGqEW1BX5Sutp5nG()nD!t4Sc0WASmtxPNvl0NDBAPI`=FVy6;FeO8Sn zLjk}}wBI)c*zJ5ej@2aK;vG*6*5EUdsQ}tIx%ULX&U7jGK@3$20Jb%IF9kSl^#gXNhSjK004t_qfNyokYGf+_ zCI$D&Rew0I>uSH%t6#EzDv?&HVa9I(+>dO~9)IHgs6F=^K|9j3Roj#&u*&Lh=C=UO zj-|gh1(SJQMW^$WQ>!Jkq}4`_Wkdm(PxH zYE_d%Mi#)e8QGwHw{|!IB3Z|$kYKd}NH(_+AnPG0GSeh%6C=}ZRvlnuA0Kll3j%4C zi=t|kW)h2*PcsQyp#YINEmZ*R0Z+^Xq?$UM&r+D|7(jXk4dq+FiB6UvIYX-1&yZkN z0e`f%RvaA!T9Cab({ojbDu8B_>tlo?31A6cGU5wP?m1f(M2IK={ceHQ{x|~A3FnSm z8xvzRu@TdfVH31+nbiTaM{aR7WLEi zvw$(ue{fAAopmhuxjo~?Z9@d8n13X1dv2BBHrzNZGD^SCJgX+l)+|8UzDCb)o!4W6 zK&d#xMZ?hEvbsG%UZ(T$7$qlJNPt(k78qjStO1TWgbA=}&(s{vtqv{VqbU`aZe^*Q zR#(%zsup5_#|z z8X|yo<?w6+5qQNiyg`Kl9xg)d$k3l8o?)kIuoCh(mpEP zloTVy(=vqK1Aiqfy29w7ERa&WD71j7YV~7qvMotDM;I=+vu+a@aJ)PVIBmtQbUp?b z97+m-$H{F8+)CF{WoYvi?@SL3O$p#mGTi y^v)@UlnPtY;ad;@OC*-X-OdM$NRX)poc%wZ=U~E#yr2gF0000PROL1Mt_TvS*MThy?b{+@0C_@nt})GmQ|=q97T1)Oe*o-tYY*pv45{pQg&T&BTNF{ZZ*Qf zRb$4V+NWGI7)MYdN0@+fj_{#yM7d1d8o{o0Yp~U+!FH!c_@;9Y|Kj+oBbGBp51mt9 zC*1D7*sv{TJK#r30qE^XPnMGGuu5FMr?MKu-ez4x?weZX-MK8fBJYZ=j*#VKw=D`N zp0z~@dC(T0A%Do*B8SXtiE+I#WM@4tnQC;!_Z3p^?kR}73R^lNS_0rXx1+vkB{ zTJKo=JuD8Vit9I>?%aW!2OG7pq5lJ>gM&DQ0FI(O2x0zUx_t3&)yq5reVH{i^cdjj zMm?7a9zevPnTrRIHQgTSXCL^j)4R3E02ZxYE&v?2x?QyZCFZ`x;P~C=+q-B-((1>>Y amG}b)LjBq0gW&T30000v+3~*ArxT7oR*aN-nMOD$4&(h!p$LB_|a@i1t6?Y0EtbrI6(na z1Hhy6Yje-c&e;l(oj`#d0Q33{IP=R9JBA*=&XG01pe=9jj|S%nHNbHSKm!iX&Dk;f zoW^6M0yt6t%zu5~szJzQdMW_;Pyh-JKCM8^8lb{z1*ipDdEQIT{W9Oq3UF*6ptcjJ zEuds!=~&qZAb4?pu?67i*b!Ua6ejxsPHF(o=`$Kac#Lwdc&;64fMXS41vr>S?>QBq z18xqk2B7_cnRZcC=p_}Pb57~&()YEf6{C{tEY@@DU4KB!iEqwbU6)|EwaGq!aIRCy zPGAMP8jvO1yBYDVR3NFuGMyDCr|-ACw{g|uA|pltC-a~F8z%l ztDvCSFFl_NASdC%Zwg06R-5P_l2iy6j`&k?BXa(S|rQdVs0l?#2?sbj( zDd2HykCRrx$(`F;n-B_6yH+v}!1FJ2@N3#|0e?pAr8czgrMy>Ln{c~;9_Q2X%4-(S zY3g`dCvZP=w&CFA2-yda1`0l|++lDTPZa@wVXy+U#t)+ac#$O1S-xMnSEs?^3$+W7j_(!Cdkwb>cpG;&Ms0perq&j-hwe@wH`&`WOCt!pXMaI6=zG@j>kdm? z1h%5g!ZEu90Dz6HZ&@#$zo`IHY1zp+C-CL-k{YZ6Xjhsec;EWfm{qlpz^&oGB5<^z z&}KKMb9lN3&cCXSpc(9#{e>ND|5pQe$~=AmU)eK)=XF)>188!J^8tL{i`xJI*h4~F lcq;-qTn9ihpA3ND`~fh54`KcrgnHA z(XmchgbdoGi;GJZG17m)F;hhmk_-XC#nCM47;tD-ovtnxx(E)6m3pf~MTcIo#WV@| zIoyxDuXv`*xew3zcn`4nOi7IT;K5Qr5{eV2wKQQGG4awQQGfa$k%Ohz8qLG;)$Wgs zn4|gW{gry^2*6yrQQaF@Rm|>n;}9I(kwb7;n{$bald((GekTrK<+i2bj0Ru48&e*Kthq1dfAyg^g3k5jM>Wrw^^N?hvmc7My9L4*olvz=N{wxSNBrP1Fjo zJR`>FJLG1a{(q4qP1dqbhXDAU%rW5XvGcYeJU25J-KY+?+#$R?%`dN%R#pZf?R z*gdm}z#@Q^hNQe{N$E~Efpysq(1%G7JAlO}K*a}&{dC&auaIy1nWOgkWcxWck2X5# zK7MXLg>zf#)ni9*|9%DX-i2a%>(Q_Rqu$q6Ql+N{A%B=R*U~BtOdAMUtEYYV08NVh z_}1TQxB%>FbSvHIF~ET}O99}-+WG;2Fk1m0=N|002ovPDHLkV1nQi00;m8 delta 1061 zcmV+=1ls$g1g;2>7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000BvNkl$BWT$l&&m z+fNVtxJiP#^V9KmtZ+Vna{#O|`Ub2@re9BCTH4Bh;DMc+41aJrUd;e_eGhgOmDBq=TXbm9zAp&U0bfpJ?u>CTK zft_|qD7H%Wa(|h9Dg(T_1_01IzksXqTe7i^tN{Wtz|7!F1|W#U05!cd7+b+v3tld> zlK~(m18|@nfE8H-R1k>)S~~GL-y`Qu3~>A;P@-_|Z}=I>E<7io&u|Q&`P3li08Zfa zx9ri@4pdIg0U%}#py};cFkC8 zwILz{9N7ins@-Cj_gX9PUPwAtbpgjs0(%@3fdQy|X+N?CXvlv9q~X)5_GmXpEa^DNBASl=L z*l4{AekK_J^t4Ik)u?*bnav#oIGbw>P-{nbGeC$*V1f0hz0Pz?Se;*%+nrm$1T4$=O=nO$N|X z%n6yf60-wTJ2Ka-V;LZtLuU+;W&_(BWk0#S`^NyI1;q@U;&2M?3#;AW{OdXhnuUmi z9}P}mt$$wzMazDGn3>drNPCO-(RB{sjguWt5%pa{2LM2<%(23AGB^w21E3&k1|FS` fV*=n*L=W6QqvX9sJo0*p00000NkvXXu0mjfGNa@> diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_12.png b/assets/dolphin/external/L1_Doom_128x64/frame_12.png index 133374545beeab08a20c801467dee2404a503d0c..973f97378170fa9d9d633dd3f4d80c2c90ab8fa4 100644 GIT binary patch delta 565 zcmV-50?PgJ2*L!A7=Hl(0002`twPcO00Id~L_t(|oNbdmXj4%bhM#k9ey&NS1r?eM zNd_0UI5=rBf{0@#sXEj#dqFA=iGwIO=%x|Tx&>Ua3W6scwBTT&i%`Kd9aq?}xh5~e zX_ZyKA9tjQcX7sCj5*viZZYcMo~7Q!9Nik{VmUsRwok-}iG5`5M5nbMw<*VN-MT|L z>UeHymO^5x?SIpdP^$o(xhcc1ukVUDxvHOZu=~Rmi6m|3kmE|^ZM)g?j|!T=;mWjk zY9`XGdc;&L_!PdrcGauiUnlZ?eB&xyj}SI_Z5~GmjhkRp3A(I`3@sMJE>~bUN|hrH z_*Lw0&K*GJ1<+jp^4=^Rsej%aKHZbL|1Nv$1vuDR@qY=uWZr@sxvjdN!!~Mga9DT{ zBpr95-|PhrS#LnvSjo4%q@)0|LC(JqQh*!IvL@dF1~Lwa4*(mHSxNvqkz3yYa8S23 z28&NL6@Vk8RmPzF^R2Q0W-8rYAfa@}`@w8Tn2;6`R|A|B5$PJsfD6D7VA zlv2tviY_AJXaGb+M#ek=01W^mSeOy+8w6#9+j*~l|5qC04`<`g00000NkvXXu0mjf DHNF1x delta 1129 zcmV-v1eW{41o8-w7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000CeNklO<&+|Yj<zij)G5M02+|9K|uF*>8+!IFw2J71uTR_ z|B{~E`@M(yYM9wu*Jc-Bpbv(|>D-<-&%t#E8YBa30H>=(5YNa+1~AkKUuo;s+GnZ% zXd)y7bk5OK_ndALu%4>|ww|HU*DINh>jF3L`7ldJ!yPMVgEkqUAzy-&VbUHv z#ObZI27etQao;Bc{D&sHse#_oxnyk3Fv$Wr2_!N#z-LNSD^>aQGj1*ZZdA8Xc)U&l zf-}I3fm_2DI?bc63;bE{+|}L9)eNAeZ_oLHwyv@r zXA4m2-m4b4f&q3oUt>UNLg-ltUcmsC&^TXXJZ?6?$zKgGI~IU_|3ioeMqdXzbmY#y zq6^Swq;{Pocf?>^JF2Pr-^>kqGl^^F02%|f*yN4lTj$`jTJwrl0mfRn*h>`wK5WQdg~QI^{DsU^ViRMjPli80JpaXJfx}jSjMV%w^SI?HTbi7&*@d~ zXBfZ|VHf~F|I;pf-pJm!-~x~8BQXHiR^lsn)>RCEjihA)eC`g=AZRfFMHB`wZ3BCS zi&cxYvsI%ySn9#mHrFtK77?6J&tEYh`hRK$m{OGN-yHxIR3{4uB?B;WTlYJ$O1CS! zfS&BAXbp$n$V>)+*x4_^LdRY*wOY&(3U6 zaX1AX1xEtsU-MrCSt8=#M}w1C>*EI@QL-N(b|#G=l1(eHJx%8TRyf(=6w#k0WB>rf v%p5INOa@mWYyeb5&!E#0J^)U|DS`V75FJ$vH&SPt00000NkvXXu0mjfOW^nP diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_13.png b/assets/dolphin/external/L1_Doom_128x64/frame_13.png index 00ee5d0474308cad4065cd0b4e6b550c09cd2edf..1a7e06051403e2412c3cd3773a46bc2182dddcf9 100644 GIT binary patch delta 554 zcmV+_0@eMk2)6`~7=Hl(0002`twPcO00I69V(D_R5#PJJqZ|vD%|WxPP!SpY}c8PC>2uARrzWz`SU`Q2W=fa<1Fzvpg@*Hs0hAcn~#(H4L352*HE=dIdQR07*qoM6N<$g5bsm;Q#;t delta 1060 zcmV+<1l#+!1g!{=7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000BuNkl9Cck6eLkN*Wx1DX z3;7TE(?kEuz%{sO#-}Jy9jVR2PpS? z%h~o`rI#ICyMpOM2c81Fo(gs*n8@*7(TV)C>nY$!4p3y7Xp1T*kC!sG$2?HqNq~k< z=N3;Oz|kC_j-Zk9v=9OK_m)!XI|_yi5Xo6^#IB ze62q#1?u}rfPb$d5`d4VU6OrTf2B+Ud=-@dJm{VNdg?o0eT~>KI6-!$wDBHdGIll z01b^2fREjBYLA^Gb4vnjCP2AoiT+-@>P1Wf1R_8yDSzbsNSNPcV-mnnTKlQ%X-^BI z{kMpa1PDNY+CF51=Ga*~OaHAvNCGS%07AReUYpaby;?s=NdQH??GXj)KCF3xhmh?_ zfQ}L^T<;lMf3GdRN96O8=Ny`iNdRuF;mq%C&%c`;W7IC9B!DUMd)rCv%T;XTpGU_T zDJ9<|0e{FpA|+e6?K_nOXq=g=A`X2{0!+$-0HZlVOQ>J&&=V9$0)VsHI})`VLb5Fh zFrZNatcrTxzcentx03=%09I#Zq#?3!n|9{{l5bu?fE|%0ML)mC>+GVys|m0=(zvtG z*^cZ&eIx-4TKOh$M4UEOA-h-U)dbj4)_-5u)qlLCwn+ekdI+#fTGp@CKV|1@2vFK+ zrL`WaU#@bFTOC*Gaw=%{^x7%4uWfid0eEDh?3-^O?Yu-|c+QLW+j^fM)kSvmFmWj#n)_SG^I+XN?4W(QA8K zzJKXGPDd1m0ClO|=ijY}3XAwADAG1@L;{4#0Yn3VlTI&wEy;$v0rKb^U{sM7pJ>f*2D@^ABLo=Lstx5O&w29xUQd9ii;m=Z#69{cV6^|J@|^1{ z-UIaXdpFJ6+zO`hPDFY)VpaEl3rB;s&VMYAO%Of$i##{|$V;`}am`7fw##-b%w0AB z(H>h{QEwezC4dzzcUqh$$g(b0B0vIoXPPsL{^%!ZRn|TuzO(z*~2W{-QhB{woKF6#Yc8qGv{t{p$K2z*A3Ie4^NM3A+J^?txHE(UL%<&>b5f ewO+XaUatR6M4I&>1rC`200007=Hl(0002`twPcO00H$$L_t(|oNbf8YZGx4z(4PLeL66pA2tx;S(ZT!hwo{z9ljQ*7~? zw0RD9-^<=25o0j@R{P^{ zP-o*lV$)OYKo=wmz3%N0S4J%R|-OYpU8djseUrC8qBU zA+VB;PhbT}q6a-m5@x3i@y3N8XYPnt1Wq0%9l(u&7ZSkKGoWe%rH<*gb?EbbXH@C# z(dr9s{+eGiz5HI?fO9L_ZiJ5Z&b=z+t=W><^r+|G(UQxhBk6RA>=#;t?2#{l>}ca+Lb1_%l+vXcSIISjx>b}~ST%K+2?d(J2whhvff{v#p- za5`}M;C+eS$$tQVs0=`LtGMs`<3q=c^vxWgfrt!%xUQ@D(a6AKGC+yV08%}w&XQaq z833??0g%d()~Q}nP*&h{|0V`7Z3RbV0E_v1j!@6N7{GEpw`Tx}KHT@cYl_~Yb4jG+ zC_ys7WN4joG#;IRewPdos0yfflKo3i8G*`91_;Ig=zo+m^uyi){Z9IPGJv68h#mu2 z>dRFJ5+nmm(5s$vm|d!B1Hp>{w*QMD4SGhX`pwc+>jc>e9L%GQDAb`v|1%vGlS9ea z+1u%M4Dggnd(ZcDvtIDgRz!752589l!tA^NTh@5rg8{av0-jJl>V@*S^WHPw$SMG2 zz6I5TbAO1{21jHSP;3p;YyNQht#*i`bAY#$&w(>OZQF9=R^r$kppKtq2u%sL62~#X zjHvHn)DT*YqZnXz)YEySSj_^*FhIl%JOYkj08is<5b0~nis@KNRc~y?3F{ zBm)#VZKAvuRnOY9xov<(bBh5uwm^9lNAv*@+O2}ltC8^*xGhjUxNEMz z1%EEwXxu1C^F)2eR+QHn=)pPnF*$%15sZ)X zTkg+ZIlvMIcmtHP+5sw1r#J7K4A7C^yIu)v-HxmRq;o`tr2f~)N(KPgz3Yg0qvI%; zdL^a?Y6rlHv3#4!0Fk4=!ioj7!SvJ-#D7U(Pqb{Vg`0GID-4ZYBf0fnl^%FA!6f4f*n}v za2CQlKt+r_Qnf0000=v8aRGGDl(t~KAlXO1Ejwe-B?$|6cZXp7xyYUCLxlzZ0Tg|_?SGk* QS^xk507*qoM6N<$f^AsUqyPW_ delta 887 zcmV--1Bm?S1A+&T7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_0009tNkl$LVgV-C9yF{!uqT^r= z($wlb(op$l0E@KN5}(u7F@ZkQwt-qH8l^B4WjpxC0J9f0lC}^`5CQWHU>PMVO%TO^ z!;geX8QBijp7NP3#K@y&$oy^tk@vLaV6W_JP59NOl)$b7tSbGkq^C}i%5|B;svF?;c3amxHm@->DB8ub0gh9yRqR zpm07AQ4=WtFhtM)bFO{p{7xX!z;RaptJ6Jt^b>)u0b10ihmzI8d%~Roa*ze~5dB18 zYk(+t5ufN7V0(@Ml<^e(M8^QCcoUzf^IO4(cRY$ubTWVnUd1OO`UV6@jF2cIyaNCL N002ovPDHLkV1oMym6`wm diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_16.png b/assets/dolphin/external/L1_Doom_128x64/frame_16.png index 6aa7a7dd328af467ca5aa59a6739ef8f1c8d311d..4dfc8453509c9fa6c8f6282923515a9f508ce0d7 100644 GIT binary patch delta 482 zcmV<80UiFL2k--s7=Hl(0002`twPcO00Fm2L_t(|oL!Q!j?+LCMbC^4j?fB1mm*T8 zqosplrFB8ERQ$q+B+UnpQwK2d zdT=v1=!q_UNIU0ro27#rf$}m&b`950FfyjuoG{Z zKOsIAzIK(5+6R?ZAt_J+_j_Of#!wH@*%c$myla}Mo^7O?U6?|>uyL@IKkrTOgi)q% z=%W<1IC2O5g@2?YA*vT~bV}-}-w{hoO9R~WU<_~p9K8z)_zZk{*n=sMIHZ3aa1#K> zrnp!5DaTN9P4^I%oaOcyF5%28n&c&_;3@J7>I*OUxn1mo6P*t&>oL2spJD(uSKRK6U0Xfi7vuw|3~!+`HIkZF`XK3h zP$=hF$YUfemp{Hp$^+2f-?M$tBB|}})OK{RNVdLgll^VkaR4|3cZXng2)b2l8^9cZ Y|BnO7Unek3ng9R*07*qoM6N<$f?7)4i2wiq delta 920 zcmV;J184m31EL3z7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000A2NklIQA9B_mR^cUwgZR0tOo)nV1b=90Y-!PR__|ypyiqfN za}G-Qm}`VLDhA+)ze@O+&VuEG^Ad4S9Ut)Q8f(e=o zU_pG3uWPG-aewsK-2`j{SQ6jkoNKOA>OFTh0m}eAVbt<6YG=V?hL(Xjc4)k~{=1r@ zx*gmS`r{3j3qHdUAQZc2%(cXhQJ`pmlTxCmGMoyY1&R@Oivn2#p!NP4^+9^ySq$w3 zjNp?rEsd^i0;x2zC6WfvZ0MBeEk;0yOgjw&DtUk$HGko_M$j}tZwlEeUB|+E8YY!q z&3(qnCusJ<6NLBtivSwED-<-&6_lRENkFY04y-e629 z5v|nNsY9vOg_(u=)iB9kQY-7k#MCI=L%?VQ^!|Qz!|%32_=^C@6RLR9xKe=Bb1h#- z?-~MT3V)E>m!DaO)|HB-`-W@-ASFn0Gk>jX<*nsfx^MU*!oSJOL1T5&TV@ym&`qGe z3P`P&HUAD~1nCn^;k%=nfMo#5WgNFW|J~GYG&7abpqpUYpG39J9a1y@(sz36BvDQc zWD~r!Db=uBY^aZVRU)5Qh3xTpnqxrt%h#hh`BvJ&yqiil%OW&-5BD* zx)@@SRaru7?PWFstfUlOtPM9WqzMT!+#$u;{LlWB5Dbbet6W30a_=k+=idk;}NrfM4$#Jt*u)(lyWAR z9e?T(#U}zZKuWNYhKo&b+8AF0$^g0ETH6Fd3iYYyqV|5G$(KWG)WiwT0>+7%k~z5L zpGfiF!qFQH{Tw5D?-@-fSDS`C#gtE|FFQzg7s<)P7-N<1dKa^(@_eGq_zqmj(;S{1&}9_bP;l#ky=PG;PH)HD+Ipbr!G4SxnApGXapNq$e a4*Um+*u45pELaf$0000nJK>gPy9qW!0ryP{*Bzhyno+g4{5k=MihmJD(k$ zmc*76EpPuC;+=;SGe8tZTaeTc*9?DA$pF2=OO}JY-(4m|Wq)Y~=n1y8=x@ZaTqAt5 z%m5(-DB*Li5x!Ys0FL;(gwIKhaH0uB4ZxjEDB`C)&vT>+L=0eA_>>b(Fl_+zTHniQ zCipk=VQ=CS{eCA)W1eBy03OAUoMeI_19%oca*7GM4RC_^krPbNWdKX!OD*EOn}BTq zOXBCun!&RPSbqkvxGhS@JUV`B-+6?oZD0=C42i<`&fb#nUb8^+aj@moPc$|zuVR-F z%>YDx(q>6~kH)AP!20aJv=PYw8nYfHvv|t_uWNwb*`Hsqkj7i!Q4qTm*eguwo*t)< zYXVt{kAqj%{#v`-_7F_q<*~8&E}%v$SaHwZ!b9Lun16a4+(Rx{2;t|i^uL_jMJr5j znz8;fz>2`83&dRXT3@?N!0q1yY9(N_X1B6Idfcmtmj&scU4V9N?dhu)?9!#wQDO3j zNZuLR2KGK!kqTt1EvbGu?RY5^O`2;-Kkjmz2TM@M9h$8gVNc8B%_N#OTRb#5cLfdwf?Pm#mvl3BDRBW zg5?>Yv|nENI+z)xw}0t(M>T=!8lWe@d758YS6A-)(M|9WQCNNRXEwlZW1AIB^S}qy z1Rss_^w|JQp7f>dAg*P!S-J+0UNFv|ENzu9{FU8FO4Mv5`kAqP$X#k0<<=j4y#go9C z0b0UHojQ6KK4QuM9C1cd?<(QZFOQlrK<{Fe8+ff5k9Z151ZsfV-nvJqnhCU1J)-zT zfPV%k2{seB+ytl9_!cY!Xr8LoE?vGE0V&m&`bC}nL>sS#muQKT{t75Rn5mhA+y05L z-WHA;xRsY!BtW12M1X669#D;G39%A@?D8F0nEgceHE~O@B0iCz0nkspE@fQ5Ds~5! zW~gA|u(5It2&Iw&bpEW7}Z5FR64OhuaqK*B{NQsoYDN__wPQFzz8ch%fa-^_e7 zvj*Tq9qDhx0HzUC z4ZxGw#7L4hqrwb9HUewC8{d;$189PxD2C`PD9S;>JSY;2!3WTf&T?u&=shR^Xt%+t zL6Y=wvpQ7FvqvFk7-byBLbrEm-`p&gvnxsaaX7bJCgv>67oW={rI_dhrh| zTYzMti#2HY;(wqIprGeRh3>tiI@UQCe{|n>$t zJqXp-H$L!J(9hlNAvn>8SYutXZ_=XM8y*h2tRC|V>Rbp~!zYMEyLUR5^nFyQ=5=t2 zk+fJ`eUns=K!1PF4ndEk-o-9Pv4rVE*k{T30KUe2=#Qlpb6I Z@E^)|&6f*yjcWh^002ovPDHLkV1nx3+s*(0 delta 921 zcmV;K17`g31EU9!7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000A3Nkl@5?PToy?qTk=-vF|N38(`-sImrY~29SvFeeg~(f!Y8kh#xt@1S$iZBz|Of6Nn9P zqWF=WO&~JB&VLiW)9G3Ua?ql~+OWH3fvN$#rv96?WSC_DbTnp&$EN4(m<5Uk@EZLQ z-v65s-q}6_MBz1&TZ;7EvOxBcFz?aNY3Zkz-`0zH29T!N7?n3IujSPMt@Top8s9{( z83D~CJC%X1yMaV)vuo}D?*wif-H(N*GwmFuW4O4dOn<&m_%8#rO#VU$CgPX=Chglr z$FyajHgeHTuuDezV}RL%i#R7hFxO0mXMo-)shMDvV7nNl>4_ikmV6&TOB&@hBUoIEx2N5t^7OtTv;nxFT$s_3 z-kVW8-G71n5Xn2by6&aIj50!RyS$(1CK$d7cpCuC4WnF}E$vCJ7e%uyC#wUe#MBa? zi7aW9TMX{VlEO`ZmA=s5c-VUZt2^*UX>G0DiOiW`cB)4dp9s(ZZ-Vs< zTz_hU(`tN;q5)U2A-myXyI4FcEp?b vM8+SBM!xAW8js==8E1eizAy2Kh`s=V?h?3|j{YfZ00000NkvXXu0mjftS_^g diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_19.png b/assets/dolphin/external/L1_Doom_128x64/frame_19.png index e47cbcd36a58027b073d1a2ad56e76062f8d8582..efd1d6b0e6aedef3b671eaac65f797a2fb3e1771 100644 GIT binary patch delta 478 zcmV<40U`dI2kZlo7=Hl(0002`twPcO00FZ}L_t(|oMn=+ZWBQiMbC~`*g`;-ZVRL= ze?SKXlD9$fH&9tL&_Rh%P!=jm{s2BB9YaM)J|I%Ih=i-eQY^BLy?ZHk#xrYPHFM{@ zH}}mO0H$h)V{92$eq(@#CF^A@%*N8ANJxrj@H#4CkhHZyNPkC?R0JU(OVVkmG0Oq+ zAQT0_yVxypuE8v?-e-}K$>{vs=q4sa(WT)* z%p{ph!7ql?T7N!O&;=hIKMVNlkYcPO4*zJ=HIA47iyS^bh?;u|(siFw9_WbXSZj5a zC!Uj9F5Msu8CToVa^ePIfM)ap)ou``gql}us_@9F$hpJ~!mv!ha1wec0Mph%0AN)4 z2^yB}Xno-pQ}yv{yBG>ny$Lne8Lf?rZZ5bP+_JjM8CR4+s1x47VkfM>Bpk delta 913 zcmV;C18)561Dgks7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_0009`Nklu$p!428|q_kU&fqoSiMfDHzG;YgLHHY3#Mv$-Tq0DuSr6eC|ZLI`YaS=Z~t zNuSK-G_7p^0#R3hjTImnv)hmyhzrBFwp0MB@tng!dEQeHN`KYT3P1@qx9K&dzFZLA zS_VLjQIzqeE(mWe0RUtEDdS7!Ab5m;6##5DNijcH2*D);EC6UWK9@%brU8&X)>GvT zf}fdxwq`!S-*?i~=NSzHVA1>}PY?_NVA=d6FA$Ic@L+zD2M9<2crri9Is|9{Jer?m z83Gglo|Z-4G=H@WEM+l6lB`yNE&!fOzX!2a0PC_?1)2b8&;C1a>C1ElSTT9ERt2g6 zXwUv9QD8{NTCXC6I{JDd`D3Jcgy_QEa^dT3Ir6pqSM?3EynX721`v)sAcCqgpj?^W z)986LZGSz#0AzQxoNxl{0bypG&-*Dkwg4L@flmS8*w*E2FK;KA#sQUvy#mq@u=9cp zHp@AJyRwqx5J;>9+vWh&OvsO|E%Q!XAsmrp2wtl@#ZdyEX4M>RfgjcAwYWm0H^4Gn<_lZawS1vf!VW3i7p7Lr>=3}EQ6tOkV5w3Gz{suTqvw!p9*5Kc&@*P%I4{O0 zsR96F&S>dfWxVtYLTUgQ*@VIbe&@Xf()LmSgaXi7TT?G6)gahi>Lr>FAP|5j!)5|k zLVw_GjPD5rz|LK@)=if+5G0lQr}Ik9egI()i0GM<-vVB4%(URZw(n7>r-e%m944zy z-^DCB`vC;b0Vt9RrY4CR0xU^G_5)l1mPm{F02cuFx&SasQ}zQ~09d8Xd;sLLg0K40 nXg&Z_1<>}Txuw;70DxaKkfD#qS{f$+015yANkvXXu0mjf4@H=X diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_2.png b/assets/dolphin/external/L1_Doom_128x64/frame_2.png index 218fdedbe5dbf80882b89df9cd844684547dd739..d740f5e33c8db728d55b3d46d1737a598858d66b 100644 GIT binary patch delta 737 zcmV<70v`R^3+)Av7=Hl(0002`twPcO00Oj0L_t(|oK=(2i&SM8#((d3j?He&Hlurr zt*kj^H)b?akkCalnP5VpK|wd+ivK`h7oypG>qbQ^5!H2!K}12!-gF^p4oTFFtcp~G zvJ-B)tSrvzi0g9BJYAfbVfMRwe?0HQ^S&=148P>*AKY*qbbnqy7Y>8`#pl;GP#L>& zWnIg$v2zz~sJ0!Y_>*A|JG}PbItzQ@uT;apefO*c$oCcHpCw1m+I`>`5@3S-Krtu5 zWN^Fh(YP)-i}Rz+49MpJM@cb|1J}4A5mM24V8mnPRB|CzCcthrF~1BHkvial7%L|= z5hJaE)91LxQh!Cn)&u9Ua&ksgO-cufvCCA03zVf+f}E0L1l4w4n|be)Hp$1E|4#73|Z|cXmP`Njgnr`sL{MKl>l~G{6%t|9j$pJ^(Qt T0G+e~00000NkvXXu0mjfM(ktV delta 1492 zcmV;_1uOdP1=1WfSmn<-Uz86ru#!P0di^lKA%BQaJ>0*u^5ObnfX&bp zZz(^!@?Yv24+CriRtjC6oE-kfvf8zUhXFQ$Q|1_c?;d2OmF>l20Gq%m4?rD3i2>+0 zt>1&k05(CQb52I1f31EGZuAJZJ<7Yw13~-=QaFf9`agYR{k5n?dcjg>i5W+ z^^O1o;4mbMihnvj1zrXiW4y>!!o>g?rFjSPt%eX~0O}7^L1lnS#s6veF@z8U0IHcl zWB{*a(r2QwbOKJm3ZEs)0MM7}d14u$Tls898U~jEmssgG0{lC|pcO3eCl9bg`MBL` zC&y}&esI|swILU6J6gAv0nFls0d^_>r9+FDz-nW~7Jqe@0cc+{_+@|-=oj~66%%kQ zu!0FH7=Yf-;8rSlC0*}C$2c=ghZ8|n(ZD}i;R)E`4`}F^n<@r)dAkSollGaro^$3> z!DD>R>X($;?E_RWfD}qfb#k&lr>%ZKCQgpPlXhL<0A}+5_&H7C7H%H~y)&eimfk& ze(UNVqb?7CuQTn344^s}{>|v{0X%I|wE6&*@PACyJ8dUjd4R~)a4QwO0vQW`7bB?3 z1V+b8jc2O?SQHrDCf+G$&~+AI%_(i~qy8Cm+9{%jyFLK-ok1G|SOe@*ROKNO?cZsq zfm|QCXE+}L(7FZeGJ*<7Y1S$u$Qr6g@sax4Gl7+Rd^d1^q@+ug5oDDgnKO@UI|Fp1 zdVfV~_p7%TZ(Uxxr}cYqTo|bBSDYLtb0;+Nv|WLS@}qsB@>)Ab82}wDH+X9`cqf*l zd#gW{@GwAS`%*o}7yvg|?Yuh!kJ53wozRqjXRKZZ1sr1l9K6X5EbrON;hMI?$#p?u zfGXv4_uk?xAZo!LSmEdnV~~us(!r$laDQ{K-2kZdXO(VEC_N;JCQz!O`2d+MPs>#t z?F3e=@{IB&rdhQGSPo#sVDI!dbQW;hAq&u)NBMBCB5bUHwk=Wmj-32iegG}s&Hx$E zRl%)hdQiee7*gGp2_Few2B6p0*gXy~##uG7N2-(K4W1JzBX{ zmUHyHth^Tx=-uC<(dA!^=sjtSX%Rd@%;|vgHq^+_MLl9 z>o1n0&aMYocKa(~mgQpShd!gNe1H6$)&`d+sDeey-Y7uw3p4}rGD6w_swc}@DOd)_ z|5|@xxMZWDL>pj?S5c}nnlaOQq`FfE5T#hUci)+0I`Ga&q8i*{(84|%!EkJ#F@zN%%(?il zVUknh*~dJx8dk^o5;)qHsGP2TEF&?2)*c32Z*u}I4;SutD{a;4r{J7JPT`#5xu^(a zXkFSIUf1UT1_D+oS-QVk`Aq=H2yox1EcYy3<;H#h+0awN;UUG~r|KLA1x*`D~t~AO30000Q1bt}a-adHv-2Lx9ap`8Q~a!wulC$tW34sI%_IohHQ9ipqW=BQv6X-ZR*i=ZZvt{vXXYFPje@HT>(k-{u~S-RaHQ<%m(AG8TiN~eJ*eIC`=zQ_sO@&|p)A>WYe4ii{V zQUxPz55Pl7V1H_=r%8H6Nnk%#GX<+PNiFl~yV_uZNota`t2b(c18!2KEJ;!iat?F! zwKx1|&Y{GX6F&<8Y{(m=NAtPmRe;1Munf%l>mN#~!vvNEe{iRE0ODZU$5nDaDaNaw zq-bp!JSFAWXtyOP+T6#qL=!g@4_u&b$DsI#Q&rmv|dGOA~uV z4|m;!>vRF6vQDLLQC{^oV4(_aaM$>D-3L%C{gQO7c(ahD-UN7VzkZqR2f(pbc25D+ zuWC!ufxfE8*jgTPnIr{+8UJh!r_T-GeXpK@5-TMj9Au>a4=GgA`B+vLurPTjl;B!r z@R#IRQd!vVG^ADvI+BvY-+l)4M3RpBk<>_EaR9EGr)1CGNhfk?(6Ur3N|HKKkSex! u0B8*@^+E|CHv~;H+6J(o&3pxDq~IUEZyT!rs`VED0000$}>Q3BzRrG0=y0VpXK1dd@&4EYoiq$9v=c&?$Tiy(no7J#Kf(GoX<+b;n94l};Sqn1}p(APK$ z0<##E1ApmjA@n7PZx<_XwkVoL&8l_ItesY6D9-so=O*kN_4RMq+rX!GEZ?zoOgdO1UF~^nKw^5NHwUOXj6^ z=}PC5)&o4S>LJ+eo2wYV2$042G=j$F>2pEN zA`tl^zh#=P;LL|Qp`}7x9Q6chu{7iDpG&Y9 zMnB(wcXA&0EWmZOq=2ezl3-Ai$X-ft+N!6IwVptV?~iPz)Ix13X_AS!Nq) QsQ>@~07*qoM6N<$g8LX6WdHyG diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_21.png b/assets/dolphin/external/L1_Doom_128x64/frame_21.png index 36d818beb107acdbad519271c35ae9723a7345b4..f08e98d81b16b096a8eb1cf3ed48097ef55f89c7 100644 GIT binary patch delta 632 zcmV-;0*C#C3WWub7=Hl(0002`twPcO00K-&L_t(|oQ;z`Z`42#hM!#@u|Ysg3KA)R zUC--l9Gy#jsoc%1qnLRQo)a)2o;Mc(vd4tfCR!v0!bGmBJdryUkdw< zkBX^Q&(6H>tab+eKN9y3NMisj;RF;N=)y$z0O(N?lz@4)+kb&Btm}0p6@T4KHEvEp z(;lL!zcm41$mb@0Ch!U@;oNVHqmi=&(~ih47RhnWPcoEoW_ERVDhZf7BoXJQz#VZh zMKQI_(xZ)$^k`z6#`6`Cv^NpW0e0b7-hrZ6@G{`UsjeglFR1h%N`-4Rdn`*^B+{8y z6PBC4@T5-wHh+f|#-ffn3qS}jHLAc@lYzAr#xVm3KJ{O{3@!SN>2xX z#bkV4%W(nHLEgFe0S!=)WLSDB+|5{mg?w0aefU8IgpPGA#K7GQ_?ZH>Q&|A~2LP%M zBuSf6<+Zl$a>YRH05w%#l6ItqC9r61x+%N|RJ|=)2Ns_BVLN<=+VKnHr6#gb S)wpK>0000w0=wY8 z$BOd0u1PbA#g702-1p52Skk5g5ic(?7}BzyoP z0d{nDC}8%x#R+R1AyorZCkZyc{2JdFgY1b@J^1Si-&_Qv`gJi@Z2yyD^2M8d5MGHvPecOg>$BiZZ{3PK@z!JdAce*Mdvq`Z6uNy%XZ~Az=?2L_VBY>#> zR_*yS?tj~ruxCP%PEy7qtAt-sHIUhBX|?^woxt`&gSON5@9FC_VD$^l1yZcPm6~9f z2asm>K00l}#R?}CK!0BVdyW!*L{V#2h~1Ad%mZj^@0DS#7Glpu3x5{SD{!F91WKT- z@0NF(mPyf=>KdTxT z4Jzc6!eT1k2#}fU*7PkEnDq4TXg2z+tRy72L=kVrpeT55=19F-Yk$^!zzmG;5ODLh zW`AE_<=`lIuVsxiMnqytdirN;i9UNOjhMV?_rIt`Mcl{Z%mt;&HNvu*4XRxxG#bE) zkS~Tr2;YK{ZPy5E2j?=YM&SNx*aPq4v!etpAwF{E0xe_RkCk-<*Vn@V)_Tv}hD!-S zdCpudqwm9-?^p@*FN6TZ3EvtjVos7p)qh(~Za+3gh8;*?`jIGr^(X(?;PwKGwUS1? z*7QS>k(0ix_%1#^;t zR^YvPvN(#Cq?D-^uoL=I<;gl`03!i67p=MA#+N)}Ccr8$w;dPr>MLmzjHI)YW`A2~ zfYy`m-L3TvWO7&bMcm&IMnAAP}QG_CW6Ze meBg}=Dw&IF&L9Ub5&i?q)~b|h&F*{v0000@ zXf7Y~@OW2S6%mOETKn*BW4<8Gt=+ z>{?ozB574pDY7eTK#tf>yLkBdC}{Vz4sdC#d`j0H`~KzP>vS##<^k3FA5^=I4`sXD zObtIJzGXUtx(9mV@wPQvk690dVH-eai_)^C*iRE+^H*x@ zNs4YarBHRRT^QIe`@nbrN{%H-vGg@PzGmCtPpghTuT}jaKn~r#pA8yNG99_;mZKK9 lp_LRgT3|$BMT(^m;2%4eDDky;SD63+002ovPDHLkV1hnF7SjL# delta 1156 zcmV-~1bh4B1dR!h7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000C(NklJruPI=}=yp&Y?YAb(8+r#Qg{ZxF}=6WNI8 zi0w%~MFj5_z@R5^M&^n35AX_r#3`%S18)rQ4|w%Hg?xZl002Pm-xzlm#N&fNX@1|J zsRf*{m6UdXS<2xLgbx9P)Yzj@miv#?XBtBY4$Eb839m5 zmr+{^QeoVIIDaps3jnYB)k2EZ0VIOBW}KD+PT6O0Yt2RYZ_@81H-deRpI_%`5QqiQFg?K#TmdVc5I8Y@xuiW^^#T6 zuT?Q*iJ*<^Du6}`CMSE3ivV?gp}9ax^_S%YE?EGV3T0bd5AA&c>N$>lk3+3pF##UK z90XP&ReuBPX(9ETH~G8p>$*EA9YFem+EYG{G4Fs#7ohqTJ3vMX*SC+D%TvIKO5^|@ zwR_GcwI$tA-*uG2toa4Dx0+QX(_0*Lr97JuTUgh^NbiQ7hV%9#*W&KLd*0wW@Q zOTW@vy4L=z^?)51-65FG+u|5M0;obheqOS=E#pX6|8AG)tEbY8X{GG`!5yr^<38SO zyWp%`LzZ>h;Mzq(;{X;+ZrIGlp%LdXd#UkWbRR`a zzegit^>bt3KrowhjAa3MVMP!bt8nB3S@sX$D1dBx^Kgj%GKS~exc)N92Uz@RShf8O!+m;8 z+ZS%4=2oRb=>F^As{0*va5HKf0m_xKzn6O5(M_8Q2e*2ql)!6EZ+zk z#R7e#%l+>us6sl1%bh?;KzM2%AAw5m>aqn$MSx+A((iyuF5ngeSVVyFl|)F4Tw>{^U9n>DUB=Oa!Xn# zkY*}RxK)P2mVZ7~gMvBwV&F3kfDc{e1vn}rFebx_X#&EE!IY4-2^me^#dQ_OrEFlg6#_c!N?CaLTIKvQN&PDvw{WrEyu$|_ zZb{1S?@Lc3z|<~Nz_-T$8thAw)}^=2s%&M`hN;5{42(y0e8d1)2(w7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000EcNklDTtwr$M+VQ@2+UJ`E5WoVIgt@Ev2QU&~=Z$KyllErdjRD}>w?9ev z01g7|80fS>`R^L1?2|(`3$O!8s5RoBwJxt#jGdIkMSu|-lv1vY`L+4I^_iWpTnwN| zxhPl!6A|QTB!B2e0Ln_V4h{?6DroI^Zx(~=0;iC`O@K@{KownDW4ZNc#-Ad%EKGF) zwbn=L3tkJLA;hWL4-h1P*9vIOeLY4RC%sGi`;&yLL6ZPcwo}hq%zajhW&t(l$)pgQ zL7BbqGEO5n&!P7&Q&Ys{(!^a{h3EoyDr!XCg@n4$Q-6Nmy*Hw62TLT-{@!z7D_R2p zTUxs+)Is1(OJEJur14qgXvGWKy9Bdgx)1{3^KB9B*MbWywQKFQHqI@rLWqx5pd%Nq z%@(v{H1EoqkD6!2zQXl)E&Udg;rltQ9(`3i(@LxoT>sRISq+gWyT`%S89)>x+@kb; zfa*$ES$|CCf_iOomGmo0hFK)2Ezj4T!1^+SXVUslneQ}E{R_(lQfj`LmVnIyEY-bV zlUDw11x*F8-xr{sAa*hGYoegO+c%2y2JnvR98F{K1fd=;nK82@yhY&$r%ZbxX5?(9mZC0p>=}(t&FU zq1l7ACb2_v2q5tN004Qy_oj+ekmND-9)DrscVj|Pf!vC4eMJnwe9g!CuBR;NX$GxQXsECkus0&p>a1ucPCg31;Vw8~;J|I!$X)qijk zU{;iiwW>zedaRZS6G3td__=IsV*$#6SSxCrrbN@o`e(1drby5t?QDbykYNS9HTM;? zhXO|e>75j*HO-(XmW%;<*W4xHMCYeS;8B((n?ZOZBVvJ3O_)qA^H_owG_7#Y`j@l- z5+a1?t^If|sWKQX{w&cBo?Z9OuzwJ}DsU}JFr)H^F|`oX3oSy-?qSq_bAjJTLZtnd zF|(Q6LNULRYv}oY{BQ2OMyHEz0<_q>DiI`%2xPUDzEMO-4+5!;uIegAqgEPA$=5<2 zD^k8KTq@M`O52`-o=U2wG03N002ov JPDHLkV1h%bW~KlD diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_24.png b/assets/dolphin/external/L1_Doom_128x64/frame_24.png index efda32966d363c04d85345d37a0b943b37269516..24693dfe47354b65563067efdc4c433d45bd0877 100644 GIT binary patch delta 608 zcmV-m0-ybd3GD=s7=Hl(0002`twPcO00J~gL_t(|oOP11YZGA@#(&@4wU?rB8N{|? zOw>Q1bt}a-adHv-2Lx9ap`8Q~a!wulC$tW34sI%_IohHQ9ipqW=BQv6X-ZR*i=ZZvt{vXXYFPje@HT>(k-{u~S-RaHQ<%m(AG8TiN~eJ*eIC`=zQ_sO@&|p)A>WYe4ii{V zQUxPz55Pl7V1H_=r%8H6Nnk%#GX<+PNiFl~yV_uZNota`t2b(c18!2KEJ;!iat?F! zwKx1|&Y{GX6F&<8Y{(m=NAtPmRe;1Munf%l>mN#~!vvNEe{iRE0ODZU$5nDaDaNaw zq-bp!JSFAWXtyOP+T6#qL=!g@4_u&b$DsI#Q&rmv|dGOA~uV z4|m;!>vRF6vQDLLQC{^oV4(_aaM$>D-3L%C{gQO7c(ahD-UN7VzkZqR2f(pbc25D+ zuWC!ufxfE8*jgTPnIr{+8UJh!r_T-GeXpK@5-TMj9Au>a4=GgA`B+vLurPTjl;B!r z@R#IRQd!vVG^ADvI+BvY-+l)4M3RpBk<>_EaR9EGr)1CGNhfk?(6Ur3N|HKKkSex! u0B8*@^+E|CHv~;H+6J(o&3pxDq~IUEZyT!rs`VED0000$}>Q3BzRrG0=y0VpXK1dd@&4EYoiq$9v=c&?$Tiy(no7J#Kf(GoX<+b;n94l};Sqn1}p(APK$ z0<##E1ApmjA@n7PZx<_XwkVoL&8l_ItesY6D9-so=O*kN_4RMq+rX!GEZ?zoOgdO1UF~^nKw^5NHwUOXj6^ z=}PC5)&o4S>LJ+eo2wYV2$042G=j$F>2pEN zA`tl^zh#=P;LL|Qp`}7x9Q6chu{7iDpG&Y9 zMnB(wcXA&0EWmZOq=2ezl3-Ai$X-ft+N!6IwVptV?~iPz)Ix13X_AS!Nq) QsQ>@~07*qoM6N<$g8LX6WdHyG diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_25.png b/assets/dolphin/external/L1_Doom_128x64/frame_25.png index f409d10d3d0cc70c1e46cd0e3d72d388772923b7..2f12df072a240ce300a71801f9859580713e41f2 100644 GIT binary patch delta 649 zcmV;40(SkI3Y7(r7=Hl(0002`twPcO00LY|L_t(|oQ;z)PZUuUg}?V^WrhT0r4SO( znZm?Ud!w_3h1&TGz>W&Bv(U^KVz5$MEBO%?S}}$g?bw1s6BBk7TslTXnO$b*Sj^0# zov(Q}U(P-E-k1B}|4*1yL9@DB0RVQSXr&d%@Bobe0DwjIz`CGIv!_MnZsjJBiNq^tNE7%r&oX>IhZ2A8C9gxPgpTL3CTZK`mz@lCG*luMgM*opFMdJR~H(AJ9!iF2#kwZRw+ z7e79-2l20Z9o7aN-XGs?9X|YPEuT4e0#rsGd(@jCg>rxgSzmlG>)s5kLIdHQA z0dPMC_HO{Ta+$dTvk`!X`;w$h>3{?*X7mp|mchb!T!DfwV9|;PkU@hZK>2zWN$N>C jBv@E;n?Md0TKoYwNjDBy(m3V-000043#_i|6isrC1n)}bTz{9naOmzH6YND(8Zfx0MOvYuf?C;0=(FZuiXNi zg4X7a^17~@B#DKJ0IjuSH|l|8->06J;5m?P+tM3x;hQ80$0jB`Apsz0O2I-jezM2IL*ziFk0_Z z_9R7W3~&NTu#DK1SC`)lGXb991t|IP-=%l^cpfL6P1!6!l5%7XY+urba5C0~c6I_mw3Zm&H^e#1}x_ z#*Q>wkUk?>D{4M!o{D{ik9Ptygz{Mb%Bt^vRXfs4R57}bET9WjC8G7nl5wz+8O9yg z;%a>WB7Y5}a$V0N8Jny^(mU%Skr+J>TL;hzHs-_CBVP}w{)ML9P0hE{6R5uzfWehc zcW(?s`@R4*j#GX_Q|qpn0Iy-{23Aq32G(vNH7;8D9%#HRMKF~IkZw@h<%?MJ36OXJ zPo0B$R^$Pq(;v;8cUJML!dpO^k!tAyJo!7GLx0;zleA`^Mu_NGU^N%(0ix1CfS*=x zE#y$?-|U5x-wbJNKoTG$Z||^n1p8S0@4wMYte^=De-I$MDdL%5YW+LAfgW%vrxcc0 z;e!Af2V+sZRAEx3ubq_Mp-8Wmsvdm_jdz3yqnL?576XA_gE%`PNjC3X&|Y-l8nLHh(4*706YDngCTSALqN4w(Kl|)}*5p8KflG zO_J?j54Us&sbYusAhl^9W%c8q8WN0iQhU>+#9C}8z;0M0dF~1riC`gtL`I36rc$sJ zQTJPg>tuvgj?wDJb6JrfniP~wt1-v^qDZ_!Pu0;no|6gBE3wAt_W(K>#~%u20)Ipb zYhAZnmL&kp!Yr`tvSUxN6I)||@j&qBl5y1MQbb!EmV?U%yy<2%Tm*=S1*|pq3f40N zCcz9dGG_M!N@fAsHTS#RFD5}os@m6CJ;Tn~3=%~~vle&>VW}c|u(IOJ>u80N9$*EJ zhu9H(jn>Z@&kp4S1QB3&-8=irh<^fCy`<#5ix8$O0AT+$pn)ck%G`rS(X(_i5@A=s zZZ9xH6`61iW2Rh8$Sfj+7J|6E{>6V-0#<7cL4xogkSmA2_=GxLOY#Wr7(iO+7*UZB zcN5mDz$hYw{eJaF1p3*+#LNniy!lIaIR_-zkS?lUZd_b z>^x3Z>vA(oJ%4P9ysVt4cYyuI6q#|y!~-G+p^UbeTd!TC3l zXAugFY+?ijziJUf3QJnIhy;eQb%VkfHz2Txh(8225h6DRMgu6l1Zpl&P8;)gwEZjM za8El8qw(ozZHrsquB|r>@pEkx&a|}CFnR1fsX@`XP=C&L8z(jBcfPd8+kYB?yuX^c zG?4&^SZri-xB!nRn@m4wathed{_QN&9>BhpsRwXmrM?fKNGrr)_IZd8&_}yfU?qSB zfN5}tAR3y614V_Rs_Hg?+g8Zv;g!~_u|^O8+skO+)G?%Au9au-9~_g${*`tMlpCHkP& zk6KR){4$eNc;lzx$Khf8Qj8tIOX(Bf6->V^g=uLk9fC${+<#<%!|`bbXvdFYWln)} zx9`+@cgcX%+IR(%sRMW^y^>LSMz7bUqXt<8Y=CMAG)(WPm7O_2aI}%_$pDr}2IxT2 zJsAKHg#plL_kF9KkQ&RKCj$T?Fn}~?PY=q_*LAVke=-0d3IkNkcDyezz|uZ|HK-`; z(K(`huBS7_0Dn*V0G#aX0~qRMiJoz@5AdNXfI{W~3?eZ=&E}uZU3HhLg3JK`UbLmj z<}Kz!8EsY2-rqR~_#6Yw+-@WT?#ck4%mFxu8|?#V$JO)90TwerOV1oQBacvX9gl`j z1_;6c5-_=Yn=Dd}kPHx@3Xp(_oP~bq1oaw~8))Sv1AlA=Zd*tO2*Lp9j8wE*fOCR~ z46tP%;0?G%l=OR|KlTiw_5nWmEuc52Rv&6#AJwBikK2H@nKgSoKbr%*ozr?tX!C2pQUpo%RYV>HInX%y7?Z=A&w#fmWFbUV7;qK$LmHA6D03r7YBo>frcWS&R zG6(pJr+?4)77OpS&Jdw$$v!|CH$IhUQAhlnI+y0~!10~Hl^w*DbE6JNGQeyDaI&R2 zsj6Zoj%5Igm&E7aI^ha7IFbRps8?#fM1dCrgy{oVznqn<)p^Jf3^2p9r8X;$i-=rM(v((?zIBslfG&J0sZX_j_l1b^t%}sSDTO5-EP|s@SDdqpZ{hNsIL2?4@ z7jXJe@4&6ikqn?UJ{R@vwOM;NwGFh<%rOAP7AUX9k)6P&W!q?i_ZGM?v(sTCFTAQ3ne>DCa&V2N*>J z%C72*(7F7=Hl(0002`twPcO00It4L_t(|oNbc7YZGA@$3O2S?VWA0S4zbM zO5)(6gXth-(B||n$e`HL#l=x@>L6kg(8-~W&7vIx4t8~svj`QsxDye>CrsX1M0> zhmyH{X-$UqQF{BXs8!D&W{8mMZ{>p~fSJX<{3%+2NYXSQ91=KbhR=x=RNOSf<0zn( zvAFo=(9;%RY!#>%fO0S1M{D2X>rQI z$8X&a>M-bjX+@T3!Q>Mc8(@I+YCxk6X8}f`Fa#xTbYOrfV2X&W0~A^!;!zP1sR5{lhy=!G zrIgaI{WF?U$}%bs_3IOUSJ1)j zAGe<#_~Rz2$<8mwk0ZkQtvLrkl+h<3Dw+Oz3bWEy1q2W5+<#(#!|`bb!1s^h&6-r^+%j{x+mWKhbJuARv_O1-DWfvfUbApx5 z0eGEe_ZPZ=SAXXKQCOv$V}O}CfF!$WfTXAzKtQG%0IK=f-~+q4uApiF0dFz@tL!adf4DiVsK+-ol2N=~^HNeX?01Rz38%Mt9bV#hTBLjS< z2Cza3$eBQeXQMNRssR#o0X<-+Sy-b7%mzC$z$a^fS%38GwAK$&mtc`WKoF!X2Ee(mo&PjIW^4c*qlr)qFsPS;I!+5j zE^B-8EszRC>v0m1OrLlgh~;CQT-MLj03P;Ho!WlX9H1j#yN5%sxU*FFUe6%SAbPf~ z41#SKz<)yFSO-Vt(z+R2JmhFPiUEjR4OEvU+a&wwT1nQb0=FiC|1r}(;k8s2y-(Uq z>lwWY#Q;s;8)J}`MS@|A_Vt}i)`2Q0aRY_C302cjk*ot)?F$b__;z;K8 zD)feO4bZc$uF*N|U)}p7i z_J2$ElZ@BU3j(+vnM~p}#Q@Dtn^c}e)vL~K?ij$?EHQx8UcSu$son;T9u-*ch>WM8 z#{#y4yXIO*${L)G2nI;=Hjr+dcAr+HMFO5t%5u1e{;sz-QC)y*8>kuW-CDibR#F>0 z?BIg?m>OUd8Jth`d!ElxHNYzj@B~!O+kXK7pf){u)?$E;{NDAO@V4#9F2JfID=hv0 zh^%4&BD;5;5l?K?lBw5Xj$k+dsAAf_tz>}A*$?nyfzf1|4Fq!$*b^R=jae#x4H0%~ z&bI3AGJut0cF4>~tPW7?$lP)t%K+INx?+g58ra?}`^oLy4+eNzP^`c%4yWK=SX;df z&cE(|5wrps2R|0h($07*qoM6N<$g0u(=djJ3c diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_28.png b/assets/dolphin/external/L1_Doom_128x64/frame_28.png index e756f177eca42ebc14500853a7d3b82d399fd151..6e4a776794e70af090439b3419f5cffa4d4a843e 100644 GIT binary patch delta 579 zcmV-J0=)gr2+#zO7=Hl(0002`twPcO00I|DL_t(|oRyP5XcJ)=#(#IYHt8Q|gH+Rk zn%x8BV<7)S*oEF}U4)9A{8rFTIx|1lQ*yFr=G!@{*}c?K zd2zz@$P}$?cbAZ;t4p6p!zAL(1&*CCh~EmFyh-$Ch<8k)KA1~&5lWRV?HEbt=Ty!5 z@~M+FRv_-Uz3!R zg0zSz4?LhpM5Jct0HvoEAg8Ah09&tl5ou}%5s}yiXbE1zSsjnoMx*``{s1t#KlNuk RJ9+>B002ovPDHLkV1l#i72p5> delta 1092 zcmV-K1iSmt1kDJL7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000C3Nkl?T+Oj2!`oq@Bfy&f5wDiUlc4_+VUn7=bZXMMIO;fb`K&tDNyHm(s3OBmF-z+ zEHr;;J|pxetS8c)Uyk={hx3Vo7r-u~zo1>g^f$6IE4FGuV1IGv76Cr4T?Dv22WZc% z-xW{qi>6_M`9lIDBzM zypK1SX7xG($bU%WZP1p0oWa{^?WJ8$CBW-)05nOn6Q^wl@^j??KgvLW-Z)p=6#)#& zL;z3b-|J5szX%|-lK`WHs+YZc)cR;YGFND25#UEV2w-g&Jy}hfBZ>f<2w*9-NwVAn zjHLBl1fcr~V961*dY+sC)hz-fA;3u7CV83Tk*r??pnqo&0A=#p=UzX(v1K&(R0P;e zfGDAHxf7+siU0`+z-_dCul3QB7S*1*MSw&(Ko9w-^pK!uV-Y~eN`R=z(oO~*+cnzA z=S6^oIY5ixEA|uNE9Ft&MF456Bcs;(x8?|=HnV4bq#}T!uh@I*dp>#=wA zoqQgtB0x~&_ae)CY_l9SivU0o1h^9Uybom8%Y=*Vy4{dy*DHJPM7O@I}V&->-S zpXWLJ;cZsh$4hN)UQd7>(ry7q^>^Bc#{L8WTAN2;l2qW|NxL*6$oH_! z&3_I8r1|#&&}1N7B8seXycAyu$WCsT{LI@~=f=C8&L|B5c-ea{qwS7lO>R*Z0&rV1 z5g<(tpc>f80q$@sl{}_S> z8|_(F7eV&uZ;Fi4*-JI=*ybd#x5`#K=P3(-XrHa4sJGhCC4dzzPjb*3WbuoY2#^3P z&b2eje)Q9{Dr3JYG>^ZMz^e&Gq@Lzz}zOY{@vi#?uM zWt!6_KDVLw08x62^NI4mOUea6^c;k0%9sQqrCk7}J*oxpas2~>HNyXii61Ti0000< KMNUMnLSTa0OZ&k9 diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_29.png b/assets/dolphin/external/L1_Doom_128x64/frame_29.png index cf1f5278786c76be112118fd296403e554ba2982..06fa8b6e498d56e15a2e908e7cd148459e190834 100644 GIT binary patch delta 550 zcmV+>0@?kG2(tu`7=Hl(0002`twPcO00H_*L_t(|oPCo&XcJ)=#(&?}(0*J+V?l{k zyt9LfF5;qFql+L8aj5~9;N<9J-TF}nHA3gKiy4nBW>o2Lo2xj8lbiu{QBs7Ike>HC z+@IW~;yb?l?s?zud7lHESCZDm2Mvn>X-U!;)w70bCd6BnmVf&%q5_LSZ)^Z-hdxwb zR3}~o98|MkoZ`()v0*+X06bGB9O#ybS&jYn4rSs~>(G=kp>1qS#93$+3H=;QLI6%D zb8N>?U%NDpAJzt@Tbwd!rG5Y>ng>62A4MB7*>0qMye95{{BXfc{V;XoqN7~nI80hp z!+eh+#Ma*Qa(|+NMiYF_U0;Ltxmz7?{Te86woXRTyFud&KaV!kDc}Cw-u-p=j%0U< zPVYbd^7L}yF4pLp;Xkjf>iEe6-%cIVGx-R{5XQv>88p}e5fX2fGUh>Siy9XFEV6|? zfa`O>a<)g$uDkVt?+r7ey>cFEn-`b;)b-v<2j-pLc7G!yE_tA|$u+Kyy%2ffcB+xxRsrngS${91Bfx=7?q$RtKwL;r1t2P9ECdkL{Q%9emjNdE zMEonjs)Z_mhPeoo1k=WXz=DWK7eH-@NQf&U;sK~t5gF^RN-5<5$PJ~G(XNO{a;Jny oHb{SmL?0SRevn|=DAb|GUw{z^P|9lG0ssI207*qoM6N<$f`~5!QUCw| delta 1025 zcmV+c1pfQ81d9le7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000BMNklq2w01$%#q~OX5?JZ_80K{g1 z)hGsl7z}`;bZfdc`@cmo0K{ehYg%VTF#yD1fKw<2fLIKGDcuU|QBVv3XBhw+z-vtH z5m5{Pdl^8wlYd_YPX1dN;DQ5h1oe}M5FnlgwLYWGj#p{bwMyXh#!Jbw~WF+jtPlx}4VFw)m5KP3Zj z)V%_uW1)wZuBAGw;Zia{gNK(tm0=Cow0$gWn2rHfK*}JbooaDjO{SxLCN%>{@~L{R z5A~ZWHL|oAJ#*jpNBbx!Ee7a7<>k_@YKuL3wlDinFRQP^-$(jz?Ue;6;iR@sDJ6dQ`eOD08j7Lx&E!LeQ-`Mq4n)$ zjP$YUInuk0zk>l>kANpiTMQ#T=ec`(8NFQXktX%y+S4#V|Lp9T0H6QbS$4Vwm=#(b zr4RQT*Pmv9Fj;_hVtB#&_+pjeF?vU!+Nj^!`i6A(09tUAeT+=`)aPdy9P8+|6hc29Rr(ggpA{ifG{{2A?U(Endu+phK;4#-? zfPwtCz~eZmEMPE3RIFgSVgPv8?r(Uav$UDoWmJDDH3Rci@aXbm_4Q@+-QVCbXX`r7 zW?1SVaO7pXjPe!-09dc9wClBF4;jF6IePOJ!+ZlQ|E)-NAsN6s(tL{OsUL?`k^3yD z_4^0{p9T~w@HV4Uh%yJtzV2@Xt-u?1e?xTLKVpDryB{FV?s>pg%szQy zv@(Nw2+d(jReC9z3C%%bDtIWgw}^j$O1&6TI%%PYUIZ^9sEK;8O3U_;7KEkQMzkK3 zE+wE)lU*y)f)-b@!QFIs9uKoyH}CEF@Vvhs7_82ruic=|HGfb1Bo!Qoc#{nslEtbM^|@#sM1i*N6ZA)W7hvJ57r<;ujPyv?l~IQe}BRyRN0 z&f7Q9>e?B|X(dhHy7zA0el5RweV@a_7uPy3!D8sb$?&+xFwem(W8l59R$hUE(z6}i zsphTw_tAZ89$?{vgH*x1&#x{(L8=F;#d*`&`@eta0D?NT7?}L%L}U!L0B#=7|C`p= bmk#^~W4A8W7wHGZ00000NkvXXu0mjfF_Us0 delta 1553 zcmV+s2JZRw1(pnu7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000HZNklAzQd4B$va6_0&MxzX#Nip4&t!+qbP@~`XqqkQT^o=knR*MAQK9D)qh)BTL6Yj_x7 zGc3hR9#3tSXKQkK|JS|tFu*o&rJ;hcA8+gNbPW#!YyywQInW>?XF86R0!3+#)*c4f z3W)(QRU?dgx`u}VHbGM|{k1$@>My}#g4PNcAYzq~g?uBB0cLr*h2Ne*R=`rx{~Lf6 zISEmN7&$Id41d7Ssa{mb_!LMCz}r?J!~i`?^9mc^ZU`C!Xoa3xFb$wm@tVw&48aPt zs^QW9s+d4E0Bdp9m~3B-0#`$uf7ZGpF@RPms)QH=WFNX>ao%RkgjbQ9Z3O(g#X?K! z06Ub==Utr!Szb2tJkCDv>-~MPA^tIdQ)qa#5zyS3`+uXzFdi=p)7UD!3}E(|pOLxC z2v#EVoKi(_)Ch=8x=X>IuAtfIWdO|xP>xkx;%z@%@G02A0weYG9*i)6rg+N;wD_Tm z0Y1t5En1zK1ynGACO66kt+n=Zn)ee{vH%(Z-^3MlfXMpzIxE+cei`&h-p}FX;IroI zWq_)6{eRB(eyzH8B33eCMw$2{k!;1%eB;W`{eh+~AkztXtAaE4- zeZM~6ii#K@;~3gpT|Wqk!lI;a$IKWYV;Eru$SRE%ss&av>e}ywQ3f#2b>lwHxAjM% zpL(`OP+14Cj#JOTwi&>;9|JS%0NPtkE`vT(V}F23WH#y@P{{yzPpSk;CFE@e5cPg; z`BAy=Vg#dgfDD6L26Hq6^ah^qU<4IeK=xUs{?lRr>lZ9|rd7}R4)H}r44}OU)MWDd z0bv>gSPw^rG5ZH46-*$}X9X%5AbX5(Ol1J8?H#BZy{*z{E9wA}O#IH*Esfh61Dr_J zQhzkfH?E3ZdKduLf_)-}fjBw{jG&T5B5&HNj+iWc(-`ZXrFe5*PDLfQaq%Ro}Z zOopij^*h1jpBTA=! zGlSG91JE_CN$RVO{ED?OJUN9{qa(9rm%-X)$cL4lrXAs2)I{5m?@jo2pePwQ)1xDcW13RiMhS=12UK zsI2n&eQBdt)F&dxm1GD#xxO`j$^cHQ++mdqA$gg`Hmje_VgOWngb}RxN&0?V8h@Ap zQk>?&ypqT7V?RlLRl!F?gaM>$>HN=vKigXwfTwtB^CJBdO3+>wpjGZ7Y>=7%cmt4> z>7{v*T$o?)fR?UVY{j3=+Y3pibR4D)V0OA@RRkl28;b!XdA()UQCLTewk}PM)$SR{ z)+~TW;To+)QzGw7jnL*Q<@33`_^}-GZHs0BT3lcmP-I_Il|V^AB|J~TK3+N`<$OL7X>X?)Z zW1d`nyx}}_?ahUKBu|!POL8>XX#?nul=19d8AwLP&s09nV;x=Cm!PqM#SmVGa9tZJ zfzic#=oz~*&(|Q)wnpXX{eQfV#st=U9CW?C4v;w>ID3qGJ<6T!{Rk_twT=qxqs2p! zwD!Iac^TwcDfSzk2j^I=e7+vZ>-oB{uQV3-PrHwEw{}<>IE$V&>ffn+f|e#q^e?5l z7$D-gZv~rOS-{TCs>BJ(Cur-?lqVenTH(iw5B>om2Uilo%qkB6015yANkvXXu0mjf D_#ocz diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_30.png b/assets/dolphin/external/L1_Doom_128x64/frame_30.png index 1b16b867ad77265a1031c071b0cf4e7706c8af67..6d6717c40339d2179ad3eeee66288e6245688f27 100644 GIT binary patch delta 518 zcmV+h0{Q)o2b2Vm7=Hl(0002`twPcO00G-cL_t(|oPCoqh!a5+hQFPxmmw>7S1jBe zV%D{>k}Ize3|wJjVQ0Y3POuPc1cgjFporz!C|CunbcY}~*w~3!T7=~qOM`GY?vPk^r0xY9Ja0#`~zM{(mY)42gT^t?>r?a|}T5 zux9LzD~9z3&}M5DLqX#5j12Nz{-a^N_G>g^NL*ePs7s39Yo}NP7;Q)EH7Et1ypJ;)5u^uKHII!otjr^Z#Hp-2E^}7jC5FUl!|9Wrp?%wnk@@#7 zE}N;WrO|=&fdQmL%X8>x`>NS?6EMxTD&GV?<;zUVX@3Sxr}bNRFaTz)Z6g4^^zm6v zH-JAfzf=DP4vG8&%79T))16UdD0jps8tJxV>wqirj;KdCEaDR@K0vyi)N*(ui{oHIn zv;9lU(s2t`!Ia>@DIgSq2K&d&DL@)ox3j7og-`&8xKsfAtfV|++fKA1zYq%G5SI#| z9r>q~B65IGfN5MR0De|d-i>tp$N|0x1(?UB0^An)HLE#DPy zNEP7p!kvclg@2_29QhugrglQF+!|AA<1R+_bLZzq0fHagDgb^B)SCrE)wSBUUNf~F zy)1mxW)`k0x>A7Fu=m=%HIK;odP7;@yKyp8#!=KFI4}WoTc=A`X1o; zH-V*&YRj3h)FGA$AZPrMD$N|JB^*}(>RDXI^>zDRd4D%}yqvSTeQp#0KU?=f)pN_c z!Q-Wr)a`Sl0IQKBt>396nhWGc0VI*ra&WIrZ3B0_S!Z)L0jF;(1yDT(j*c#zV_@&h zj@#C4dO1Tc!R$G-b;qzuD==#RxVi@j;vRr3OWRAMb+x^AxnPw899IDA+__klYuqS6@I&MPjQYp{LIFM&mkQA9Yo#phf44nSdqV*n5()rz zk(P5F{+zTg6kr3`*&G|J?RBjH7LlG(`u^ci+KyDAHSUbPc-mw&DKMGj!70H+pT+lEkpg)vW~Jx?nI zIQ~uG3b!nNL30yW1=Epl0$16+u~u1~FMef)0uW=o!iud{3h-nOaC7tn=)4Ld2Wa&F z8nZT!f(c(wuWUB)H-Xe(qj#3}WyuR0VRhb8Kh7Sp*-2n;msu{zD;oe{udSSmBo18# z;Co8TON;UeaMp#Z2&4k+yttX=_M=}5i_0)Bl<$5efvX9{E?!%7iW}xYt*`q30(S9Y z^cQZn{Z|ffWAp>u5j`5*;$Q4f)q8*)e9Gbj+&P!)Hvquh63XG0B#`2X4G`=jHh^>f Y0TZ8-9v%E)=l}o!07*qoM6N<$f+Yc-7ytkO diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_31.png b/assets/dolphin/external/L1_Doom_128x64/frame_31.png index cec7329b4d49b99143949f2bd171eb81e1d82a5c..25770b6fe24922bfe1d08e85a8b641a27af899ba 100644 GIT binary patch delta 374 zcmV-+0g3+L1%(5U7=Hl(0002`twPcO00B%%L_t(|oYj#%N&`_8g}*x)oFNenLePki zS%UUL;ttX|VB-QTbOFIB1vik+lqqfPUYE|o6~qllECOSkSn09{Zz~!he6F}epoz=q0LF0fs;1tnh)4vWXCe}MEmc*!v1Ql<05**W*!Eybz`1Y07oj80 U74}f^X8-^I07*qoM6N<$f=+m#bN~PV delta 724 zcmV;_0xSK61KvHWN2!-)X-~W|8zwEeE5-|eeW_>fAPIK`FtRP7X5mi#8)=H(6Kfl{KFos({ zZap>lr`8hP8y|+B$HVwU$`0T)=nQxT(~o9jQrUt-@bt!o0)HgOO97Ar1O*C^94J6? zpa98%0wf0tkQ^vLa-aaofdV843XmKqKysh}$$TgJ=gN}n>JQ}0xX~zz1&M7kNH3WUiMF9 zXCTj)TG$0l()#h}tMy~Ky+s}1MZexy&J7A6WcMz^$_bzV6aDSRVvbON0a1+K&~^f^ zVA}Fc;C~8{ic1_CbM1E zb?J7N=v%)#yh`Cxxb^!;0#_3X3r;gSN0d2m_Dxm)-#`majQ&RSv47+M(W0LyPV}r2 zX>I#8RjmVP^DV|FiaVFk4nP!NLPtbO0y)Av0I&rPkevTvWXcgyR;El5r6Eh4CGY?Akau=YL;~gZqby0P`idyzKzk zFEdse3Sgq+97sB`10c0D2bH9u2uQ5Oo}M^>c*++Faz$!Q86(>;l{C9yq^LsDwqXP& z9>dgEI}EN=RM1<`rbiY?H=}P>Pp*y>+L3+`Y^j)WaA?-Ei-l=4tCl4b4MSe0a$|3& zselp}o?CAk@_)gUO`tyGQs$%<$}X2aYAgW5;y}#Z9<-$v21%|kvl`RZS_n~EblJ$k zu~y4TWBIMi#Pwm3+e5&^*`lvsL{0#2i>nX^wRk-Y-a0$-$RP0A9iMtQ;J~GYhsw&l z8uuv=Srq3r;2G{uEATLQSCxJDj!r(hep~CI93<{`f`13jf4|eN3dtGUS_YtBTXSHE zehff>-N_f)67aER`4rFJ_pW1M@W*3-y)TFQ6bnBK@N({Gvq2O3j|y;bPep*$1_Xzp zwcQIe;X&}wL3V#V$=@lRJVfhPHclUZf{K}3%0c2GB{r)!n+RYWaKwV?><|f1alkNG zY|CBH6e~__2Enk~j9v2YkILd`)8?Q!QHehD7ge&VxtK(3qW}N^07*qoM6N<$g4eMH AIsgCw delta 1161 zcmV;41a|ws1d$1l7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000C-NklM*7^%%#dwyl803>xre)LI5&bPDyjsVd}Fsu?7 zalUr$6gcOXQh&@&?3Duy5kS=W9-EW!IKEQbsI{%S3!v5c5!;=K_S{}MKz9N3aDK}* zZvjUD+*a1M`$+;@7ah3XpN{NLw>kiHPRpW0I{#U;?B6;w_~M$fM6}+_y_|*CXPrvd z9N@n13r7NYRH_|zpttu|`*ds^%Phds(Z1L~syAzPR)1i4@+^KN|FA{?Z7BFq#+Dmv zHr^>;Mgtix%b!{Yh&~)UoOAx0hY36^V>~&4G!%Te@NOlv4e9R-;R9o_IRUOWOODg( z02uCGQ+5TnIPz2xKwyOA#_+Cd0g>rluaa-_i?y;B$pNS+@ZWOqN(tF2?=c!`SrYl)n!-RG3pk<1*JJM8nn>~SE zJlmn9^VWOq%8>m4ma;507I7~ZLCb2bHE_>@(~fxS035^W03&*zchkekA{e$OaQ5O1 zmjp)N=Ts3qvKBDAVkeb zB?o|Q@R33+b%CW3dvEueotKOzveMbo^PvyL2++Fkuk~7~Dj0pvj3{7T()KKScgq2^ z2C;5A!dQE^#ct=&U4I`wDByWb43E|Us6-5($A5biiWfbsqKK-0mY}dhsrQG!AGZl) zSbrUW!?RBS9~NhE6-Mg1T}!-@L+kg}Sx(nFK+hgQIosN+r82V?K39hlH2jW>fLyyp zvwv*=Xel@<0_xZmDZJzFrDB&S2cSA&z35;S4drc9*YL3TfJ(IJK!X=E74gA|HRQS&2x_X*Ky-$HZKQPqs>VXGOcH2ir`|6iInSCLQlItS bR{j7JB!$y7OT-EQ0000gtSXr4P9EhN?v9OZW%EBTxlENP=2?%nM z2;o?g%Z$bDU2=bdQ-1iq@B7Z1H}HR+1%nI#l?(#U-X5$dc7JaUg46cRAb8N$DDVz@ zV0EW64~!~nCRv}(ozfHy3K)~6g2`jRL`R+22f>Zas`6q6N66N*8>?Lg31>}P)2 zNo1{XoI#k^w5>1 zW6SSCQAT6a8A!6lR1fb}5J2TmtD+X30DcY#hs`;i!hV>IIIRRGIsT)%fwvN7AbTb& b-e>*+7)z~ooY_2E00000NkvXXu0mjfc&`pn delta 1204 zcmV;l1WWtc1iT557=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000DTNklnhh_TRx*Ja2U%Gz~&qQ zY|atD<{SZR&Jn=o906?35y0jg0c_59bOjDJrRd4p`@XB+eSZWnIi(cSz#xzsA>7wl z3z!mYRLKLtHGEH01V;dqK@F)HA3uZdkBHz1U?Qj?EhG;R5y6Q8CcxwF>2)wLJx1v^ z4J@U&RJ=RTTdlF48W`@)wsBJrfGfkfvdnbljZpVZ(b_B9^MPgp;Km*LVMh!FjbIsX8j*anbe)TQ zrLt?MHapNX4U z(Orb#^#GO#KHSZo7e^|2T|a9BmeD2ST0@nUPhTCWgAL6CXn-+1i$Yo=g!X)IxvS&p zEcmFQwaG_{AhURl5Gm`eB9MBs_8nFpfFiwXXd(!E3GJTUz(SYC@TO}4wcCj@;Bs*J z^dBYSS$|gY0)RKOR}%wpZSuzhJl$xL7r=2rCSSgS2xu?o0$$4l)G}-cka{^bJidqX z7#>y;0f)9*C>jGu{1-r0Ntx%l>0iw*nU#r->C@~7$RN%6Tld&iy@2NRrpyD>Y-+$C z5Lu0kvZ@Fqy2Jq5!VF-|6lyBe)9~~?ZxKQB7=K_i+Op>1FWq7Qj~7^(w|Id^VgS#} zTQ+89x)GPNM4%ZI&QlK{wNcYNK+BK!en6BbgwRt2+`2wKN5z4E*D|Eh=%3!-byKKRXolWG z=_saPXaO8;6D~H;#O{p&G$GyhJ#H~* zrl}xDwtn6i$Kws8XYrA{F7^6fi6DBh7rp1&J;)@zYJz5b4%b1dn{{1^9q@N`_W<0K zarWMi;d+fmt)JZC-A8>@2q&TrPeGVTlNqSpanNOk{J@BQ%(S$`6Ynp3u}>9!7|UUf|lCN z#s$(dxNOQa+roFkO51AC8G$4wJS}u+S;c9BKrbuzevIV_;Aal%{;6k(w9!9;EO^Zc S39okm0000C?%OZD8TZ~@rpq1nW=-iS2^;DAs8To*#%$P1klrfEBG?F zWCi0fJ3t4_?LM@GuGU~6Hj6e90KFX2=&pyBrL7)p_>V*m07|d`(udU2trfCK1T&zu zdK|zi5n?V>1b#Cbm8-Ks6&}f`DH)gF$s0cjJ+RxbG zHljcQc6a^k9pT3zM`76KPTa~7ij%#%10xtW);&0)EgeAuujk*|If2@dLIv_>yT5Ef z6@eNP&#$$f{`09~%r$wqN(Osc1Kz&-zG6jy7XTENxj|nA_yfRJQpRh!3PA_#eYLX} zH;$QKokf`Wy8#qolBRb(3)T)&Fr7^z0pbb3&H3}TghN*WP-clQj&D?zL{D4*VPR^C azVR0$Z?WLk6O=^&0000kC*MH?6`xroS-1jXixEhGZ z5Uz4+0Vx5M$}vEF2isVU;21zMU`4i+5BtFO79%(YkO)|j5;z917{SySK(nb*`huDr zp`m;HzRC#yS~1N4T2_fS-4oR8294KKa)6$n`WDbqro;%no68PN-x#gE_j-OsXd{jLs|}We6a#42{lNf{MTZfBw9*}H-xG*t z#IP6u3L&!SFcbLpf!FH^LbL5ziUG9o!5in4Tafb2t$*j5aW!ovj8>L6#~zJQF~GZ& zZ=rJ@*qsL$!30s!cqUNnQVr~jv8kd z<(D!p251I>lJ`jq==p%eQe((;WX(cI41fo>ECd58CA)WJUmt~0F@Sgt^wilo=7gO$eQ&u}r6M2(IT5ElZVm(J?PX-Y7Yu*B+a->H=RwMWYcw!lACeVwQ zq>QL?ZYJ-JG)VYSid58s@1?xQv>2c+O!LhieAlC3coqF6roj85WK`Qg8B%hXUJKAp z04=v=2vY2UZxPX$aV$xO4P^#pNMUFmV1MN1Da##^IGVu*(MLg@gL=lvtmP<*tRl6R6XhVo*f)>5w=a3Dkaj0KzPOO7EZfH4JiW7PSy@L@*Y(}v`ogcR2)=2$Q zb8&`rU03e!0ajv!fl92WWdp7+{H5M=UJv`c@XILR>(CC-y?33KBTvf))Y_!?Tz~8U z_Z7|n)W&vDeg)+*>D>TB+UMxPa>e=f*ghzy+{YNVzsGV}eIVE323$2-IR{?}w0>p#Gf#rhm)~78(5m Xu62k2)5_9M00000NkvXXu0mjfWcW)@ diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_35.png b/assets/dolphin/external/L1_Doom_128x64/frame_35.png index fe9e9f81fd1b0cece9ce3dd1231cd0fe1f867760..6e6ac6a021668b6d6751d6601c539fdd97178f5c 100644 GIT binary patch delta 610 zcmV-o0-gQU3GW1u7=Hl(0002`twPcO00K5iL_t(|oVAlbXcR#dhrfM0cRLB2%MuHd zBHWrPg2;h|7J>^lcG?Kq1#B#W+G!CklbDb$SfogKh654AG*(t?K(Gszf`2wB+MIGl z$ZhnpV==2YYo|e`p#$>;k_fQLN+mKyJb~s%TWJZ0)OY02`k9;H532`@lY!BhCQi2 zEG2i7P$jY_P=DTxi(;Uo>f1I22zo)NVwnS{V2os|)fFJwPXKhHiy7n)CF4r_}&{%w>9IcZgT+Tz2uZ~pbMa=P+QWBtMV(V6jDG`EL0WkJ^6|!WAQ1KUe}uV~ z=6R-F>qBP56v~3~+@S8+!c-+SsYnwbQePHZki`Ch1&EUM*^U|(vLVk|Hr)#r4aE3O z+XW&XO+Ha$0!2ay&k?~_TL8l5+gT+Y1l0+U7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000DsNkl5p-~W|6SI(l8qk@OT@1}b<#-#EKh_1OxDW7t9EU(!waG1*xz{5EL zcsNG@59bIVna^kK9Qz31;T!=BU}Z0G1dz;iU9(?7wtDh}i<|=11s2S^kLj!tevt)egJ-i|~0_emm0;w%F zqz3i?_&W0ECjR|-`Zvutf7E2 zKIQ7AXHlPCLIlui{Fb(>(_#pZ;VV%&K(_#Tjo)+69cZ1oQ8~cb3`zzHyR}*;^~-qz z>xBAR1$Yy-sM&v4pmDg$T`N&Jz`LhR8BNse*n!@OLVsod5Nm{90eB3aq+UM$5kPhXH_&I3U1 zWIT>lY7!|qfVEiTjaN@3JDCp80ajwwf{}OjXBNNGasY4PB8#0Xhn_PQz0XL^0W6)5 zaCN(iAu}AN)&Y7t<+hO{*g*)R4$BP70X!Y!ws7`7O$gcaGwd69Md?zdi&}MY+kt2!-5v(Q->0}Q+ zQYZZ;ST2^t5S0U%&I90WL~h4Q+tT&2OE|FB2dLdYtql|bY(IQ2!1@4d(&rhp)e}C? zj$kSBDIe?sxV}T{08u+swXci=COZg0f`6LD@H;FH_AJ3Yn?aFbXC#sDZS@A+ zz3`K|&dvI-LJ+=~MTQrcMYISk-hg@s?K+n`mP)o*LXFr6RO&D((T@nEv$A8{B zz>pjOqy4Dez$+ezmc3I*A%W|srw(vk*Ze;e34iRaP`^P-%Crg}Y(o{{xMz7o?Q{X$ z2~V+13xl`~mC)7iEyCkiMgZQtVE6EWi#?V$Qc1X#sb>OrukQ6?sg`Q1gx+UQ@c@*P zpG;3k@Wgy7RFHolBHJ+1E?DdRyG9_Dc6;*z?jHDT%#z2#?~b-YkiaVfPE0U#NK5Wz rl0Yjv&whyJ3F^Nou=~fJ!81mG7>Jq9=Lj|b00000NkvXXu0mjf7EL~u diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_36.png b/assets/dolphin/external/L1_Doom_128x64/frame_36.png index cc80bc5434c63f72a426e6f727156b26b8ae2ae6..2f37e6371c5542b5d84042d92642f6363c8f3100 100644 GIT binary patch delta 610 zcmV-o0-gPc3hxAv7=Hl(0002`twPcO00K5iL_t(|oYm5?Pm@6y$MNrbectv$nzs#v zSQ4QxD-z;n2LcrrM;8S)0umZ5^EP&wmPRp5_4#WP&8Wgv3&H@4W zL$x&6zMPA|i@+y%0L9&$iy-qA{K;t_x%rg*7U&(|b+FjtP!*p?5Nv}#RFkqgRKz(L zSpvQ+8x({>oqwK9LT-#1tL9+5RQ$j(C&O#aR30AZ~beh2AkrA>w#s~kll$2!sh$pQW=1A`!j{K!sZ6UN6>=9%(8)y)WKc^ z0x$Y&(k&3{Y*JLcdRh5E2uH^;DAb#84S90<`VQqys{8ZgA=-<9x?bPBBZ@rC6=R?@ zxBfGzdRq#>0({Ch{e@YlAPJP;M!GJobbNm0_1{jw#sGLrQ+X6gS^!?TN=gC#2@rOh wK54?AumwOfuZ=xhw53z4VFFD6VwL*LKS-~%hXKT`UjP6A07*qoM6N<$f{e8m%K!iX delta 1280 zcmV+b1^@c*1c(Zd7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000EKNkl2=H$+3}H-hvK zp_X$NkP^_STm)!s@ER`(4grz@8&Wbpya!(IA;BR)B49&m;39yB1V;lTfF<1H_GV!G z=|w03@WYI#)o+Ex>#22vo}VfUfDeHuCbhj0IDBJBYc%Tl4O0ogv5|Vfk<{fIAQ|7X zCO880MuKUTK!1<%J?-BJ&iGi_Q=joObnjU<4mwXz1~49pS3i(vwA z#_#FpDVRA|i`P@eo}~fKVUQ6pqDAQzPZZF$2rEf%BG7y2Fw6Thfy-2)#VRN2IFUE4 z4&X`6qCH?Vr|lUJV^>zvqX8uKZ_NyTsIa0<^64oYXMgw>=2t(L)%znfK>a_yT(P6t zt!bZki&znAsWDepEk|;9Oag8jwjK_BIOF1h;E!c;_&XRivP2FlqP3sZTE>$Blwywn z+OyoU0PDH(j4;XF-^k~wBUnI@TAD|@XBDh_e?yu&K!ax@-fKr6vJn>R9ZdES;*HFa z@^&~6Nq?+b98rn_A5KBe1eL<9@-8lYg6+NK>ZsZPG_Iz#tdW3Q^JVV?WU3E%PT-_H zc&5=MLsBG|RtIP|?@ECnR*sDYV1q=|$oX-kDkI=jcSkg$jLM~@UJbzEmjF>|oqxBF9R|n@Eh>&if;15z3OkBAJ)jH< z9lcV#}hyq9e#&BUL$<3`p4IYm4Z2AYvRs&%~OGijw1p#yc7Yb zPi{=SuC3qDvw%o%&0ZJq8icCyNo2Qb0EtMo)|`hy88AWuZ@Q~R1MXhr<(xHr{S?`wP)hX6!K+R2S=d=S{XoUH$W@fO28QbM<#s0#`T*< q1X}TA?}yMLLHnHoR|M+WTK@r2MlI>x4$6=K0000vU=5hZ!* z>%9(nd73}LGk!Sd`~9AK5B#51H^>xF(KPVv<>`q+a&a2$vwtt9!BSTvKy?C6wG4pw zWa3dPXaHUAjDh@o{}cgT2~*cEAFBX?8;n8jQEwGs&c!J>nYv_kMOttqI-hl%Y0n^= z^Ptm?3+L)c`CTO&>05)o`gnG8Aq9J-o-kC6&v&DVhOWpE<8(05Fwj-`L7FVL)YYNf zQ#jI&K$-&qf`6STRkc;*Eijt+iiyPslIU*^0iU3+TkBY_>22VmnwRSQ5OrOqUW zKuoO158by0`Jq7v&j*C+VDYH2+5v)5z#Vrso>3L8Uj7dJZw{6}9e>|{L)d<0h+}{Qv)8K#(VjU? z;tUM)D+WTmo&yZ5mD;)}V0{wkfINHCyrjXAetE7`JNS?ghR#9=>+`)vfgl9|tZ(1a zB4a%OMX}X%*}=r9I9IDW0jvQMMDIGiiU3Im04=I?b8Hw{u=r|uF+c;#0M10Ja_yKW zK+XWpg)oFga|j=9m&a$g)*li5d#8!-H9|>409f(1_ybG|w*|}}bm{;A002ovPDHLk FV1k+H02KfL delta 1198 zcmV;f1X26M1hxr~7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000DNNkl3D03?)_m|Ce(guBbe&@rDCt;7Fq=iOGVGjhD1nDdi~#+u~>T102l7A;9K1 z1lSyh0Gs0wU~?P-Y>q>K&2b2@ISv6f$36Q24rDwJU#z{Z%YS|CLxALXo<~%0C5VRz zS2?|alz>WYd4PHj%2-Ko2#^d|k(~137$|Qc!685*U`0x3c>oIuP7II$8h4M+R|Vs( z6+_a%=Xq3&-VxPWrL`U_xXSj<>uVkWJ{afLdQzCxf!#L-H#fbOU-1e7s5Pkdl07NR z%HWhw84NX_IDZE4%whNvU{StR=3CHGK6Le1`IIcRwIY-NUgdjazX@3Jcpj*EiHZTj z2+*tio-r%K8y`i*0H+z004;0gi~*0ajD`3J0=-R#DC^%9c#W6#>oIC;#mz;U7^5O~ zZ$!H)BMwj`0iM2cj|;MTg>NN+HwI{( zvtVc%c(Mf^o+VW?hVue9mtt`61b>n{YK_?i)~czc7toR!`aOW<1vL$koe|m#$duB- z-uPJ_+JErG0F(#*69degbWZWJi8%tA=pUa;*9+(&P)qULOF~OnJ!OpS1!(b001J~w zEESUC>vO>8fxnfA5K#w6@jXBkv{?wZzY-C?st(ZW89d6DuIEWVXJC2^z@ zD}fp%uRwySF@P6uO)BNOaWMnC`QEztEToD7G=E+|LZpY_(!v$icMa0U0GTEiH>teO zmemWCk{|}q+;}#$%3G->&?0q;7+{47q=3I)z~{2P7yi})pQGfdtp@Pj|9lWa-4r)u zA|@}=%V>&5nE^c&^&VUs-J=VrL$(_@!&2bOYVPe-yrzX31X&mCI{Tt zWC7Y|!1Awk1Ebbx%A-VD?PxE+xp#b=>wj@r>Hw4h*6Y674t~=TGq3d$D1}h50Y`Ri z48RfTx~`nx1B}M3;8E)hT4UjsI^VMTk3tYWxhrOpK;sQCB+KWjpzvK^_W&6KvQe-Q zN+N+&3AB=TNDQzVBE5hVy>nwCV*n0QV}PhqW;7y5Am#582{hiIl@VDpttkYMDu0P9 zL!$tX3>Cp+PvJ?k)BLMgtL42(8gFggGDg$%!ZK7bsdpZx5`cQ4EP#a6SgS^k8^@6V z%S1H2>b0g2AhY5jBn!oIUcio?RtD}{ybgZmtCY`w7azec&5b!33E7DQK`Dxh>@{T5 z%qP4*CwtPs3GikJScdBpz@U(;Dkr810<~Dl`Z;jQ(*}pswq9F{e?i-tz_Q-&rT_o{ M07*qoM6N<$f;xgH#Q*>R diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_38.png b/assets/dolphin/external/L1_Doom_128x64/frame_38.png index 43e0f8c6938872fd8dc10338d77340cffbe9a38d..189a16f7b09a3e7820f116e16d307c111c6755c3 100644 GIT binary patch delta 591 zcmV-V0T&1aS-{P=ulgE`pTQMF$bxi+qingcz6f zYn$FVTw=|i;4KF~p68z9x%c4zTosE90Fw@aoSPkV6uLJC!G9_Db`aceDgunOd*I@l z4SUqfSS%<2i3>pXzSIz4+VoO?elG))bPS6h>ml~ih9=VSRr|GPxxQ=>sMDV8 z5oc3*L`u@{O@FFw0nFc?Tp9VqH0?%TVKXL-@&0T`Stw{E0EcN195kv>661a7FhA1N zND$yz2EYTcP*UT&Is}lfG&Q0SP5bPG0mzTHYT-~$h7!$G8Qm9f@lG9JuGCpk!wlxo zRspzEQgYE_xBHMHkRNK*BEbUNHUrSjvdZG5ntma3=YOqJkK=g#oB|7eDjPD1%Dcm> zTiS)C#)Z>&Nn$GgJp#O#Z|bm+j>L2U=p0+N5R?1mL4ftK4ILG5kq-)a`JsA~7=G_K z4DjklQ=bw;XFPz{6Rp((McDN{usyFLfCaq8FuGRt0_*|QF;>ozkm&H`m80QL zQ88op0!T<5WJG4^RuKV=1zOCSq()AFyaf(?Ogw7OXa@Un7rbG;7}@mSAJvU=t8oC~ dC7tBH@drg^wqKLThvxtQ002ovPDHLkV1jIS621Tc delta 1232 zcmV;>1TXvC1lS3X7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000DvNklu&2H41hz`_kZQ=7nAGy4g^#9q@$iSKmZ$K8@6&?*L@wfTmEb5qGO!>e;lnzxyhjO+0we+pQiHPq9wj(FKmsi09zU-F#-Cmu zSAdZo?TT1dJvAqA@J!bAc^D zbm0uo1bT(k1PQBDMe)t3mN$0eXdK-0J^zLAF38bEs$VJL=QRTk6!=N%nR%s{N%JNvVZ!yckPHJH$au;l)z#IUX<{0 zC{n`|7_LbBk`?Y=&KA1*kq&h$J$ zG>+xk;%K!tzlO&LkhX#s=Rrn06yf9s{AhUq47X6H-Ur|u$%9VU`vA}x^ET9)^7ROO zce4+PoPPpR<-aU|r@<%k0bHJ9H)Y@=g(dC-MA$Vlkj9M{Ly!9a{|eys=0~so$Ss*w z@nmChoi09rm#0&~t=YxwM5CaVm0wA}1yE>%-r-8wkoy3ZefNpb%_3aQ0`yE!jYi7& zad`6p9BC~81$9g+OGR_WyfeBB6|?SFk!2ShFXS-}!etC>21mFh$huY_3> zIioIs^fL1+D1ijEAcpt=xbe|=5>BvABy*Wr3AB?xie5f|dMPx^q+!8Vys6|Y&@tt)u8Uosk~)RaJ_$SX1@P=;a@(6VBzbvcd4*P}Q^ ziGSWgdNMNbEQpG>vb&uHXcM9dlB|8>nz|Uy(9t^&O|Sp z)b?Pzs|ueII{Xf=c=)p=3b6J8mmii2rhk;m;}>vkz-KFhg=Yr3G|NR5g$N$c@~d;lz$Rv z-n&$%rw<_Uhy}28B7-9IMDxfsC9qh7T8@jftV~yc4D_@D76C-cP#!$C6cHaT&6O~( z5PDk;%0u?z5r7uwQ)Q%-aFpr48+cuL97QS(Yau!gE#1qN=@G5fwo>H*vfw?t=phVC z;)_xOuhqeQF4y(>=i*1?0<@DoTuDYFtKv{lf|5LYZ60tLi!ULSJx<^Rq7ecv!zm1Q u3Z+OZjT2~PrPVJX3D27b#@mBuj{X2sO=w^UAY$tP0000L_t(|oK=!fXk1ko#ed&7k7Qb7XKWu- z{FkR@BUL5{q9{7gx@gp5yD-p=wBp8{3&H=8J1T7vL8$IC7DVF01Ue!@Vg|d2yEIZt zEkZ`9nyxx=rgS1Rb6mVknB3j{aqhX_IrqZw>X!cV;eD<>)qk^LP`Gd--gTmU=el-* z#nSS3!+U$`U1`|E7kba^@~|hQT^@cu0}2DhW4bM8)S3hE{z4wOo3R0SL=v3JwE*^k zfB%-`mW=JG136IT65y1T022Y9|3V^SMwftBQmoXH$Rlk4vk5*wCs8!14J=o&Qd^3O zEf@h-&tajqQh(fOtWibbC`8FWkOS)bu~2KQIr*J%3P(5b6tFCwg&H`;Va1Ka14ID- zf`!_T36v$JFb-B~hvE(Ze14961ab{LekF2Jh3yV4T%Z#Hwxd`{CL9=yZ=sgv9Ed14 zw&x&m097Wp74?P#s_1H_c$vHdU9y+3P^(XRcF73VK!4$-5ge=sU<+7S1P4_B?zxIW z6C4c46FrK}GzQV{=!`rJn)$7nf!=M)mBHSj7@#bzA8X$ieT9{@sch0_d-PMV_h@E~ zt!d-rW{e%u^@0OD$HuD$R^fUY0W?{=xB~j*%NK!hN&Um!r(=BXSQyQ~*5~D0F?Q(f z;t?oF`hWYb)mt(C%?XZV^*#Q;1fX*V!0Eu|)I)naU>`N=b*GDp$?<9vbb5S}2r%sY zwJNst%lxUX1JwU|Hd#RWc=ZfmQvatjOV?uiVENwZixB{0Q~M4=Iefc+7IJ;{yC<(~ z#P-MH8$ZNOWT|Luy$J^@)5!}?p0iNrI7F{so={zef;#uNv|5d=ck{{kG8CjnLF;L3 z{nqcNryXFt$$AR**`C)9XKAG+V$;tbPF{(&Kg$xpgU|o@_5b*PBK{S-mrnoy002ov JPDHLkV1i$VVyplF delta 1481 zcmV;)1vdKQ1M~p@52C%pmfb0%H`<2l}tx?7@!HLYUcqVt?>vb(>3{r z0U9AO04?M)Gacb!fF?*zwyOCG{JX2b+jw~J6UfP^%8%-G%a4U6Kr2`>-J}RmlX=^LuVbRzUs;fPXIM^YJ^D12krpEfL1!ZQ;xy z_zr+>=W{!D2Z6N4R;{~Z++zT06Z&1dM)C2j;5n%p160%i84QqtFRIv!>g?Rj0-jT| zY-BNj$HpJ$|LiAx7SO$2`zyH10O+}Buzq!Iy)1MVggcPU0ILYq0DsjP9muQ!=rwwe zKPTZ|b$|9F{ig=gE;jVgIkgGNqt-G19o7!Rc^cT|u$>)3=^eYz0wjB+=c40H-2Oty zU&78>D1!l_i6M-_P176cr#R@d&{0oAO^UT z_0bmb7|sCLQLIU0ph9dF9;efBE0NjO<$5E!j$!}~sSvZ|J!|>=%*T=Bs-Q8zY7j_v zTLE!g07N6$18WP_5eymw+-2OUgX@;`wtojeX7qa|)Vq{aGl8}XSXuJ4UWN89?E#RH zI8Z^ggn?+?0@U8gC&Wec0kWtV~mmi&0>wAymnFBq%9)?l}CZF8~`4A z$z%yBqrEgQ*`!t973_w#v)aE`!*>qX+2@2SBu1=IeGz3buIjruvJ(E4VOXC zUicj#(Ke!Tp8Zq?F@ZK7#r%BKe-1@PdY)Y!cUSgHws;&aIbPZoO&PAs+ASS*7EqPd zXcD@dKY@aP+Qwz2XL**R>q30&G2UbwSb=WmPaqpmy&wezstv5=a(Nf}x|2To00000NkvXXu0mjf>_^t= diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_5.png b/assets/dolphin/external/L1_Doom_128x64/frame_5.png index a128010008a4fffe60f915fe5d716ab65f9a29ea..fa7e6ad10fa29f1a3b3ab562cad5e78649489895 100644 GIT binary patch delta 583 zcmV-N0=WH&3Dg9T7=Hl(0002`twPcO00J9HL_t(|oQ;yfOB7)kho6~Qn-$C1yl4c@ z5FWae9)gghnZTg`LLundvExo*SrF8vyMKm3;ie0AbI(~YMqn7_Zd#5yJHHOIGqdig z?=s9Y&%E#N`@R?cf4R{B@M-{)QxW9A9~l>$WO*?$`5z>^z;zzGMyY;@Gu zA;zFOTpB}8WR(4YOR@Wmu|8we{_y)u`&C>g94r5@{8v&uHC%v-kkl-}NQxsJyyypp z6dxBw&l?TEu7+jwIkO2zQ4S`szP0&MniCj(EtNrO-jM4 zYb6sVeJO==+ka|-X~IGPMr192W&%vGx^+of)U6Q0jsF}=gs%o*X8q|}U z#F=sefoX)i(RhBsMu4T{RPDsi3=3=}yOO;jNeAI5W))VuLFcUpXz>AN4WguJkE{cR zKLx&G9k>1Xwj=FDi+D_(SOMf&_Zsv~^1F{~-eG2h z83}k?T+}@15yp6y<8)1luk@ER-O3GX2?5WuE~W>w0YEVyU@fI7%(np4-ItWy`Xg-z zc`&eERzRQ=04P0@Bz2{qz35N!uyL>GP|yPx04nItUHX^Og~ZQlw0mG$n;D1!{sDgi V2-y6DBVPaj002ovPDHLkV1h+56R7|I delta 1152 zcmV-`1b_R~1c?cd7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000C#Nkl~&p3m&k_W00Y#7wtomN0x2Tc#R)DrSwIt* z$U=OJ*qZcRL~yo%25JIFWbSDH07n2Mc3Hg^I5EIK;MMyU@&S$j0D#`VF`g`l*9U>z z{Jua^3)o>RN$miml*^)jZhkNQ%`QkO08Yw9K|;(7kxvpqDgo5QONr*T*QRT`**gbm z1V9yCdTl9ig@5q`;;axZ0KDpF3n^L$;0WT0s~;dx09?DrZAR@zV{yNK3b`DF2tZ=@ zH5pd>c@I>dPZh;-0Tl8%#7R@M(!U3=W7YHDSsdXpfHh{fixG-|v4ib+2vo4N5-3^y zH8iVi1u?yOjp`X0u#E#q1GQ0mD{=JV1@2vfNGx-JnSa&KMJur6zId;>wYH@Uf=KTG z+-!l{hBKB`e^fu&&J~sjz+?4m(@4!27?#DV4EG1q-w2wCvOQib&H!eyVp|-I?=AqZ zhs=_G&59vP1Z7-P0Tfa&InjHZ2dMK4$puoXzbGd#$pTubP_)I>klq)de%B)3;!tZ< zOn}Ew2Y-QCNR>c)T1frQn*3GxbKM<;4#0gt=_#MZm`{MG3sC*C9UvlwtJ{0b7Tp$SDgl0qm^=UAw6vRBYyyo7o#DbOBi?c@3?IgryL1k=6vB- z5aR;^=b@h~+G0l|SKe&Tg zSlq`OZ5J&omyo61Hd^gGA#nf=KAFhZptrY6$l4*e^r#L_UkI@z-aAW}5k%|vz44^m zQh!9uF(m*C!o0y11m_v*{dgpZ9S(=o0aSovJE zf;|fOxkpFFxb0}~juc6XJAs)6RaQ1(AZ{ zyf`wfegK0TLA_X@S5-TL$N`f(ft-MF_dMPj8CE}l(H6iJ0fsh8-yK=3zu+5J&ni{d Sz20L00000dL_t(|oQ;w_PZUuYg`Yb!FiSLd2-%!&wbwu|G$Fz7|7=UaE2fq1J5tUz~cN}3zM6=tA8-PeE=Se13w;%QCjk% zp(2IS=}3v|*G=S%fT?!j05=03fbS+R`d$veD}t?fYN#*^CreMeBMMXf9O0e~BTNWi zY9Ec{pbhS)LCGXl!1YS~l6$fyk9ZH*uBpcEJnQ?Gbl3TT7wSE%a*}N zyFIWf3CzCEvVTqn1xet(RxJZ7`;zMB_=g(cfU*0Mbf}MNfCs)UQ zH0KerPl@zN?K*z1b;D<^;2!N0vl}UChORHI`|tV z*`Ng=6?LsxvjJYAbTm< zf^Al0*H#8VNw-;%@)>AKvU9f;Df=)c0?e@!L+=(3;E~zQ5+UtngWZ>^nZgYjUD9eI rNh(V9OmQ|BLeBsksG0t6$N~QVbv-DIZox|z00000NkvXXu0mjfH;))A delta 1173 zcmV;G1Zw;01f2;35{E=mqSC z_ZrCb910E^!crxM~O zfrVb*S8#d(*+WTs1(=mw8uL@@d+s$mAT0qXB^L&cVO9)z3JKB?pfx<#(A4qLa&0Gh zryvypu%^psEPn``BhDuxh0!7WY%tz_92FBVn+tMCYmBe)R2 z>LIg~U#nz@BEkE<`UI#(fyRkWbS!}FUvLhPV)I3iK&=Ysl|s=H*MfUq0K2Yde2q;l zubiOXV}B_L%wkjyq`QUKb=t=F0wkD70jLki-R0A`=LxV>fp%V&0z{N>?Rbl|d3q_DfColr2xjZ%D#kAYWHCOxp5on-`%t~#TP51=DYasfw%vb1fYw84 zoX4Ami=LEoj3o^ly>XV{C;%6q(WG2hAI9uq6x%t*+9A2r?hdLP2+=gWb(OF}h~D+1 z`+sr6l6TJW$zU)|U@wtM2+A{XdlK0^enx^QlB78mEcO1;7>neV188`T5_la7DJ2mBEWjZFHkQ(h7?ovh zXvr83md*rfv6LH5diA*`+7@j4U0p{HSbs8DKmW5QA4rO=6+o*V$GUCQmMe9QFejj_ z#Y6r}Q6NATS@UQ@tt7tnJz)lpe0M1n0KS~|bM8D`P`zKnBU=(=fC>RLRA9B|?zus; zf)NS4<-e393ebaf&z)N(Xd#mlh^qiBj#)FeX4bHzf`69xh5t3@^z?QNsTE*`6@P`u z;C*fG<1PQCC=(#MBG3pKkGV8{U6|$~N n18N~a(k_)|=_kWm1^xp=SV>rJnGXH100000NkvXXu0mjf3W5g`8?OqX(L`=70@AI^JP+IM zmY$r;B)`1(=FNWw{(pttF;EHsa0-x)fk#JUU}5fhgbAjuD}T&j&%y0+;KyS%YKvY} zC{m~$j96U1Ya(X^OeN(eZU#I6-)%o0W;p;)2{+@ZLSg1VFFv>$QJCZR5pJufFd=*? z*&XRY0`9xqGRZOEdbOeDhOB8z>HH8(OJ{K??H3u1o1DTzH0UvdB16#2Com^l2O~8G z;F%;a+iGQ#41dd#z+KZx23EEubf;Zw}Pb=0P7Mv2BxEpkCn_}V#k3$_!CWlG@gv`WuMq`x)MrC)|ViZ zt)@mhT}jES1H2Np#%1O3-bs(N{Tiw|Ria4kUR@Vq41aa~P@-OF!%bae6MI7+f5Wsl z=mAJook_j2!qqjvK{d|7U+3#w13;gK1IrkEHUCwnQ$ z&i+lLV?n^dM1a|I`V2!ofIH@84jyJPCCDteS)3Pe6FlWs0aMyQ z*1$u7?Sq~{1UCgt=mWS4W;XjT*NsN!J@2U4>Agll|CD#Z_V0Hp|iU`69pbtDX(Aev_cC<+$=)Zk+RM=jCn_!_j1)xUpMafDa{NVA(RR#XAE4wh{bsAAp;q|E*v z&MdPC%x=DR6fSNB2nw--=dXEC;}TAa$2d;+ZF)=>q+@BnR*);ri<}-sM{ui3;ri z61{uKCaEpm+1RHb?E=tPO9znnW1)i|+(yo*{L^UIoWQCQn+iaqZm&=lOPEcaZ*++j zm@*s`fcB=y&iL5bZ?zjJ4ODVsp`_QL05tv>PJiIB0mIJzjA^4fPv=3uK%yK&=SQ!?V(%nIk10j-u*RB$F1OeSYdmc3{ zS%0rNej)@+8>}EO-$3n2K-=ck;=40Wm zprLWzI(eksBNuyBFZ^IJFpn|*^+%NW9AO%b9Iqy=}IcJ^JTSbs%41!6=N z1=sRN6~HNMZ3lk_VfN9pV3GU1N=mgwVD=t)i+1k!WLp5x>D9`pbQ=AZg^ce!L+nf- vCiiu){YV*00000NkvXXu0mjfSat-% diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_8.png b/assets/dolphin/external/L1_Doom_128x64/frame_8.png index a18485d6f511e2e951800e13b367b46804f0145e..f5911b1b87fdf8c1cf2f0e6c72bf8372bf0a4de8 100644 GIT binary patch delta 597 zcmV-b0;>I~3E~8h7=Hl(0002`twPcO00JpVL_t(|oQ;xAYZFlzM$er|n<*`w&`s+? z6QoN&x+sWPoDmfK7cB^G`x7!qYY_z9h}*jJCsaWi+du^u&AN)6ico16Nk1TyWHOJ7 zNhWDl-p%D6&VAqKe!%~aVmJay1pur8h(?V4>eaPbxCuZm1An1)wT3k^vp5ReU*B7;{52=m%VjiZ7WNGN$ui&#$!KqUZ)QgB`Z_MvCSqGLRFJssk{Y;7S*- zhJlfyR#tS%RDiq_45BYtRcMBNFo*r;ONsoQf#J{b8=m!xE^A5PDhV>9BDlm|6yX z$M=X*r47Di0^Vu1f5XPdR@_k|_EN)!yy9aizbi=>!8DcwTV4O`Qwh+@bF2b{aWy}= z0~l`}JVk0Xyy&4TorEh`KBu(Zo&5R{;FUny(}fzvxPR#C1VAe4STZ^~(*an- z!&KPhR_QV|0>~{P9J~Ob_ z5@4~G8cuad@q@Z_>i2_z{W^k{51^zeNoq=Gz349hh{5Uou`wUO0UIEP9z9`rC|Qm@ jNi8YqfxFt1)a`+PO$i&&=mT9^00000NkvXXu0mjfVI~#I delta 1185 zcmV;S1YY~%1gQy-7=H)`0002e)_;Eh000SaNLh0L01FcU01FcV0GgZ_000DANkl4Q~iwfJ^LkT}zj!hSvcWfPaKi1b2aS5uD-#S9_}f z5+jkFc#2p^`Y9rKLjVCt;EK!>?Z35G04Ppby&iaTfPWZQ@3)ZO+ADz88Xmt#JXsK5 zp9FI2`wmGj;Dk_8+5uK2m&g3v`d)g?DJUrbPRWHqLX3sTCyAhx03h*FqPgR><=ScX z&OsRgU`?0VSbq#$VLX92FQf}#T=mvQiq-)*f_UQUZ!J*(T)Q8~tj4YG#r^#$PL*)c8x*#3p&04X+KmJ_&C0aPiJZE+CN^8(m)6!{*T zTDx+B@qZrbB(Msp5@>e|vFp6a--Tbt-J8$>xGyN(<@31b6A`Y;PGLpgCE*P4p#m}G;E##P9;VPAfj&XkR(f- zO`UIai50kII4XeXO%cod+||EpH_#hY$;pLuvw!KA03tq&hIlSv+|_?#*yv8V5`txa z;lCs>BGcE*%RQy5oln~j*n!y@g4J_t9OFj-RmdN&=d5nceYmTCw@bk8DYs&>wB0}B z1Xg&Q$6JL9%E~2VX~PCJE)o(4(BM;vd<|x?T|(9g$z?=$(0m}ollbT=!6FFi`q}-Y zVSgzj=P(JtgD@+!Ap`!+c?W4v;)Km1wE(=ym&|9e-B}JHeHTbJ6jZhCa11H|WUYKE z23o?>S}}2k0N)@&UapchQ_0PT~Cr_^;8M2VN$$btDqHuJ|zlK$dXCt)Rw9)Sb3D52jy8m}@)mX);pWg+s}t2t&!BM8gXPr(j?DpdyN6G5|F0A{+>Z!hw2-3BIL zER#%CSrEGpyd3WU9V;impv}^Epc+DQwhMm&aLs2zx*-x^00000NkvXXu0mjfcLX8Q diff --git a/assets/dolphin/external/L1_Doom_128x64/frame_9.png b/assets/dolphin/external/L1_Doom_128x64/frame_9.png index 4030284bf7ae552950626bc39147e8f8dcb54128..57491c2edbb3da617cf629e659e4315fa895dd1b 100644 GIT binary patch delta 598 zcmV-c0;&D63F8Ei7=Hl(0002`twPcO00JsWL_t(|oOP1HOB7)kho5g|ZB{I2^WsL} z4&k9o=|Kodnh6a0FBF2V9Xsw6mIXmwy8CAs6mGg;H}{+dV+4j#?xy9av-9gPJG<*b z-{oT-o_XKj_kAz?cU7VR;FSQddLSM!w(94<&Ga<@3SAIc=YMNh13NQ=zzqk$Y;@e$ zA;wS~?ioXFWP1I8D{A<22ubxG7)f!Z!*U30$RN*Qg1OFf}j$Yf=h! zRV$e=;Y%r8*nd_7EDII_Fp<5yLm4cv+f_+g)+2p~BDhIPRg$D5C|OK%regP8C8#F1 zh%@CB0?UNF)p&lxCcsv5re@-2h7FFAJ;~XSq{DC&s|c&@p!LoJwD=IK1W{6VM%Dr2 zPlB&lCrv-T<4XI{B38f;PTh6q*)HIFAZ_YU%}P>nwSNyFRkSA=?Y8t8u+Spl9Rycz zWZ9HRTj`!Et&M7Cv;oaf`#TXt`JFb}O}Kv9JEd>NzPxeXWba~N1(0XouaQr(De?Z( zns<~LAy_*Q@TB`t^QNrFnDH#f*_skx=`U%jksJ0B0$yZYEDvS_fbM*Ny_BXf-vChi zKvHu1k59B6(EB&WodxmuAW)m% zH&|)`Cu}999Y9LCBHGvH_ttk#K}i8VrGcElL$%)peNo+wDx&#x^|kqYfwf2 zRMBPhECsDF?tegB6w(ENSN&`u#p?hXLELfm10)JSYxnpW={cz{?f>6}Tn$nLV6pq2 zjHvy51gg!uiekF}8u=RHtSMS+e+95(_2WNT9O*GYG-kI82~EJ*!A?8`YS>x{w5jJkn9;bTdPW5t;{et`O?o~`9HV$adzT;++Z0Uo|#vTdE+4@(!TQ z7PQZ3`ig3gYNy({!WIFnSpD8K($fb^*J;sPhZU1yZWLEGG!b0=QHt+v0jy?+Z}xapXrFYVC>% za3AgGhf4oe6m0GQO(w<)U`5{EUT0X+DsM7{^3z1>3A3Bl!x>frQ+kVxWJX9+Wc;NBngXWf=E zVtw>Nr^jwp3^~UVpjx7SYXl^@&DoRnF=$TE`>Cd5I{Dl z6^LD>!4fC*MD8Tj0=EF7KB&TW(xWfI0)N=XXAwbmjBvCANc*q`R3K?RP?5%_T`arp zA7C;K%!+bxzm#=Hk7uSmY8%Nano&sq(=Z&#_rGi2qkh+7)#|6lI1+6prUek;0^XYY zj){!uLo+`a_770N0XVF#x$oM#I2Wh_mjLtFmqwRu?*1maqF|J##+7e|HF4-jx8XcP;Ks%ozwY9QoJpe7(Z zJ&%t@h1Cxbv;}BIfZ>hOPe&E&Zz2eb0X!nWc+z%JNd&(E;?-|NxisUV00000NkvXX Hu0mjfJ)tH- From d267665310b31c915f1dfc9e4bbb04b358409c05 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 28 Mar 2025 14:39:58 +0300 Subject: [PATCH 057/125] upd changelog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72d4dcb03..fb3e03aa6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ ## Main changes -- Current API: 83.1 +- Current API: 83.2 * SubGHz: Add **Revers RB2 / RB2M Protocol** (static 64 bit) **full support** with add manually (by @xMasterX) * SubGHz: **Fix Hollarm protocol with more verification** * SubGHz: **Fix GangQi protocol** (by @DoberBit and @mishamyte (who spent 2 weeks on this)) @@ -20,6 +20,11 @@ * SubGHz: Various bugfixes and experimental options (rolling counter overflow) (by @xMasterX) * Anims: Disable winter anims * NFC: mfclassic poller fix early key reuse in dictionary attack state machine (by @noproto) +* OFW PR 4164: Added Doom animation (by @doomwastaken) +* OFW PR 4133: add nfc apdu cli command back (by @leommxj) +* OFW PR 4159: NFC: Support DESFire Transaction MAC file type (by @Willy-JL) +* OFW PR 4153: NFC: Fix NDEF parser for MIFARE Classic (by @Willy-JL) +* OFW PR 4160: GUI: Fix widget text scroll with 256+ lines (by @Willy-JL) * OFW PR 4132: Infrared: Fix universals sending (by @Willy-JL) * OFW PR 4149: HID Ble: increased stack and improvements (by @doomwastaken) * OFW PR 4126: Stricter constness for const data (by @hedger) From 7f135dae0354d812200b2a096471a053c998bc2f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 28 Mar 2025 14:47:33 +0300 Subject: [PATCH 058/125] little checks for timers --- applications/services/power/power_service/power.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index cca15f0c9..31fcfcbd2 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -416,13 +416,18 @@ void power_api_set_settings(Power* power, const PowerSettings* settings) { //start furi timer for autopoweroff static void power_start_auto_poweroff_timer(Power* power) { + if(furi_timer_is_running(power->auto_poweroff_timer)) { + furi_timer_stop(power->auto_poweroff_timer); + } furi_timer_start( power->auto_poweroff_timer, furi_ms_to_ticks(power->settings.auto_poweroff_delay_ms)); } //stop furi timer for autopoweroff static void power_stop_auto_poweroff_timer(Power* power) { - furi_timer_stop(power->auto_poweroff_timer); + if(furi_timer_is_running(power->auto_poweroff_timer)) { + furi_timer_stop(power->auto_poweroff_timer); + } } static uint32_t power_is_running_auto_poweroff_timer(Power* power) { From d6f9d7e994f7a6ecd2f81bcac75aeb2e214f801b Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 1 Apr 2025 00:18:09 +0300 Subject: [PATCH 059/125] upd changelog --- CHANGELOG.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb3e03aa6..618589cf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ ## Main changes -- Current API: 83.2 +- Current API: 83.0 * SubGHz: Add **Revers RB2 / RB2M Protocol** (static 64 bit) **full support** with add manually (by @xMasterX) * SubGHz: **Fix Hollarm protocol with more verification** * SubGHz: **Fix GangQi protocol** (by @DoberBit and @mishamyte (who spent 2 weeks on this)) @@ -20,14 +20,17 @@ * SubGHz: Various bugfixes and experimental options (rolling counter overflow) (by @xMasterX) * Anims: Disable winter anims * NFC: mfclassic poller fix early key reuse in dictionary attack state machine (by @noproto) -* OFW PR 4164: Added Doom animation (by @doomwastaken) +* OFW: Fix DWARF dead code elimination and linking +* OFW: NFC: Fix crash on ISO15693-3 save when memory is empty or cannot be read +* OFW: Reduced ieee754 parser size +* OFW: Added Doom animation (by @doomwastaken) * OFW PR 4133: add nfc apdu cli command back (by @leommxj) -* OFW PR 4159: NFC: Support DESFire Transaction MAC file type (by @Willy-JL) -* OFW PR 4153: NFC: Fix NDEF parser for MIFARE Classic (by @Willy-JL) -* OFW PR 4160: GUI: Fix widget text scroll with 256+ lines (by @Willy-JL) -* OFW PR 4132: Infrared: Fix universals sending (by @Willy-JL) -* OFW PR 4149: HID Ble: increased stack and improvements (by @doomwastaken) -* OFW PR 4126: Stricter constness for const data (by @hedger) +* OFW: NFC: Support DESFire Transaction MAC file type (by @Willy-JL) +* OFW: NFC: Fix NDEF parser for MIFARE Classic (by @Willy-JL) +* OFW: GUI: Fix widget text scroll with 256+ lines (by @Willy-JL) +* OFW: Infrared: Fix universals sending (by @Willy-JL) +* OFW: HID Ble: increased stack and improvements (by @doomwastaken) +* OFW: Stricter constness for const data (by @hedger) * OFW PR 4017: Alarm improvements: Snooze, timeouts, and dismissing from the locked state (by @Astrrra) * OFW: fix: flipper detected before it was rebooted * OFW: NFC: FeliCa Protocol Expose Read Block API and Allow Specifying Service From f783e0b3ab6c28cd84c323e7e8be5faff35fb57a Mon Sep 17 00:00:00 2001 From: DrEverr Date: Tue, 1 Apr 2025 18:39:42 +0200 Subject: [PATCH 060/125] add support for Favorite App Ok Long --- applications/services/desktop/desktop_settings.h | 1 + applications/services/desktop/scenes/desktop_scene_main.c | 5 +++++ applications/services/desktop/views/desktop_events.h | 1 + applications/services/desktop/views/desktop_view_main.c | 1 + .../desktop_settings/scenes/desktop_settings_scene_start.c | 1 + 5 files changed, 9 insertions(+) diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index 784b1eeba..6f81d99cb 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -14,6 +14,7 @@ typedef enum { FavoriteAppLeftLong, FavoriteAppRightShort, FavoriteAppRightLong, + FavoriteAppOkLong, FavoriteAppNumber, } FavoriteAppShortcut; diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index 4fdcc3400..b329cc16d 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -174,6 +174,11 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { desktop, &desktop->settings.favorite_apps[FavoriteAppRightLong]); consumed = true; break; + case DesktopMainEventOpenFavoriteOkLong: + desktop_scene_main_start_favorite( + desktop, &desktop->settings.favorite_apps[FavoriteAppOkLong]); + consumed = true; + break; case DesktopAnimationEventCheckAnimation: animation_manager_check_blocking_process(desktop->animation_manager); diff --git a/applications/services/desktop/views/desktop_events.h b/applications/services/desktop/views/desktop_events.h index ba91a30cc..8eeea00e2 100644 --- a/applications/services/desktop/views/desktop_events.h +++ b/applications/services/desktop/views/desktop_events.h @@ -8,6 +8,7 @@ typedef enum { DesktopMainEventOpenFavoriteLeftLong, DesktopMainEventOpenFavoriteRightShort, DesktopMainEventOpenFavoriteRightLong, + DesktopMainEventOpenFavoriteOkLong, DesktopMainEventOpenMenu, DesktopMainEventOpenDebug, DesktopMainEventOpenPowerOff, diff --git a/applications/services/desktop/views/desktop_view_main.c b/applications/services/desktop/views/desktop_view_main.c index 57cfa1a3e..9ea144364 100644 --- a/applications/services/desktop/views/desktop_view_main.c +++ b/applications/services/desktop/views/desktop_view_main.c @@ -74,6 +74,7 @@ bool desktop_main_input_callback(InputEvent* event, void* context) { if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { main_view->callback(DesktopAnimationEventNewIdleAnimation, main_view->context); } + main_view->callback(DesktopMainEventOpenFavoriteOkLong, main_view->context); } } } else { diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c index dfcac3eed..23309bd74 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c @@ -182,6 +182,7 @@ void desktop_settings_scene_start_on_enter(void* context) { variable_item_list_add(variable_item_list, "Favorite App - Left Long", 1, NULL, NULL); variable_item_list_add(variable_item_list, "Favorite App - Right Short", 1, NULL, NULL); variable_item_list_add(variable_item_list, "Favorite App - Right Long", 1, NULL, NULL); + variable_item_list_add(variable_item_list, "Favorite App - Ok Long", 1, NULL, NULL); variable_item_list_add(variable_item_list, "DummyMode - Left", 1, NULL, NULL); variable_item_list_add(variable_item_list, "DummyMode - Left Long", 1, NULL, NULL); From d08d38f3b2a05fd55e3c50ca9be4ca378fc0c6de Mon Sep 17 00:00:00 2001 From: DrEverr Date: Tue, 1 Apr 2025 18:48:14 +0200 Subject: [PATCH 061/125] fix --- .../scenes/desktop_settings_scene_start.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c index 23309bd74..8555bbf71 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c @@ -18,6 +18,7 @@ typedef enum { DesktopSettingsFavoriteLeftLong, DesktopSettingsFavoriteRightShort, DesktopSettingsFavoriteRightLong, + DesktopSettingsFavoriteOkLong, DesktopSettingsDummyLeft, DesktopSettingsDummyLeftLong, DesktopSettingsDummyRight, @@ -247,6 +248,13 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even SCENE_STATE_SET_FAVORITE_APP | FavoriteAppRightLong); scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneFavorite); break; + case DesktopSettingsFavoriteOkLong: + scene_manager_set_scene_state( + app->scene_manager, + DesktopSettingsAppSceneFavorite, + SCENE_STATE_SET_FAVORITE_APP | FavoriteAppOkLong); + scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneFavorite); + break; case DesktopSettingsDummyLeft: scene_manager_set_scene_state( From 380402a55cca7c0ee07a0b3ccd8d2d5f17ed653b Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 5 Apr 2025 23:40:13 +0300 Subject: [PATCH 062/125] revert cli changes before apply of new ones --- applications/main/ibutton/application.fam | 11 +------ applications/main/ibutton/ibutton_cli.c | 34 ++++++++++----------- applications/main/ibutton/ibutton_start.c | 11 ------- applications/main/infrared/application.fam | 15 ++------- applications/main/infrared/infrared_cli.c | 20 +++++------- applications/main/infrared/infrared_start.c | 11 ------- applications/main/lfrfid/application.fam | 11 +------ applications/main/lfrfid/lfrfid_cli.c | 22 ++++++------- applications/main/lfrfid/lfrfid_start.c | 11 ------- applications/main/nfc/application.fam | 11 +------ applications/main/nfc/nfc_cli.c | 19 +++++------- applications/main/nfc/nfc_start.c | 11 ------- applications/main/onewire/application.fam | 10 ------ applications/main/onewire/onewire_cli.c | 27 ++++++++-------- applications/main/onewire/onewire_start.c | 11 ------- applications/services/cli/cli.c | 20 ------------ applications/services/cli/cli_i.h | 7 ----- 17 files changed, 61 insertions(+), 201 deletions(-) delete mode 100644 applications/main/ibutton/ibutton_start.c delete mode 100644 applications/main/infrared/infrared_start.c delete mode 100644 applications/main/lfrfid/lfrfid_start.c delete mode 100644 applications/main/nfc/nfc_start.c delete mode 100644 applications/main/onewire/onewire_start.c diff --git a/applications/main/ibutton/application.fam b/applications/main/ibutton/application.fam index 06455aeb9..01c02ec23 100644 --- a/applications/main/ibutton/application.fam +++ b/applications/main/ibutton/application.fam @@ -12,20 +12,11 @@ App( fap_category="iButton", ) -App( - appid="ibutton_cli", - targets=["f7"], - apptype=FlipperAppType.PLUGIN, - entry_point="ibutton_cli_plugin_ep", - requires=["cli"], - sources=["ibutton_cli.c"], -) - App( appid="ibutton_start", apptype=FlipperAppType.STARTUP, targets=["f7"], entry_point="ibutton_on_system_start", - sources=["ibutton_start.c"], + sources=["ibutton_cli.c"], order=60, ) diff --git a/applications/main/ibutton/ibutton_cli.c b/applications/main/ibutton/ibutton_cli.c index dcac8f963..2be75cb75 100644 --- a/applications/main/ibutton/ibutton_cli.c +++ b/applications/main/ibutton/ibutton_cli.c @@ -8,6 +8,19 @@ #include #include +static void ibutton_cli(Cli* cli, FuriString* args, void* context); + +// app cli function +void ibutton_on_system_start(void) { +#ifdef SRV_CLI + Cli* cli = furi_record_open(RECORD_CLI); + cli_add_command(cli, "ikey", CliCommandFlagDefault, ibutton_cli, cli); + furi_record_close(RECORD_CLI); +#else + UNUSED(ibutton_cli); +#endif +} + static void ibutton_cli_print_usage(void) { printf("Usage:\r\n"); printf("ikey read\r\n"); @@ -18,7 +31,7 @@ static void ibutton_cli_print_usage(void) { printf("\tCyfral (2 bytes key_data)\r\n"); printf("\tMetakom (4 bytes key_data), must contain correct parity\r\n"); printf("\t are hex-formatted\r\n"); -} +}; static bool ibutton_cli_parse_key(iButtonProtocols* protocols, iButtonKey* key, FuriString* args) { bool result = false; @@ -111,7 +124,7 @@ static void ibutton_cli_read(Cli* cli) { ibutton_protocols_free(protocols); furi_event_flag_free(event); -} +}; typedef struct { FuriEventFlag* event; @@ -203,7 +216,7 @@ void ibutton_cli_emulate(Cli* cli, FuriString* args) { while(!cli_cmd_interrupt_received(cli)) { furi_delay_ms(100); - } + }; } while(false); @@ -213,7 +226,7 @@ void ibutton_cli_emulate(Cli* cli, FuriString* args) { ibutton_key_free(key); ibutton_worker_free(worker); ibutton_protocols_free(protocols); -} +}; void ibutton_cli(Cli* cli, FuriString* args, void* context) { UNUSED(cli); @@ -239,16 +252,3 @@ void ibutton_cli(Cli* cli, FuriString* args, void* context) { furi_string_free(cmd); } - -#include -#include - -static const FlipperAppPluginDescriptor plugin_descriptor = { - .appid = CLI_PLUGIN_APP_ID, - .ep_api_version = CLI_PLUGIN_API_VERSION, - .entry_point = &ibutton_cli, -}; - -const FlipperAppPluginDescriptor* ibutton_cli_plugin_ep(void) { - return &plugin_descriptor; -} diff --git a/applications/main/ibutton/ibutton_start.c b/applications/main/ibutton/ibutton_start.c deleted file mode 100644 index d252bed7f..000000000 --- a/applications/main/ibutton/ibutton_start.c +++ /dev/null @@ -1,11 +0,0 @@ -#include - -static void ibutton_cli_wrapper(Cli* cli, FuriString* args, void* context) { - cli_plugin_wrapper("ibutton", cli, args, context); -} - -void ibutton_on_system_start(void) { - Cli* cli = furi_record_open(RECORD_CLI); - cli_add_command(cli, "ikey", CliCommandFlagDefault, ibutton_cli_wrapper, cli); - furi_record_close(RECORD_CLI); -} diff --git a/applications/main/infrared/application.fam b/applications/main/infrared/application.fam index 586adf110..575bebbe4 100644 --- a/applications/main/infrared/application.fam +++ b/applications/main/infrared/application.fam @@ -15,23 +15,14 @@ App( ) App( - appid="infrared_cli", + appid="infrared_start", + apptype=FlipperAppType.STARTUP, targets=["f7"], - apptype=FlipperAppType.PLUGIN, - entry_point="infrared_cli_plugin_ep", - requires=["cli"], + entry_point="infrared_on_system_start", sources=[ "infrared_cli.c", "infrared_brute_force.c", "infrared_signal.c", ], -) - -App( - appid="infrared_start", - apptype=FlipperAppType.STARTUP, - targets=["f7"], - entry_point="infrared_on_system_start", - sources=["infrared_start.c"], order=20, ) diff --git a/applications/main/infrared/infrared_cli.c b/applications/main/infrared/infrared_cli.c index d735635e2..85ae95658 100644 --- a/applications/main/infrared/infrared_cli.c +++ b/applications/main/infrared/infrared_cli.c @@ -553,16 +553,12 @@ static void infrared_cli_start_ir(Cli* cli, FuriString* args, void* context) { furi_string_free(command); } - -#include -#include - -static const FlipperAppPluginDescriptor plugin_descriptor = { - .appid = CLI_PLUGIN_APP_ID, - .ep_api_version = CLI_PLUGIN_API_VERSION, - .entry_point = &infrared_cli_start_ir, -}; - -const FlipperAppPluginDescriptor* infrared_cli_plugin_ep(void) { - return &plugin_descriptor; +void infrared_on_system_start(void) { +#ifdef SRV_CLI + Cli* cli = (Cli*)furi_record_open(RECORD_CLI); + cli_add_command(cli, "ir", CliCommandFlagDefault, infrared_cli_start_ir, NULL); + furi_record_close(RECORD_CLI); +#else + UNUSED(infrared_cli_start_ir); +#endif } diff --git a/applications/main/infrared/infrared_start.c b/applications/main/infrared/infrared_start.c deleted file mode 100644 index 6de11b677..000000000 --- a/applications/main/infrared/infrared_start.c +++ /dev/null @@ -1,11 +0,0 @@ -#include - -static void infrared_cli_start_ir_wrapper(Cli* cli, FuriString* args, void* context) { - cli_plugin_wrapper("infrared", cli, args, context); -} - -void infrared_on_system_start(void) { - Cli* cli = (Cli*)furi_record_open(RECORD_CLI); - cli_add_command(cli, "ir", CliCommandFlagDefault, infrared_cli_start_ir_wrapper, NULL); - furi_record_close(RECORD_CLI); -} diff --git a/applications/main/lfrfid/application.fam b/applications/main/lfrfid/application.fam index efded8001..c067d786f 100644 --- a/applications/main/lfrfid/application.fam +++ b/applications/main/lfrfid/application.fam @@ -12,20 +12,11 @@ App( fap_category="RFID", ) -App( - appid="lfrfid_cli", - targets=["f7"], - apptype=FlipperAppType.PLUGIN, - entry_point="lfrfid_cli_plugin_ep", - requires=["cli"], - sources=["lfrfid_cli.c"], -) - App( appid="lfrfid_start", targets=["f7"], apptype=FlipperAppType.STARTUP, entry_point="lfrfid_on_system_start", - sources=["lfrfid_start.c"], + sources=["lfrfid_cli.c"], order=50, ) diff --git a/applications/main/lfrfid/lfrfid_cli.c b/applications/main/lfrfid/lfrfid_cli.c index eaafcda92..a25032d6a 100644 --- a/applications/main/lfrfid/lfrfid_cli.c +++ b/applications/main/lfrfid/lfrfid_cli.c @@ -14,6 +14,15 @@ #include #include +static void lfrfid_cli(Cli* cli, FuriString* args, void* context); + +// app cli function +void lfrfid_on_system_start(void) { + Cli* cli = furi_record_open(RECORD_CLI); + cli_add_command(cli, "rfid", CliCommandFlagDefault, lfrfid_cli, NULL); + furi_record_close(RECORD_CLI); +} + static void lfrfid_cli_print_usage(void) { printf("Usage:\r\n"); printf("rfid read - read in ASK/PSK mode\r\n"); @@ -568,16 +577,3 @@ static void lfrfid_cli(Cli* cli, FuriString* args, void* context) { furi_string_free(cmd); } - -#include -#include - -static const FlipperAppPluginDescriptor plugin_descriptor = { - .appid = CLI_PLUGIN_APP_ID, - .ep_api_version = CLI_PLUGIN_API_VERSION, - .entry_point = &lfrfid_cli, -}; - -const FlipperAppPluginDescriptor* lfrfid_cli_plugin_ep(void) { - return &plugin_descriptor; -} diff --git a/applications/main/lfrfid/lfrfid_start.c b/applications/main/lfrfid/lfrfid_start.c deleted file mode 100644 index faf275355..000000000 --- a/applications/main/lfrfid/lfrfid_start.c +++ /dev/null @@ -1,11 +0,0 @@ -#include - -static void lfrfid_cli_wrapper(Cli* cli, FuriString* args, void* context) { - cli_plugin_wrapper("lfrfid", cli, args, context); -} - -void lfrfid_on_system_start(void) { - Cli* cli = furi_record_open(RECORD_CLI); - cli_add_command(cli, "rfid", CliCommandFlagDefault, lfrfid_cli_wrapper, NULL); - furi_record_close(RECORD_CLI); -} diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index 639a3fca7..bcc2bcbd4 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -310,15 +310,6 @@ App( sources=["plugins/supported_cards/trt.c"], ) -App( - appid="nfc_cli", - targets=["f7"], - apptype=FlipperAppType.PLUGIN, - entry_point="nfc_cli_plugin_ep", - requires=["cli"], - sources=["nfc_cli.c"], -) - App( appid="disney_infinity_parser", apptype=FlipperAppType.PLUGIN, @@ -334,6 +325,6 @@ App( targets=["f7"], apptype=FlipperAppType.STARTUP, entry_point="nfc_on_system_start", - sources=["nfc_start.c"], + sources=["nfc_cli.c"], order=30, ) diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index ea686834f..276b53e56 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -226,15 +226,12 @@ static void nfc_cli(Cli* cli, FuriString* args, void* context) { furi_string_free(cmd); } -#include -#include - -static const FlipperAppPluginDescriptor plugin_descriptor = { - .appid = CLI_PLUGIN_APP_ID, - .ep_api_version = CLI_PLUGIN_API_VERSION, - .entry_point = &nfc_cli, -}; - -const FlipperAppPluginDescriptor* nfc_cli_plugin_ep(void) { - return &plugin_descriptor; +void nfc_on_system_start(void) { +#ifdef SRV_CLI + Cli* cli = furi_record_open(RECORD_CLI); + cli_add_command(cli, "nfc", CliCommandFlagDefault, nfc_cli, NULL); + furi_record_close(RECORD_CLI); +#else + UNUSED(nfc_cli); +#endif } diff --git a/applications/main/nfc/nfc_start.c b/applications/main/nfc/nfc_start.c deleted file mode 100644 index d38a956c3..000000000 --- a/applications/main/nfc/nfc_start.c +++ /dev/null @@ -1,11 +0,0 @@ -#include - -static void nfc_cli_wrapper(Cli* cli, FuriString* args, void* context) { - cli_plugin_wrapper("nfc", cli, args, context); -} - -void nfc_on_system_start(void) { - Cli* cli = furi_record_open(RECORD_CLI); - cli_add_command(cli, "nfc", CliCommandFlagDefault, nfc_cli_wrapper, NULL); - furi_record_close(RECORD_CLI); -} diff --git a/applications/main/onewire/application.fam b/applications/main/onewire/application.fam index 9fac2ff21..3d35abce9 100644 --- a/applications/main/onewire/application.fam +++ b/applications/main/onewire/application.fam @@ -1,16 +1,6 @@ -App( - appid="onewire_cli", - targets=["f7"], - apptype=FlipperAppType.PLUGIN, - entry_point="onewire_cli_plugin_ep", - requires=["cli"], - sources=["onewire_cli.c"], -) - App( appid="onewire_start", apptype=FlipperAppType.STARTUP, entry_point="onewire_on_system_start", - sources=["onewire_start.c"], order=60, ) diff --git a/applications/main/onewire/onewire_cli.c b/applications/main/onewire/onewire_cli.c index 9114f3cf1..f7e15c295 100644 --- a/applications/main/onewire/onewire_cli.c +++ b/applications/main/onewire/onewire_cli.c @@ -8,10 +8,22 @@ #include +static void onewire_cli(Cli* cli, FuriString* args, void* context); + +void onewire_on_system_start(void) { +#ifdef SRV_CLI + Cli* cli = furi_record_open(RECORD_CLI); + cli_add_command(cli, "onewire", CliCommandFlagDefault, onewire_cli, cli); + furi_record_close(RECORD_CLI); +#else + UNUSED(onewire_cli); +#endif +} + static void onewire_cli_print_usage(void) { printf("Usage:\r\n"); printf("onewire search\r\n"); -} +}; static void onewire_cli_search(Cli* cli) { UNUSED(cli); @@ -63,16 +75,3 @@ void onewire_cli(Cli* cli, FuriString* args, void* context) { furi_string_free(cmd); } - -#include -#include - -static const FlipperAppPluginDescriptor plugin_descriptor = { - .appid = CLI_PLUGIN_APP_ID, - .ep_api_version = CLI_PLUGIN_API_VERSION, - .entry_point = &onewire_cli, -}; - -const FlipperAppPluginDescriptor* onewire_cli_plugin_ep(void) { - return &plugin_descriptor; -} diff --git a/applications/main/onewire/onewire_start.c b/applications/main/onewire/onewire_start.c deleted file mode 100644 index 219335411..000000000 --- a/applications/main/onewire/onewire_start.c +++ /dev/null @@ -1,11 +0,0 @@ -#include - -static void onewire_cli_wrapper(Cli* cli, FuriString* args, void* context) { - cli_plugin_wrapper("onewire", cli, args, context); -} - -void onewire_on_system_start(void) { - Cli* cli = furi_record_open(RECORD_CLI); - cli_add_command(cli, "onewire", CliCommandFlagDefault, onewire_cli_wrapper, cli); - furi_record_close(RECORD_CLI); -} diff --git a/applications/services/cli/cli.c b/applications/services/cli/cli.c index c9d074257..c2a0b9cb1 100644 --- a/applications/services/cli/cli.c +++ b/applications/services/cli/cli.c @@ -4,10 +4,6 @@ #include #include -#include -#include -#include - #define TAG "CliSrv" #define CLI_INPUT_LEN_LIMIT 256 @@ -486,19 +482,3 @@ int32_t cli_srv(void* p) { return 0; } - -void cli_plugin_wrapper(const char* name, Cli* cli, FuriString* args, void* context) { - PluginManager* manager = - plugin_manager_alloc(CLI_PLUGIN_APP_ID, CLI_PLUGIN_API_VERSION, firmware_api_interface); - FuriString* path = - furi_string_alloc_printf(EXT_PATH("apps_data/cli/plugins/%s_cli.fal"), name); - PluginManagerError error = plugin_manager_load_single(manager, furi_string_get_cstr(path)); - if(error == PluginManagerErrorNone) { - const CliCallback handler = plugin_manager_get_ep(manager, 0); - handler(cli, args, context); - } else { - printf("CLI plugin failed (code %" PRIu16 "), update firmware or check logs\r\n", error); - } - furi_string_free(path); - plugin_manager_free(manager); -} diff --git a/applications/services/cli/cli_i.h b/applications/services/cli/cli_i.h index c7ec8cf6e..ca126dacd 100644 --- a/applications/services/cli/cli_i.h +++ b/applications/services/cli/cli_i.h @@ -63,13 +63,6 @@ void cli_putc(Cli* cli, char c); void cli_stdout_callback(void* _cookie, const char* data, size_t size); -// Wraps CLI commands to load from plugin file -// Must call from CLI context, like dummy CLI command callback -// You need to setup the plugin to compile correctly separately -#define CLI_PLUGIN_APP_ID "cli" -#define CLI_PLUGIN_API_VERSION 1 -void cli_plugin_wrapper(const char* name, Cli* cli, FuriString* args, void* context); - #ifdef __cplusplus } #endif From 4f5cba4cd162045e5b70f528d8f9ed80508f3668 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 5 Apr 2025 23:41:23 +0300 Subject: [PATCH 063/125] Revert "Merge remote-tracking branch 'OFW/gsurkov/vcp_break_support' into dev [ci skip]" This reverts commit fc25c9fba02abb640eaed84988f7184fbfb823c6, reversing changes made to 41ae5d8981aa7ffe776b018c7574aa6ba7723e72. --- applications/main/gpio/usb_uart_bridge.c | 15 ++------------- applications/services/cli/cli_vcp.c | 1 - targets/f18/api_symbols.csv | 1 - targets/f7/api_symbols.csv | 1 - targets/f7/furi_hal/furi_hal_serial.c | 10 ---------- targets/f7/furi_hal/furi_hal_serial.h | 6 ------ targets/f7/furi_hal/furi_hal_usb_cdc.c | 13 +++---------- targets/f7/furi_hal/furi_hal_usb_cdc.h | 1 - 8 files changed, 5 insertions(+), 43 deletions(-) diff --git a/applications/main/gpio/usb_uart_bridge.c b/applications/main/gpio/usb_uart_bridge.c index b755a89c2..e6b71cb34 100644 --- a/applications/main/gpio/usb_uart_bridge.c +++ b/applications/main/gpio/usb_uart_bridge.c @@ -35,12 +35,12 @@ typedef enum { WorkerEvtLineCfgSet = (1 << 6), WorkerEvtCtrlLineSet = (1 << 7), - WorkerEvtSendBreak = (1 << 8), + } WorkerEvtFlags; #define WORKER_ALL_RX_EVENTS \ (WorkerEvtStop | WorkerEvtRxDone | WorkerEvtCfgChange | WorkerEvtLineCfgSet | \ - WorkerEvtCtrlLineSet | WorkerEvtCdcTxComplete | WorkerEvtSendBreak) + WorkerEvtCtrlLineSet | WorkerEvtCdcTxComplete) #define WORKER_ALL_TX_EVENTS (WorkerEvtTxStop | WorkerEvtCdcRx) struct UsbUartBridge { @@ -69,7 +69,6 @@ static void vcp_on_cdc_rx(void* context); static void vcp_state_callback(void* context, uint8_t state); static void vcp_on_cdc_control_line(void* context, uint8_t state); static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config); -static void vcp_on_cdc_break(void* context, uint16_t duration); static const CdcCallbacks cdc_cb = { vcp_on_cdc_tx_complete, @@ -77,7 +76,6 @@ static const CdcCallbacks cdc_cb = { vcp_state_callback, vcp_on_cdc_control_line, vcp_on_line_config, - vcp_on_cdc_break, }; /* USB UART worker */ @@ -289,9 +287,6 @@ static int32_t usb_uart_worker(void* context) { if(events & WorkerEvtCtrlLineSet) { usb_uart_update_ctrl_lines(usb_uart); } - if(events & WorkerEvtSendBreak) { - furi_hal_serial_send_break(usb_uart->serial_handle); - } } furi_hal_gpio_init(USB_USART_DE_RE_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow); @@ -383,12 +378,6 @@ static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtLineCfgSet); } -static void vcp_on_cdc_break(void* context, uint16_t duration) { - UNUSED(duration); - UsbUartBridge* usb_uart = (UsbUartBridge*)context; - furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtSendBreak); -} - UsbUartBridge* usb_uart_enable(UsbUartConfig* cfg) { UsbUartBridge* usb_uart = malloc(sizeof(UsbUartBridge)); diff --git a/applications/services/cli/cli_vcp.c b/applications/services/cli/cli_vcp.c index 488455ad6..39802bd79 100644 --- a/applications/services/cli/cli_vcp.c +++ b/applications/services/cli/cli_vcp.c @@ -57,7 +57,6 @@ static CdcCallbacks cdc_cb = { vcp_state_callback, vcp_on_cdc_control_line, NULL, - NULL, }; static CliVcp* vcp = NULL; diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 04a7852e0..6f9c88732 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1460,7 +1460,6 @@ Function,+,furi_hal_serial_get_gpio_pin,const GpioPin*,"FuriHalSerialHandle*, Fu Function,+,furi_hal_serial_init,void,"FuriHalSerialHandle*, uint32_t" Function,+,furi_hal_serial_is_baud_rate_supported,_Bool,"FuriHalSerialHandle*, uint32_t" Function,+,furi_hal_serial_resume,void,FuriHalSerialHandle* -Function,+,furi_hal_serial_send_break,void,FuriHalSerialHandle* Function,+,furi_hal_serial_set_br,void,"FuriHalSerialHandle*, uint32_t" Function,+,furi_hal_serial_suspend,void,FuriHalSerialHandle* Function,+,furi_hal_serial_tx,void,"FuriHalSerialHandle*, const uint8_t*, size_t" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index b497c94b6..3bc8e0947 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1691,7 +1691,6 @@ Function,+,furi_hal_serial_get_gpio_pin,const GpioPin*,"FuriHalSerialHandle*, Fu Function,+,furi_hal_serial_init,void,"FuriHalSerialHandle*, uint32_t" Function,+,furi_hal_serial_is_baud_rate_supported,_Bool,"FuriHalSerialHandle*, uint32_t" Function,+,furi_hal_serial_resume,void,FuriHalSerialHandle* -Function,+,furi_hal_serial_send_break,void,FuriHalSerialHandle* Function,+,furi_hal_serial_set_br,void,"FuriHalSerialHandle*, uint32_t" Function,+,furi_hal_serial_suspend,void,FuriHalSerialHandle* Function,+,furi_hal_serial_tx,void,"FuriHalSerialHandle*, const uint8_t*, size_t" diff --git a/targets/f7/furi_hal/furi_hal_serial.c b/targets/f7/furi_hal/furi_hal_serial.c index b4d47727f..8ad9794a8 100644 --- a/targets/f7/furi_hal/furi_hal_serial.c +++ b/targets/f7/furi_hal/furi_hal_serial.c @@ -1036,13 +1036,3 @@ const GpioPin* return furi_hal_serial_config[handle->id].gpio[direction]; } - -void furi_hal_serial_send_break(FuriHalSerialHandle* handle) { - furi_check(handle); - - if(handle->id == FuriHalSerialIdUsart) { - LL_USART_RequestBreakSending(USART1); - } else { - LL_LPUART_RequestBreakSending(LPUART1); - } -} diff --git a/targets/f7/furi_hal/furi_hal_serial.h b/targets/f7/furi_hal/furi_hal_serial.h index 191cf9f77..ca8860a60 100644 --- a/targets/f7/furi_hal/furi_hal_serial.h +++ b/targets/f7/furi_hal/furi_hal_serial.h @@ -256,12 +256,6 @@ void furi_hal_serial_dma_rx_stop(FuriHalSerialHandle* handle); */ size_t furi_hal_serial_dma_rx(FuriHalSerialHandle* handle, uint8_t* data, size_t len); -/** Send a break sequence (low level for the whole character duration) - * - * @param handle Serial handle - */ -void furi_hal_serial_send_break(FuriHalSerialHandle* handle); - #ifdef __cplusplus } #endif diff --git a/targets/f7/furi_hal/furi_hal_usb_cdc.c b/targets/f7/furi_hal/furi_hal_usb_cdc.c index 055618fe6..f9c1d3a42 100644 --- a/targets/f7/furi_hal/furi_hal_usb_cdc.c +++ b/targets/f7/furi_hal/furi_hal_usb_cdc.c @@ -122,7 +122,7 @@ static const struct CdcConfigDescriptorSingle cdc_cfg_desc_single = { .bFunctionLength = sizeof(struct usb_cdc_acm_desc), .bDescriptorType = USB_DTYPE_CS_INTERFACE, .bDescriptorSubType = USB_DTYPE_CDC_ACM, - .bmCapabilities = USB_CDC_CAP_BRK, + .bmCapabilities = 0, }, .cdc_union = { @@ -235,7 +235,7 @@ static const struct CdcConfigDescriptorDual .bFunctionLength = sizeof(struct usb_cdc_acm_desc), .bDescriptorType = USB_DTYPE_CS_INTERFACE, .bDescriptorSubType = USB_DTYPE_CDC_ACM, - .bmCapabilities = USB_CDC_CAP_BRK, + .bmCapabilities = 0, }, .cdc_union = { @@ -330,7 +330,7 @@ static const struct CdcConfigDescriptorDual .bFunctionLength = sizeof(struct usb_cdc_acm_desc), .bDescriptorType = USB_DTYPE_CS_INTERFACE, .bDescriptorSubType = USB_DTYPE_CDC_ACM, - .bmCapabilities = USB_CDC_CAP_BRK, + .bmCapabilities = 0, }, .cdc_union = { @@ -685,13 +685,6 @@ static usbd_respond cdc_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_cal dev->status.data_ptr = &cdc_config[if_num]; dev->status.data_count = sizeof(cdc_config[0]); return usbd_ack; - case USB_CDC_SEND_BREAK: - if(callbacks[if_num] != NULL) { - if(callbacks[if_num]->break_callback != NULL) { - callbacks[if_num]->break_callback(cb_ctx[if_num], req->wValue); - } - } - return usbd_ack; default: return usbd_fail; } diff --git a/targets/f7/furi_hal/furi_hal_usb_cdc.h b/targets/f7/furi_hal/furi_hal_usb_cdc.h index 995e9009a..89b68991b 100644 --- a/targets/f7/furi_hal/furi_hal_usb_cdc.h +++ b/targets/f7/furi_hal/furi_hal_usb_cdc.h @@ -15,7 +15,6 @@ typedef struct { void (*state_callback)(void* context, uint8_t state); void (*ctrl_line_callback)(void* context, uint8_t state); void (*config_callback)(void* context, struct usb_cdc_line_coding* config); - void (*break_callback)(void* context, uint16_t duration); } CdcCallbacks; void furi_hal_cdc_set_callbacks(uint8_t if_num, CdcCallbacks* cb, void* context); From a57f9e22b5a1f6d9f69b3c5002d2b43a1822d0d1 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 6 Apr 2025 01:57:23 +0300 Subject: [PATCH 064/125] fix nfc --- applications/main/nfc/nfc_cli.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index ba4d800f8..5b54d38db 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -112,8 +112,8 @@ static NfcCommand trx_callback(NfcGenericEvent event, void* context) { return NfcCommandContinue; } -static void nfc_cli_apdu(Cli* cli, FuriString* args) { - UNUSED(cli); +static void nfc_cli_apdu(PipeSide* pipe, FuriString* args) { + UNUSED(pipe); Nfc* nfc = NULL; NfcPoller* poller = NULL; FuriString* data = furi_string_alloc(); @@ -211,7 +211,7 @@ static void execute(PipeSide* pipe, FuriString* args, void* context) { break; } if(furi_string_cmp_str(cmd, "apdu") == 0) { - nfc_cli_apdu(cli, args); + nfc_cli_apdu(pipe, args); break; } if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { From 1385ea0ea019f1cf448feb8684f802ad190f3a01 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 6 Apr 2025 03:00:37 +0300 Subject: [PATCH 065/125] some code cleanup by Willy-JL --- applications/services/bt/bt_service/bt.c | 13 ------ applications/services/bt/bt_service/bt.h | 15 ------- applications/services/bt/bt_service/bt_i.h | 12 +++++ targets/f7/api_symbols.csv | 9 +--- targets/f7/ble_glue/gap.c | 37 +-------------- targets/f7/ble_glue/gap.h | 2 - targets/f7/furi_hal/furi_hal_bt.c | 52 ---------------------- targets/f7/furi_hal/furi_hal_flash.c | 3 +- targets/furi_hal_include/furi_hal_bt.h | 9 ---- 9 files changed, 16 insertions(+), 136 deletions(-) diff --git a/applications/services/bt/bt_service/bt.c b/applications/services/bt/bt_service/bt.c index d04490502..d2e5ce2a0 100644 --- a/applications/services/bt/bt_service/bt.c +++ b/applications/services/bt/bt_service/bt.c @@ -527,19 +527,6 @@ static void bt_init_keys_settings(Bt* bt) { bt_handle_reload_keys_settings(bt); } -bool bt_remote_rssi(Bt* bt, uint8_t* rssi) { - furi_assert(bt); - - uint8_t rssi_val; - uint32_t since = furi_hal_bt_get_conn_rssi(&rssi_val); - - if(since == 0) return false; - - *rssi = rssi_val; - - return true; -} - int32_t bt_srv(void* p) { UNUSED(p); Bt* bt = bt_alloc(); diff --git a/applications/services/bt/bt_service/bt.h b/applications/services/bt/bt_service/bt.h index d49b0b3ba..403f4eb88 100644 --- a/applications/services/bt/bt_service/bt.h +++ b/applications/services/bt/bt_service/bt.h @@ -84,21 +84,6 @@ void bt_keys_storage_set_storage_path(Bt* bt, const char* keys_storage_path); */ void bt_keys_storage_set_default_path(Bt* bt); -bool bt_remote_rssi(Bt* bt, uint8_t* rssi); - -/** - * - * (Probably bad) way of opening the RPC connection, everywhereTM -*/ - -void bt_open_rpc_connection(Bt* bt); - -/** - * - * Closing the RPC connection, everywhereTM -*/ -void bt_close_rpc_connection(Bt* bt); - #ifdef __cplusplus } #endif diff --git a/applications/services/bt/bt_service/bt_i.h b/applications/services/bt/bt_service/bt_i.h index 58a60e275..fa2a0740d 100644 --- a/applications/services/bt/bt_service/bt_i.h +++ b/applications/services/bt/bt_service/bt_i.h @@ -91,3 +91,15 @@ struct Bt { uint32_t pin; bool suppress_pin_screen; }; + +/** Open a new RPC connection + * + * @param bt Bt instance + */ +void bt_open_rpc_connection(Bt* bt); + +/** Close the active RPC connection + * + * @param bt Bt instance + */ +void bt_close_rpc_connection(Bt* bt); diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index a5f56bf41..5cd3c1276 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -782,7 +782,6 @@ Function,+,ble_svc_serial_start,BleServiceSerial*, Function,+,ble_svc_serial_stop,void,BleServiceSerial* Function,+,ble_svc_serial_update_tx,_Bool,"BleServiceSerial*, uint8_t*, uint16_t" Function,-,bsearch,void*,"const void*, const void*, size_t, size_t, __compar_fn_t" -Function,-,bt_close_rpc_connection,void,Bt* Function,+,bt_disconnect,void,Bt* Function,+,bt_forget_bonded_devices,void,Bt* Function,+,bt_keys_storage_alloc,BtKeysStorage*,const char* @@ -795,10 +794,8 @@ Function,+,bt_keys_storage_set_file_path,void,"BtKeysStorage*, const char*" Function,+,bt_keys_storage_set_ram_params,void,"BtKeysStorage*, uint8_t*, uint16_t" Function,+,bt_keys_storage_set_storage_path,void,"Bt*, const char*" Function,+,bt_keys_storage_update,_Bool,"BtKeysStorage*, uint8_t*, uint32_t" -Function,-,bt_open_rpc_connection,void,Bt* Function,+,bt_profile_restore_default,_Bool,Bt* Function,+,bt_profile_start,FuriHalBleProfileBase*,"Bt*, const FuriHalBleProfileTemplate*, FuriHalBleProfileParams" -Function,+,bt_remote_rssi,_Bool,"Bt*, uint8_t*" Function,+,bt_set_status_changed_callback,void,"Bt*, BtStatusChangedCallback, void*" Function,+,buffered_file_stream_alloc,Stream*,Storage* Function,+,buffered_file_stream_close,_Bool,Stream* @@ -1331,7 +1328,6 @@ Function,+,furi_hal_bt_extra_beacon_set_config,_Bool,const GapExtraBeaconConfig* Function,+,furi_hal_bt_extra_beacon_set_data,_Bool,"const uint8_t*, uint8_t" Function,+,furi_hal_bt_extra_beacon_start,_Bool, Function,+,furi_hal_bt_extra_beacon_stop,_Bool, -Function,-,furi_hal_bt_get_conn_rssi,uint32_t,uint8_t* Function,+,furi_hal_bt_get_key_storage_buff,void,"uint8_t**, uint16_t*" Function,+,furi_hal_bt_get_radio_stack,FuriHalBtStack, Function,+,furi_hal_bt_get_rssi,float, @@ -1339,14 +1335,12 @@ Function,+,furi_hal_bt_get_transmitted_packets,uint32_t, Function,-,furi_hal_bt_init,void, Function,+,furi_hal_bt_is_active,_Bool, Function,+,furi_hal_bt_is_alive,_Bool, -Function,+,furi_hal_bt_is_connected,_Bool, Function,+,furi_hal_bt_is_gatt_gap_supported,_Bool, Function,+,furi_hal_bt_is_testing_supported,_Bool, Function,+,furi_hal_bt_lock_core2,void, Function,+,furi_hal_bt_nvm_sram_sem_acquire,void, Function,+,furi_hal_bt_nvm_sram_sem_release,void, Function,+,furi_hal_bt_reinit,void, -Function,+,furi_hal_bt_reverse_mac_addr,void,uint8_t[( 6 )] Function,+,furi_hal_bt_set_key_storage_change_callback,void,"BleGlueKeyStorageChangedCallback, void*" Function,+,furi_hal_bt_start_advertising,void, Function,+,furi_hal_bt_start_app,FuriHalBleProfileBase*,"const FuriHalBleProfileTemplate*, FuriHalBleProfileParams, GapEventCallback, void*" @@ -2008,7 +2002,6 @@ Function,-,gap_extra_beacon_set_config,_Bool,const GapExtraBeaconConfig* Function,-,gap_extra_beacon_set_data,_Bool,"const uint8_t*, uint8_t" Function,-,gap_extra_beacon_start,_Bool, Function,-,gap_extra_beacon_stop,_Bool, -Function,-,gap_get_remote_conn_rssi,uint32_t,int8_t* Function,-,gap_get_state,GapState, Function,-,gap_init,_Bool,"GapConfig*, GapEventCallback, void*" Function,-,gap_start_advertising,void, @@ -3558,9 +3551,9 @@ Function,+,subghz_keystore_get_data,SubGhzKeyArray_t*,SubGhzKeystore* Function,+,subghz_keystore_load,_Bool,"SubGhzKeystore*, const char*" Function,+,subghz_keystore_raw_encrypted_save,_Bool,"const char*, const char*, uint8_t*" Function,+,subghz_keystore_raw_get_data,_Bool,"const char*, size_t, uint8_t*, size_t" +Function,+,subghz_keystore_reset_kl,void,SubGhzKeystore* Function,+,subghz_keystore_save,_Bool,"SubGhzKeystore*, const char*, uint8_t*" Function,+,subghz_protocol_alutech_at_4n_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*" -Function,+,subghz_keystore_reset_kl,void,SubGhzKeystore* Function,+,subghz_protocol_blocks_add_bit,void,"SubGhzBlockDecoder*, uint8_t" Function,+,subghz_protocol_blocks_add_bytes,uint8_t,"const uint8_t[], size_t" Function,+,subghz_protocol_blocks_add_to_128_bit,void,"SubGhzBlockDecoder*, uint8_t, uint64_t*" diff --git a/targets/f7/ble_glue/gap.c b/targets/f7/ble_glue/gap.c index 538f033f4..2f4e661b9 100644 --- a/targets/f7/ble_glue/gap.c +++ b/targets/f7/ble_glue/gap.c @@ -33,8 +33,6 @@ typedef struct { GapConfig* config; GapConnectionParams connection_params; GapState state; - int8_t conn_rssi; - uint32_t time_rssi_sample; FuriMutex* state_mutex; GapEventCallback on_event_cb; void* context; @@ -65,19 +63,6 @@ static Gap* gap = NULL; static void gap_advertise_start(GapState new_state); static int32_t gap_app(void* context); -/** function for updating rssi informations in global Gap object - * -*/ -static inline void fetch_rssi(void) { - uint8_t ret_rssi = 127; - if(hci_read_rssi(gap->service.connection_handle, &ret_rssi) == BLE_STATUS_SUCCESS) { - gap->conn_rssi = (int8_t)ret_rssi; - gap->time_rssi_sample = furi_get_tick(); - return; - } - FURI_LOG_D(TAG, "Failed to read RSSI"); -} - static void gap_verify_connection_parameters(Gap* gap) { furi_check(gap); @@ -182,8 +167,6 @@ BleEventFlowStatus ble_event_app_notification(void* pckt) { FURI_LOG_I(TAG, "Connection parameters event complete"); gap_verify_connection_parameters(gap); - // Save rssi for current connection - fetch_rssi(); break; } @@ -218,8 +201,7 @@ BleEventFlowStatus ble_event_app_notification(void* pckt) { gap->service.connection_handle = event->Connection_Handle; gap_verify_connection_parameters(gap); - // Save rssi for current connection - fetch_rssi(); + if(gap->config->pairing_method != GapPairingNone) { // Start pairing by sending security request aci_gap_slave_security_req(event->Connection_Handle); @@ -303,9 +285,6 @@ BleEventFlowStatus ble_event_app_notification(void* pckt) { pairing_complete->Status); aci_gap_terminate(gap->service.connection_handle, 5); } else { - // Save RSSI - fetch_rssi(); - FURI_LOG_I(TAG, "Pairing complete"); GapEvent event = {.type = GapEventTypeConnected}; gap->on_event_cb(event, gap->context); //-V595 @@ -579,9 +558,6 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) { gap->service.connection_handle = 0xFFFF; gap->enable_adv = true; - gap->conn_rssi = 127; - gap->time_rssi_sample = 0; - // Command queue allocation gap->command_queue = furi_message_queue_alloc(8, sizeof(GapCommand)); @@ -621,17 +597,6 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) { return true; } -// Get RSSI -uint32_t gap_get_remote_conn_rssi(int8_t* rssi) { - if(gap && gap->state == GapStateConnected) { - fetch_rssi(); - *rssi = gap->conn_rssi; - - if(gap->time_rssi_sample) return furi_get_tick() - gap->time_rssi_sample; - } - return 0; -} - GapState gap_get_state(void) { GapState state; if(gap) { diff --git a/targets/f7/ble_glue/gap.h b/targets/f7/ble_glue/gap.h index 096dcb46a..2f0b097e4 100644 --- a/targets/f7/ble_glue/gap.h +++ b/targets/f7/ble_glue/gap.h @@ -96,8 +96,6 @@ void gap_thread_stop(void); void gap_emit_ble_beacon_status_event(bool active); -uint32_t gap_get_remote_conn_rssi(int8_t* rssi); - #ifdef __cplusplus } #endif diff --git a/targets/f7/furi_hal/furi_hal_bt.c b/targets/f7/furi_hal/furi_hal_bt.c index 05a066630..2d4984746 100644 --- a/targets/f7/furi_hal/furi_hal_bt.c +++ b/targets/f7/furi_hal/furi_hal_bt.c @@ -251,10 +251,6 @@ bool furi_hal_bt_is_active(void) { return gap_get_state() > GapStateIdle; } -bool furi_hal_bt_is_connected() { - return gap_get_state() == GapStateConnected; -} - void furi_hal_bt_start_advertising(void) { if(gap_get_state() == GapStateIdle) { gap_start_advertising(); @@ -367,54 +363,6 @@ void furi_hal_bt_start_rx(uint8_t channel) { aci_hal_rx_start(channel); } -float furi_hal_bt_get_rssi(void) { - float val; - uint8_t rssi_raw[3]; - - if(aci_hal_read_raw_rssi(rssi_raw) != BLE_STATUS_SUCCESS) { - return 0.0f; - } - - // Some ST magic with rssi - uint8_t agc = rssi_raw[2] & 0xFF; - int rssi = (((int)rssi_raw[1] << 8) & 0xFF00) + (rssi_raw[0] & 0xFF); - if(rssi == 0 || agc > 11) { - val = -127.0; - } else { - val = agc * 6.0f - 127.0f; - while(rssi > 30) { - val += 6.0; - rssi >>= 1; - } - val += (float)((417 * rssi + 18080) >> 10); - } - return val; -} - -/** fill the RSSI of the remote host of the bt connection and returns the last - * time the RSSI was updated - * -*/ -uint32_t furi_hal_bt_get_conn_rssi(uint8_t* rssi) { - int8_t ret_rssi = 0; - uint32_t since = gap_get_remote_conn_rssi(&ret_rssi); - - if(ret_rssi == 127 || since == 0) return 0; - - *rssi = (uint8_t)abs(ret_rssi); - - return since; -} - -void furi_hal_bt_reverse_mac_addr(uint8_t mac_addr[GAP_MAC_ADDR_SIZE]) { - uint8_t tmp; - for(size_t i = 0; i < GAP_MAC_ADDR_SIZE / 2; i++) { - tmp = mac_addr[i]; - mac_addr[i] = mac_addr[GAP_MAC_ADDR_SIZE - 1 - i]; - mac_addr[GAP_MAC_ADDR_SIZE - 1 - i] = tmp; - } -} - uint32_t furi_hal_bt_get_transmitted_packets(void) { uint32_t packets = 0; aci_hal_le_tx_test_packet_number(&packets); diff --git a/targets/f7/furi_hal/furi_hal_flash.c b/targets/f7/furi_hal/furi_hal_flash.c index 28aa45173..c28f6b520 100644 --- a/targets/f7/furi_hal/furi_hal_flash.c +++ b/targets/f7/furi_hal/furi_hal_flash.c @@ -51,7 +51,8 @@ // Changing furi_assert() to furi_check() brought timeout crashes // Internal storage is very slow, and "big" files will often cause a "timeout" with 3 seconds // 10 seconds seems fine, the file operations complete successfully, albeit slowly -#define FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS (10000U) /* 10 seconds */ +//#define FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS (10000U) /* 10 seconds */ +#define FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS (3000U) /* 3 seconds */ #define IS_ADDR_ALIGNED_64BITS(__VALUE__) (((__VALUE__) & 0x7U) == (0x00UL)) #define IS_FLASH_PROGRAM_ADDRESS(__VALUE__) \ diff --git a/targets/furi_hal_include/furi_hal_bt.h b/targets/furi_hal_include/furi_hal_bt.h index 14c2975ac..6da723311 100644 --- a/targets/furi_hal_include/furi_hal_bt.h +++ b/targets/furi_hal_include/furi_hal_bt.h @@ -231,15 +231,6 @@ float furi_hal_bt_get_rssi(void); */ uint32_t furi_hal_bt_get_transmitted_packets(void); -/** Reverse a MAC address byte order in-place - * @param[in] mac mac address to reverse -*/ -void furi_hal_bt_reverse_mac_addr(uint8_t mac_addr[GAP_MAC_ADDR_SIZE]); - -uint32_t furi_hal_bt_get_conn_rssi(uint8_t* rssi); - -bool furi_hal_bt_is_connected(void); - /** Check & switch C2 to given mode * * @param[in] mode mode to switch into From 324b8ddb95992c3296b1f59b10a7853e27fef7d6 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 6 Apr 2025 04:44:09 +0300 Subject: [PATCH 066/125] oops --- targets/f7/furi_hal/furi_hal_bt.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/targets/f7/furi_hal/furi_hal_bt.c b/targets/f7/furi_hal/furi_hal_bt.c index 2d4984746..2c1a9367b 100644 --- a/targets/f7/furi_hal/furi_hal_bt.c +++ b/targets/f7/furi_hal/furi_hal_bt.c @@ -363,6 +363,30 @@ void furi_hal_bt_start_rx(uint8_t channel) { aci_hal_rx_start(channel); } +float furi_hal_bt_get_rssi(void) { + float val; + uint8_t rssi_raw[3]; + + if(aci_hal_read_raw_rssi(rssi_raw) != BLE_STATUS_SUCCESS) { + return 0.0f; + } + + // Some ST magic with rssi + uint8_t agc = rssi_raw[2] & 0xFF; + int rssi = (((int)rssi_raw[1] << 8) & 0xFF00) + (rssi_raw[0] & 0xFF); + if(rssi == 0 || agc > 11) { + val = -127.0; + } else { + val = agc * 6.0f - 127.0f; + while(rssi > 30) { + val += 6.0; + rssi >>= 1; + } + val += (float)((417 * rssi + 18080) >> 10); + } + return val; +} + uint32_t furi_hal_bt_get_transmitted_packets(void) { uint32_t packets = 0; aci_hal_le_tx_test_packet_number(&packets); From 3745ae22418b1a6b3860ff1c2c75454479a336a8 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 6 Apr 2025 04:56:08 +0300 Subject: [PATCH 067/125] merge ofw pr 4136 [ci skip] BadUSB: Full USB/BLE parameter customization, UI improvements, and more by Willy-JL --- applications/main/bad_usb/application.fam | 2 +- applications/main/bad_usb/bad_usb_app.c | 160 +++++-- applications/main/bad_usb/bad_usb_app_i.h | 13 + .../main/bad_usb/helpers/bad_usb_hid.c | 56 ++- .../main/bad_usb/helpers/bad_usb_hid.h | 11 +- .../main/bad_usb/helpers/ble_hid_profile.c | 429 ++++++++++++++++++ .../main/bad_usb/helpers/ble_hid_profile.h | 109 +++++ .../main/bad_usb/helpers/ble_hid_service.c | 325 +++++++++++++ .../main/bad_usb/helpers/ble_hid_service.h | 31 ++ .../main/bad_usb/helpers/ducky_script.c | 174 ++++--- .../main/bad_usb/helpers/ducky_script.h | 7 +- .../bad_usb/helpers/ducky_script_commands.c | 2 + .../main/bad_usb/helpers/ducky_script_i.h | 6 +- .../bad_usb/helpers/ducky_script_keycodes.c | 28 +- .../badusb/assets/layouts/de-DE-mac.kl | Bin 0 -> 256 bytes .../bad_usb/scenes/bad_usb_scene_config.c | 219 ++++++++- .../bad_usb/scenes/bad_usb_scene_config.h | 6 +- .../scenes/bad_usb_scene_config_ble_mac.c | 73 +++ .../scenes/bad_usb_scene_config_ble_name.c | 62 +++ .../scenes/bad_usb_scene_config_layout.c | 10 +- .../scenes/bad_usb_scene_config_usb_name.c | 86 ++++ .../scenes/bad_usb_scene_config_usb_vidpid.c | 59 +++ .../scenes/bad_usb_scene_confirm_unpair.c | 3 +- ...ene_unpair_done.c => bad_usb_scene_done.c} | 12 +- .../scenes/bad_usb_scene_file_select.c | 4 +- .../main/bad_usb/scenes/bad_usb_scene_work.c | 25 +- .../main/bad_usb/views/bad_usb_view.c | 78 ++-- lib/ble_profile/extra_profiles/hid_profile.c | 33 +- targets/f7/furi_hal/furi_hal_usb_hid.c | 3 - targets/furi_hal_include/furi_hal_usb_hid.h | 10 +- targets/furi_hal_include/furi_hal_version.h | 11 +- 31 files changed, 1841 insertions(+), 206 deletions(-) create mode 100644 applications/main/bad_usb/helpers/ble_hid_profile.c create mode 100644 applications/main/bad_usb/helpers/ble_hid_profile.h create mode 100644 applications/main/bad_usb/helpers/ble_hid_service.c create mode 100644 applications/main/bad_usb/helpers/ble_hid_service.h create mode 100755 applications/main/bad_usb/resources/badusb/assets/layouts/de-DE-mac.kl create mode 100644 applications/main/bad_usb/scenes/bad_usb_scene_config_ble_mac.c create mode 100644 applications/main/bad_usb/scenes/bad_usb_scene_config_ble_name.c create mode 100644 applications/main/bad_usb/scenes/bad_usb_scene_config_usb_name.c create mode 100644 applications/main/bad_usb/scenes/bad_usb_scene_config_usb_vidpid.c rename applications/main/bad_usb/scenes/{bad_usb_scene_unpair_done.c => bad_usb_scene_done.c} (67%) diff --git a/applications/main/bad_usb/application.fam b/applications/main/bad_usb/application.fam index 8d3909fcc..9844e248d 100644 --- a/applications/main/bad_usb/application.fam +++ b/applications/main/bad_usb/application.fam @@ -7,7 +7,7 @@ App( icon="A_BadUsb_14", order=70, resources="resources", - fap_libs=["assets", "ble_profile"], + fap_libs=["assets"], fap_icon="icon.png", fap_category="USB", ) diff --git a/applications/main/bad_usb/bad_usb_app.c b/applications/main/bad_usb/bad_usb_app.c index eda702cf4..96ccb14ed 100644 --- a/applications/main/bad_usb/bad_usb_app.c +++ b/applications/main/bad_usb/bad_usb_app.c @@ -31,52 +31,123 @@ static void bad_usb_app_tick_event_callback(void* context) { static void bad_usb_load_settings(BadUsbApp* app) { Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff = flipper_format_file_alloc(storage); - bool state = false; + bool loaded = false; + BadUsbHidConfig* hid_cfg = &app->user_hid_cfg; FuriString* temp_str = furi_string_alloc(); - uint32_t version = 0; - uint32_t interface = 0; + uint32_t temp_uint = 0; if(flipper_format_file_open_existing(fff, BAD_USB_SETTINGS_PATH)) { do { - if(!flipper_format_read_header(fff, temp_str, &version)) break; + if(!flipper_format_read_header(fff, temp_str, &temp_uint)) break; if((strcmp(furi_string_get_cstr(temp_str), BAD_USB_SETTINGS_FILE_TYPE) != 0) || - (version != BAD_USB_SETTINGS_VERSION)) + (temp_uint != BAD_USB_SETTINGS_VERSION)) break; - if(!flipper_format_read_string(fff, "layout", temp_str)) break; - if(!flipper_format_read_uint32(fff, "interface", &interface, 1)) break; - if(interface > BadUsbHidInterfaceBle) break; + if(flipper_format_read_string(fff, "layout", temp_str)) { + furi_string_set(app->keyboard_layout, temp_str); + FileInfo layout_file_info; + FS_Error file_check_err = storage_common_stat( + storage, furi_string_get_cstr(app->keyboard_layout), &layout_file_info); + if((file_check_err != FSE_OK) || (layout_file_info.size != 256)) { + furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT); + } + } else { + furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT); + flipper_format_rewind(fff); + } - state = true; + if(!flipper_format_read_uint32(fff, "interface", &temp_uint, 1) || + temp_uint >= BadUsbHidInterfaceMAX) { + temp_uint = BadUsbHidInterfaceUsb; + flipper_format_rewind(fff); + } + app->interface = temp_uint; + + if(!flipper_format_read_bool(fff, "ble_bonding", &hid_cfg->ble.bonding, 1)) { + hid_cfg->ble.bonding = true; + flipper_format_rewind(fff); + } + + if(!flipper_format_read_uint32(fff, "ble_pairing", &temp_uint, 1) || + temp_uint >= GapPairingCount) { + temp_uint = GapPairingPinCodeVerifyYesNo; + flipper_format_rewind(fff); + } + hid_cfg->ble.pairing = temp_uint; + + if(flipper_format_read_string(fff, "ble_name", temp_str)) { + strlcpy( + hid_cfg->ble.name, furi_string_get_cstr(temp_str), sizeof(hid_cfg->ble.name)); + } else { + hid_cfg->ble.name[0] = '\0'; + flipper_format_rewind(fff); + } + + if(!flipper_format_read_hex( + fff, "ble_mac", hid_cfg->ble.mac, sizeof(hid_cfg->ble.mac))) { + memset(hid_cfg->ble.mac, 0, sizeof(hid_cfg->ble.mac)); + flipper_format_rewind(fff); + } + + if(flipper_format_read_string(fff, "usb_manuf", temp_str)) { + strlcpy( + hid_cfg->usb.manuf, + furi_string_get_cstr(temp_str), + sizeof(hid_cfg->usb.manuf)); + } else { + hid_cfg->usb.manuf[0] = '\0'; + flipper_format_rewind(fff); + } + + if(flipper_format_read_string(fff, "usb_product", temp_str)) { + strlcpy( + hid_cfg->usb.product, + furi_string_get_cstr(temp_str), + sizeof(hid_cfg->usb.product)); + } else { + hid_cfg->usb.product[0] = '\0'; + flipper_format_rewind(fff); + } + + if(!flipper_format_read_uint32(fff, "usb_vid", &hid_cfg->usb.vid, 1)) { + hid_cfg->usb.vid = 0; + flipper_format_rewind(fff); + } + + if(!flipper_format_read_uint32(fff, "usb_pid", &hid_cfg->usb.pid, 1)) { + hid_cfg->usb.pid = 0; + flipper_format_rewind(fff); + } + + loaded = true; } while(0); } - flipper_format_free(fff); - furi_record_close(RECORD_STORAGE); - - if(state) { - furi_string_set(app->keyboard_layout, temp_str); - app->interface = interface; - - Storage* fs_api = furi_record_open(RECORD_STORAGE); - FileInfo layout_file_info; - FS_Error file_check_err = storage_common_stat( - fs_api, furi_string_get_cstr(app->keyboard_layout), &layout_file_info); - furi_record_close(RECORD_STORAGE); - if((file_check_err != FSE_OK) || (layout_file_info.size != 256)) { - furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT); - } - } else { - furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT); - app->interface = BadUsbHidInterfaceUsb; - } furi_string_free(temp_str); + + flipper_format_free(fff); + furi_record_close(RECORD_STORAGE); + + if(!loaded) { + furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT); + app->interface = BadUsbHidInterfaceUsb; + hid_cfg->ble.name[0] = '\0'; + memset(hid_cfg->ble.mac, 0, sizeof(hid_cfg->ble.mac)); + hid_cfg->ble.bonding = true; + hid_cfg->ble.pairing = GapPairingPinCodeVerifyYesNo; + hid_cfg->usb.vid = 0; + hid_cfg->usb.pid = 0; + hid_cfg->usb.manuf[0] = '\0'; + hid_cfg->usb.product[0] = '\0'; + } } static void bad_usb_save_settings(BadUsbApp* app) { Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff = flipper_format_file_alloc(storage); + BadUsbHidConfig* hid_cfg = &app->user_hid_cfg; + uint32_t temp_uint = 0; if(flipper_format_file_open_always(fff, BAD_USB_SETTINGS_PATH)) { do { @@ -84,9 +155,19 @@ static void bad_usb_save_settings(BadUsbApp* app) { fff, BAD_USB_SETTINGS_FILE_TYPE, BAD_USB_SETTINGS_VERSION)) break; if(!flipper_format_write_string(fff, "layout", app->keyboard_layout)) break; - uint32_t interface_id = app->interface; - if(!flipper_format_write_uint32(fff, "interface", (const uint32_t*)&interface_id, 1)) + temp_uint = app->interface; + if(!flipper_format_write_uint32(fff, "interface", &temp_uint, 1)) break; + if(!flipper_format_write_bool(fff, "ble_bonding", &hid_cfg->ble.bonding, 1)) break; + temp_uint = hid_cfg->ble.pairing; + if(!flipper_format_write_uint32(fff, "ble_pairing", &temp_uint, 1)) break; + if(!flipper_format_write_string_cstr(fff, "ble_name", hid_cfg->ble.name)) break; + if(!flipper_format_write_hex( + fff, "ble_mac", (uint8_t*)&hid_cfg->ble.mac, sizeof(hid_cfg->ble.mac))) break; + if(!flipper_format_write_string_cstr(fff, "usb_manuf", hid_cfg->usb.manuf)) break; + if(!flipper_format_write_string_cstr(fff, "usb_product", hid_cfg->usb.product)) break; + if(!flipper_format_write_uint32(fff, "usb_vid", &hid_cfg->usb.vid, 1)) break; + if(!flipper_format_write_uint32(fff, "usb_pid", &hid_cfg->usb.pid, 1)) break; } while(0); } @@ -121,7 +202,7 @@ BadUsbApp* bad_usb_app_alloc(char* arg) { view_dispatcher_set_event_callback_context(app->view_dispatcher, app); view_dispatcher_set_tick_event_callback( - app->view_dispatcher, bad_usb_app_tick_event_callback, 500); + app->view_dispatcher, bad_usb_app_tick_event_callback, 250); view_dispatcher_set_custom_event_callback( app->view_dispatcher, bad_usb_app_custom_event_callback); view_dispatcher_set_navigation_event_callback( @@ -146,6 +227,14 @@ BadUsbApp* bad_usb_app_alloc(char* arg) { view_dispatcher_add_view( app->view_dispatcher, BadUsbAppViewWork, bad_usb_view_get_view(app->bad_usb_view)); + app->text_input = text_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, BadUsbAppViewTextInput, text_input_get_view(app->text_input)); + + app->byte_input = byte_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, BadUsbAppViewByteInput, byte_input_get_view(app->byte_input)); + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); if(furi_hal_usb_is_locked()) { @@ -157,6 +246,7 @@ BadUsbApp* bad_usb_app_alloc(char* arg) { furi_check(furi_hal_usb_set_config(NULL, NULL)); if(!furi_string_empty(app->file_path)) { + scene_manager_set_scene_state(app->scene_manager, BadUsbSceneWork, true); scene_manager_next_scene(app->scene_manager, BadUsbSceneWork); } else { furi_string_set(app->file_path, BAD_USB_APP_BASE_FOLDER); @@ -191,6 +281,14 @@ void bad_usb_app_free(BadUsbApp* app) { view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewConfig); variable_item_list_free(app->var_item_list); + // Text Input + view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewTextInput); + text_input_free(app->text_input); + + // Byte Input + view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewByteInput); + byte_input_free(app->byte_input); + // View dispatcher view_dispatcher_free(app->view_dispatcher); scene_manager_free(app->scene_manager); diff --git a/applications/main/bad_usb/bad_usb_app_i.h b/applications/main/bad_usb/bad_usb_app_i.h index b34bd5de6..06a798706 100644 --- a/applications/main/bad_usb/bad_usb_app_i.h +++ b/applications/main/bad_usb/bad_usb_app_i.h @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include #include "views/bad_usb_view.h" @@ -36,6 +38,13 @@ struct BadUsbApp { Widget* widget; Popup* popup; VariableItemList* var_item_list; + TextInput* text_input; + ByteInput* byte_input; + + char ble_name_buf[FURI_HAL_BT_ADV_NAME_LENGTH]; + uint8_t ble_mac_buf[GAP_MAC_ADDR_SIZE]; + char usb_name_buf[HID_MANUF_PRODUCT_NAME_LEN]; + uint16_t usb_vidpid_buf[2]; BadUsbAppError error; FuriString* file_path; @@ -44,6 +53,8 @@ struct BadUsbApp { BadUsbScript* bad_usb_script; BadUsbHidInterface interface; + BadUsbHidConfig user_hid_cfg; + BadUsbHidConfig script_hid_cfg; FuriHalUsbInterface* usb_if_prev; }; @@ -52,6 +63,8 @@ typedef enum { BadUsbAppViewPopup, BadUsbAppViewWork, BadUsbAppViewConfig, + BadUsbAppViewByteInput, + BadUsbAppViewTextInput, } BadUsbAppView; void bad_usb_set_interface(BadUsbApp* app, BadUsbHidInterface interface); diff --git a/applications/main/bad_usb/helpers/bad_usb_hid.c b/applications/main/bad_usb/helpers/bad_usb_hid.c index c6226cf37..5ae4146e8 100644 --- a/applications/main/bad_usb/helpers/bad_usb_hid.c +++ b/applications/main/bad_usb/helpers/bad_usb_hid.c @@ -1,5 +1,5 @@ #include "bad_usb_hid.h" -#include +#include "ble_hid_profile.h" #include #include @@ -7,8 +7,14 @@ #define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys" -void* hid_usb_init(FuriHalUsbHidConfig* hid_cfg) { - furi_check(furi_hal_usb_set_config(&usb_hid, hid_cfg)); +void hid_usb_adjust_config(BadUsbHidConfig* hid_cfg) { + if(hid_cfg->usb.vid == 0) hid_cfg->usb.vid = HID_VID_DEFAULT; + if(hid_cfg->usb.pid == 0) hid_cfg->usb.pid = HID_PID_DEFAULT; +} + +void* hid_usb_init(BadUsbHidConfig* hid_cfg) { + hid_usb_adjust_config(hid_cfg); + furi_check(furi_hal_usb_set_config(&usb_hid, &hid_cfg->usb)); return NULL; } @@ -86,6 +92,7 @@ uint8_t hid_usb_get_led_state(void* inst) { } static const BadUsbHidApi hid_api_usb = { + .adjust_config = hid_usb_adjust_config, .init = hid_usb_init, .deinit = hid_usb_deinit, .set_state_callback = hid_usb_set_state_callback, @@ -111,11 +118,6 @@ typedef struct { bool is_connected; } BleHidInstance; -static const BleProfileHidParams ble_hid_params = { - .device_name_prefix = "BadUSB", - .mac_xor = 0x0002, -}; - static void hid_ble_connection_status_callback(BtStatus status, void* context) { furi_assert(context); BleHidInstance* ble_hid = context; @@ -125,8 +127,38 @@ static void hid_ble_connection_status_callback(BtStatus status, void* context) { } } -void* hid_ble_init(FuriHalUsbHidConfig* hid_cfg) { - UNUSED(hid_cfg); +void hid_ble_adjust_config(BadUsbHidConfig* hid_cfg) { + const uint8_t* normal_mac = furi_hal_version_get_ble_mac(); + uint8_t empty_mac[GAP_MAC_ADDR_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t default_mac[GAP_MAC_ADDR_SIZE] = {0x6c, 0x7a, 0xd8, 0xac, 0x57, 0x72}; // furi_hal_bt + if(memcmp(hid_cfg->ble.mac, empty_mac, sizeof(hid_cfg->ble.mac)) == 0 || + memcmp(hid_cfg->ble.mac, normal_mac, sizeof(hid_cfg->ble.mac)) == 0 || + memcmp(hid_cfg->ble.mac, default_mac, sizeof(hid_cfg->ble.mac)) == 0) { + // Derive badusb MAC from Flipper MAC + memcpy(hid_cfg->ble.mac, normal_mac, sizeof(hid_cfg->ble.mac)); + hid_cfg->ble.mac[2]++; + uint16_t badusb_mac_xor = 0x0002; + hid_cfg->ble.mac[0] ^= badusb_mac_xor; + hid_cfg->ble.mac[1] ^= badusb_mac_xor >> 8; + } + + if(hid_cfg->ble.name[0] == '\0') { + // Derive badusb name from Flipper name + const char* badusb_device_name_prefix = "BadUSB"; + snprintf( + hid_cfg->ble.name, + sizeof(hid_cfg->ble.name), + "%s %s", + badusb_device_name_prefix, + furi_hal_version_get_name_ptr()); + } + + if(hid_cfg->ble.pairing >= GapPairingCount) { + hid_cfg->ble.pairing = GapPairingPinCodeVerifyYesNo; + } +} + +void* hid_ble_init(BadUsbHidConfig* hid_cfg) { BleHidInstance* ble_hid = malloc(sizeof(BleHidInstance)); ble_hid->bt = furi_record_open(RECORD_BT); bt_disconnect(ble_hid->bt); @@ -136,7 +168,8 @@ void* hid_ble_init(FuriHalUsbHidConfig* hid_cfg) { bt_keys_storage_set_storage_path(ble_hid->bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME)); - ble_hid->profile = bt_profile_start(ble_hid->bt, ble_profile_hid, (void*)&ble_hid_params); + hid_ble_adjust_config(hid_cfg); + ble_hid->profile = bt_profile_start(ble_hid->bt, ble_profile_hid, &hid_cfg->ble); furi_check(ble_hid->profile); furi_hal_bt_start_advertising(); @@ -236,6 +269,7 @@ uint8_t hid_ble_get_led_state(void* inst) { } static const BadUsbHidApi hid_api_ble = { + .adjust_config = hid_ble_adjust_config, .init = hid_ble_init, .deinit = hid_ble_deinit, .set_state_callback = hid_ble_set_state_callback, diff --git a/applications/main/bad_usb/helpers/bad_usb_hid.h b/applications/main/bad_usb/helpers/bad_usb_hid.h index e4758ab68..8749bdc3b 100644 --- a/applications/main/bad_usb/helpers/bad_usb_hid.h +++ b/applications/main/bad_usb/helpers/bad_usb_hid.h @@ -7,13 +7,22 @@ extern "C" { #include #include +#include "ble_hid_profile.h" + typedef enum { BadUsbHidInterfaceUsb, BadUsbHidInterfaceBle, + BadUsbHidInterfaceMAX, } BadUsbHidInterface; typedef struct { - void* (*init)(FuriHalUsbHidConfig* hid_cfg); + BleProfileHidParams ble; + FuriHalUsbHidConfig usb; +} BadUsbHidConfig; + +typedef struct { + void (*adjust_config)(BadUsbHidConfig* hid_cfg); + void* (*init)(BadUsbHidConfig* hid_cfg); void (*deinit)(void* inst); void (*set_state_callback)(void* inst, HidStateCallback cb, void* context); bool (*is_connected)(void* inst); diff --git a/applications/main/bad_usb/helpers/ble_hid_profile.c b/applications/main/bad_usb/helpers/ble_hid_profile.c new file mode 100644 index 000000000..a4f32159e --- /dev/null +++ b/applications/main/bad_usb/helpers/ble_hid_profile.c @@ -0,0 +1,429 @@ +#include "ble_hid_profile.h" + +// Based on + +#include +#include +#include +#include "ble_hid_service.h" + +#include +#include +#include + +#define HID_INFO_BASE_USB_SPECIFICATION (0x0101) +#define HID_INFO_COUNTRY_CODE (0x00) +#define BLE_PROFILE_HID_INFO_FLAG_REMOTE_WAKE_MSK (0x01) +#define BLE_PROFILE_HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK (0x02) + +#define BLE_PROFILE_HID_KB_MAX_KEYS (6) +#define BLE_PROFILE_CONSUMER_MAX_KEYS (1) + +// Report ids cant be 0 +enum HidReportId { + ReportIdKeyboard = 1, + ReportIdMouse = 2, + ReportIdConsumer = 3, +}; +// Report numbers corresponded to the report id with an offset of 1 +enum HidInputNumber { + ReportNumberKeyboard = 0, + ReportNumberMouse = 1, + ReportNumberConsumer = 2, +}; + +typedef struct { + uint8_t mods; + uint8_t reserved; + uint8_t key[BLE_PROFILE_HID_KB_MAX_KEYS]; +} FURI_PACKED FuriHalBtHidKbReport; + +typedef struct { + uint8_t btn; + int8_t x; + int8_t y; + int8_t wheel; +} FURI_PACKED FuriHalBtHidMouseReport; + +typedef struct { + uint16_t key[BLE_PROFILE_CONSUMER_MAX_KEYS]; +} FURI_PACKED FuriHalBtHidConsumerReport; + +// keyboard+mouse+consumer hid report +static const uint8_t ble_profile_hid_report_map_data[] = { + // Keyboard Report + HID_USAGE_PAGE(HID_PAGE_DESKTOP), + HID_USAGE(HID_DESKTOP_KEYBOARD), + HID_COLLECTION(HID_APPLICATION_COLLECTION), + HID_REPORT_ID(ReportIdKeyboard), + HID_USAGE_PAGE(HID_DESKTOP_KEYPAD), + HID_USAGE_MINIMUM(HID_KEYBOARD_L_CTRL), + HID_USAGE_MAXIMUM(HID_KEYBOARD_R_GUI), + HID_LOGICAL_MINIMUM(0), + HID_LOGICAL_MAXIMUM(1), + HID_REPORT_SIZE(1), + HID_REPORT_COUNT(8), + HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_REPORT_COUNT(1), + HID_REPORT_SIZE(8), + HID_INPUT(HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_USAGE_PAGE(HID_PAGE_LED), + HID_REPORT_COUNT(8), + HID_REPORT_SIZE(1), + HID_USAGE_MINIMUM(1), + HID_USAGE_MAXIMUM(8), + HID_OUTPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_REPORT_COUNT(BLE_PROFILE_HID_KB_MAX_KEYS), + HID_REPORT_SIZE(8), + HID_LOGICAL_MINIMUM(0), + HID_LOGICAL_MAXIMUM(101), + HID_USAGE_PAGE(HID_DESKTOP_KEYPAD), + HID_USAGE_MINIMUM(0), + HID_USAGE_MAXIMUM(101), + HID_INPUT(HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE), + HID_END_COLLECTION, + // Mouse Report + HID_USAGE_PAGE(HID_PAGE_DESKTOP), + HID_USAGE(HID_DESKTOP_MOUSE), + HID_COLLECTION(HID_APPLICATION_COLLECTION), + HID_USAGE(HID_DESKTOP_POINTER), + HID_COLLECTION(HID_PHYSICAL_COLLECTION), + HID_REPORT_ID(ReportIdMouse), + HID_USAGE_PAGE(HID_PAGE_BUTTON), + HID_USAGE_MINIMUM(1), + HID_USAGE_MAXIMUM(3), + HID_LOGICAL_MINIMUM(0), + HID_LOGICAL_MAXIMUM(1), + HID_REPORT_COUNT(3), + HID_REPORT_SIZE(1), + HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_REPORT_SIZE(1), + HID_REPORT_COUNT(5), + HID_INPUT(HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_USAGE_PAGE(HID_PAGE_DESKTOP), + HID_USAGE(HID_DESKTOP_X), + HID_USAGE(HID_DESKTOP_Y), + HID_USAGE(HID_DESKTOP_WHEEL), + HID_LOGICAL_MINIMUM(-127), + HID_LOGICAL_MAXIMUM(127), + HID_REPORT_SIZE(8), + HID_REPORT_COUNT(3), + HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE), + HID_END_COLLECTION, + HID_END_COLLECTION, + // Consumer Report + HID_USAGE_PAGE(HID_PAGE_CONSUMER), + HID_USAGE(HID_CONSUMER_CONTROL), + HID_COLLECTION(HID_APPLICATION_COLLECTION), + HID_REPORT_ID(ReportIdConsumer), + HID_LOGICAL_MINIMUM(0), + HID_RI_LOGICAL_MAXIMUM(16, 0x3FF), + HID_USAGE_MINIMUM(0), + HID_RI_USAGE_MAXIMUM(16, 0x3FF), + HID_REPORT_COUNT(BLE_PROFILE_CONSUMER_MAX_KEYS), + HID_REPORT_SIZE(16), + HID_INPUT(HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE), + HID_END_COLLECTION, +}; + +typedef struct { + FuriHalBleProfileBase base; + + FuriHalBtHidKbReport* kb_report; + FuriHalBtHidMouseReport* mouse_report; + FuriHalBtHidConsumerReport* consumer_report; + + BleServiceBattery* battery_svc; + BleServiceDevInfo* dev_info_svc; + BleServiceHid* hid_svc; +} BleProfileHid; +_Static_assert(offsetof(BleProfileHid, base) == 0, "Wrong layout"); + +static FuriHalBleProfileBase* ble_profile_hid_start(FuriHalBleProfileParams profile_params) { + UNUSED(profile_params); + + BleProfileHid* profile = malloc(sizeof(BleProfileHid)); + + profile->base.config = ble_profile_hid; + + profile->battery_svc = ble_svc_battery_start(true); + profile->dev_info_svc = ble_svc_dev_info_start(); + profile->hid_svc = ble_svc_hid_start(); + + // Configure HID Keyboard + profile->kb_report = malloc(sizeof(FuriHalBtHidKbReport)); + profile->mouse_report = malloc(sizeof(FuriHalBtHidMouseReport)); + profile->consumer_report = malloc(sizeof(FuriHalBtHidConsumerReport)); + + // Configure Report Map characteristic + ble_svc_hid_update_report_map( + profile->hid_svc, + ble_profile_hid_report_map_data, + sizeof(ble_profile_hid_report_map_data)); + // Configure HID Information characteristic + uint8_t hid_info_val[4] = { + HID_INFO_BASE_USB_SPECIFICATION & 0x00ff, + (HID_INFO_BASE_USB_SPECIFICATION & 0xff00) >> 8, + HID_INFO_COUNTRY_CODE, + BLE_PROFILE_HID_INFO_FLAG_REMOTE_WAKE_MSK | + BLE_PROFILE_HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK, + }; + ble_svc_hid_update_info(profile->hid_svc, hid_info_val); + + return &profile->base; +} + +static void ble_profile_hid_stop(FuriHalBleProfileBase* profile) { + furi_check(profile); + furi_check(profile->config == ble_profile_hid); + + BleProfileHid* hid_profile = (BleProfileHid*)profile; + ble_svc_battery_stop(hid_profile->battery_svc); + ble_svc_dev_info_stop(hid_profile->dev_info_svc); + ble_svc_hid_stop(hid_profile->hid_svc); + + free(hid_profile->kb_report); + free(hid_profile->mouse_report); + free(hid_profile->consumer_report); +} + +bool ble_profile_hid_kb_press(FuriHalBleProfileBase* profile, uint16_t button) { + furi_check(profile); + furi_check(profile->config == ble_profile_hid); + + BleProfileHid* hid_profile = (BleProfileHid*)profile; + FuriHalBtHidKbReport* kb_report = hid_profile->kb_report; + for(uint8_t i = 0; i < BLE_PROFILE_HID_KB_MAX_KEYS; i++) { + if(kb_report->key[i] == 0) { + kb_report->key[i] = button & 0xFF; + break; + } + } + kb_report->mods |= (button >> 8); + return ble_svc_hid_update_input_report( + hid_profile->hid_svc, + ReportNumberKeyboard, + (uint8_t*)kb_report, + sizeof(FuriHalBtHidKbReport)); +} + +bool ble_profile_hid_kb_release(FuriHalBleProfileBase* profile, uint16_t button) { + furi_check(profile); + furi_check(profile->config == ble_profile_hid); + + BleProfileHid* hid_profile = (BleProfileHid*)profile; + + FuriHalBtHidKbReport* kb_report = hid_profile->kb_report; + for(uint8_t i = 0; i < BLE_PROFILE_HID_KB_MAX_KEYS; i++) { + if(kb_report->key[i] == (button & 0xFF)) { + kb_report->key[i] = 0; + break; + } + } + kb_report->mods &= ~(button >> 8); + return ble_svc_hid_update_input_report( + hid_profile->hid_svc, + ReportNumberKeyboard, + (uint8_t*)kb_report, + sizeof(FuriHalBtHidKbReport)); +} + +bool ble_profile_hid_kb_release_all(FuriHalBleProfileBase* profile) { + furi_check(profile); + furi_check(profile->config == ble_profile_hid); + + BleProfileHid* hid_profile = (BleProfileHid*)profile; + FuriHalBtHidKbReport* kb_report = hid_profile->kb_report; + for(uint8_t i = 0; i < BLE_PROFILE_HID_KB_MAX_KEYS; i++) { + kb_report->key[i] = 0; + } + kb_report->mods = 0; + return ble_svc_hid_update_input_report( + hid_profile->hid_svc, + ReportNumberKeyboard, + (uint8_t*)kb_report, + sizeof(FuriHalBtHidKbReport)); +} + +bool ble_profile_hid_consumer_key_press(FuriHalBleProfileBase* profile, uint16_t button) { + furi_check(profile); + furi_check(profile->config == ble_profile_hid); + + BleProfileHid* hid_profile = (BleProfileHid*)profile; + FuriHalBtHidConsumerReport* consumer_report = hid_profile->consumer_report; + for(uint8_t i = 0; i < BLE_PROFILE_CONSUMER_MAX_KEYS; i++) { //-V1008 + if(consumer_report->key[i] == 0) { + consumer_report->key[i] = button; + break; + } + } + return ble_svc_hid_update_input_report( + hid_profile->hid_svc, + ReportNumberConsumer, + (uint8_t*)consumer_report, + sizeof(FuriHalBtHidConsumerReport)); +} + +bool ble_profile_hid_consumer_key_release(FuriHalBleProfileBase* profile, uint16_t button) { + furi_check(profile); + furi_check(profile->config == ble_profile_hid); + + BleProfileHid* hid_profile = (BleProfileHid*)profile; + FuriHalBtHidConsumerReport* consumer_report = hid_profile->consumer_report; + for(uint8_t i = 0; i < BLE_PROFILE_CONSUMER_MAX_KEYS; i++) { //-V1008 + if(consumer_report->key[i] == button) { + consumer_report->key[i] = 0; + break; + } + } + return ble_svc_hid_update_input_report( + hid_profile->hid_svc, + ReportNumberConsumer, + (uint8_t*)consumer_report, + sizeof(FuriHalBtHidConsumerReport)); +} + +bool ble_profile_hid_consumer_key_release_all(FuriHalBleProfileBase* profile) { + furi_check(profile); + furi_check(profile->config == ble_profile_hid); + + BleProfileHid* hid_profile = (BleProfileHid*)profile; + FuriHalBtHidConsumerReport* consumer_report = hid_profile->consumer_report; + for(uint8_t i = 0; i < BLE_PROFILE_CONSUMER_MAX_KEYS; i++) { //-V1008 + consumer_report->key[i] = 0; + } + return ble_svc_hid_update_input_report( + hid_profile->hid_svc, + ReportNumberConsumer, + (uint8_t*)consumer_report, + sizeof(FuriHalBtHidConsumerReport)); +} + +bool ble_profile_hid_mouse_move(FuriHalBleProfileBase* profile, int8_t dx, int8_t dy) { + furi_check(profile); + furi_check(profile->config == ble_profile_hid); + + BleProfileHid* hid_profile = (BleProfileHid*)profile; + FuriHalBtHidMouseReport* mouse_report = hid_profile->mouse_report; + mouse_report->x = dx; + mouse_report->y = dy; + bool state = ble_svc_hid_update_input_report( + hid_profile->hid_svc, + ReportNumberMouse, + (uint8_t*)mouse_report, + sizeof(FuriHalBtHidMouseReport)); + mouse_report->x = 0; + mouse_report->y = 0; + return state; +} + +bool ble_profile_hid_mouse_press(FuriHalBleProfileBase* profile, uint8_t button) { + furi_check(profile); + furi_check(profile->config == ble_profile_hid); + + BleProfileHid* hid_profile = (BleProfileHid*)profile; + FuriHalBtHidMouseReport* mouse_report = hid_profile->mouse_report; + mouse_report->btn |= button; + return ble_svc_hid_update_input_report( + hid_profile->hid_svc, + ReportNumberMouse, + (uint8_t*)mouse_report, + sizeof(FuriHalBtHidMouseReport)); +} + +bool ble_profile_hid_mouse_release(FuriHalBleProfileBase* profile, uint8_t button) { + furi_check(profile); + furi_check(profile->config == ble_profile_hid); + + BleProfileHid* hid_profile = (BleProfileHid*)profile; + FuriHalBtHidMouseReport* mouse_report = hid_profile->mouse_report; + mouse_report->btn &= ~button; + return ble_svc_hid_update_input_report( + hid_profile->hid_svc, + ReportNumberMouse, + (uint8_t*)mouse_report, + sizeof(FuriHalBtHidMouseReport)); +} + +bool ble_profile_hid_mouse_release_all(FuriHalBleProfileBase* profile) { + furi_check(profile); + furi_check(profile->config == ble_profile_hid); + + BleProfileHid* hid_profile = (BleProfileHid*)profile; + FuriHalBtHidMouseReport* mouse_report = hid_profile->mouse_report; + mouse_report->btn = 0; + return ble_svc_hid_update_input_report( + hid_profile->hid_svc, + ReportNumberMouse, + (uint8_t*)mouse_report, + sizeof(FuriHalBtHidMouseReport)); +} + +bool ble_profile_hid_mouse_scroll(FuriHalBleProfileBase* profile, int8_t delta) { + furi_check(profile); + furi_check(profile->config == ble_profile_hid); + + BleProfileHid* hid_profile = (BleProfileHid*)profile; + FuriHalBtHidMouseReport* mouse_report = hid_profile->mouse_report; + mouse_report->wheel = delta; + bool state = ble_svc_hid_update_input_report( + hid_profile->hid_svc, + ReportNumberMouse, + (uint8_t*)mouse_report, + sizeof(FuriHalBtHidMouseReport)); + mouse_report->wheel = 0; + return state; +} + +// AN5289: 4.7, in order to use flash controller interval must be at least 25ms + advertisement, which is 30 ms +// Since we don't use flash controller anymore interval can be lowered to 7.5ms +#define CONNECTION_INTERVAL_MIN (0x0006) +// Up to 45 ms +#define CONNECTION_INTERVAL_MAX (0x24) + +static GapConfig template_config = { + .adv_service = + { + .UUID_Type = UUID_TYPE_16, + .Service_UUID_16 = HUMAN_INTERFACE_DEVICE_SERVICE_UUID, + }, + .appearance_char = GAP_APPEARANCE_KEYBOARD, + .bonding_mode = true, + .pairing_method = GapPairingPinCodeVerifyYesNo, + .conn_param = + { + .conn_int_min = CONNECTION_INTERVAL_MIN, + .conn_int_max = CONNECTION_INTERVAL_MAX, + .slave_latency = 0, + .supervisor_timeout = 0, + }, +}; + +static void ble_profile_hid_get_config(GapConfig* config, FuriHalBleProfileParams profile_params) { + furi_check(profile_params); + BleProfileHidParams* hid_profile_params = profile_params; + + furi_check(config); + memcpy(config, &template_config, sizeof(GapConfig)); + + // Set MAC address + memcpy(config->mac_address, hid_profile_params->mac, sizeof(config->mac_address)); + + // Set advertise name + config->adv_name[0] = furi_hal_version_get_ble_local_device_name_ptr()[0]; + strlcpy(config->adv_name + 1, hid_profile_params->name, sizeof(config->adv_name) - 1); + + // Set bonding mode + config->bonding_mode = hid_profile_params->bonding; + + // Set pairing method + config->pairing_method = hid_profile_params->pairing; +} + +static const FuriHalBleProfileTemplate profile_callbacks = { + .start = ble_profile_hid_start, + .stop = ble_profile_hid_stop, + .get_gap_config = ble_profile_hid_get_config, +}; + +const FuriHalBleProfileTemplate* ble_profile_hid = &profile_callbacks; diff --git a/applications/main/bad_usb/helpers/ble_hid_profile.h b/applications/main/bad_usb/helpers/ble_hid_profile.h new file mode 100644 index 000000000..2302aa581 --- /dev/null +++ b/applications/main/bad_usb/helpers/ble_hid_profile.h @@ -0,0 +1,109 @@ +#pragma once + +// Based on + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Optional arguments to pass along with profile template as + * FuriHalBleProfileParams for tuning profile behavior + **/ +typedef struct { + char name[FURI_HAL_BT_ADV_NAME_LENGTH]; /**< Full device name */ + uint8_t mac[GAP_MAC_ADDR_SIZE]; /**< Full device address */ + bool bonding; /**< Save paired devices */ + GapPairing pairing; /**< Pairing security method */ +} BleProfileHidParams; + +/** Hid Keyboard Profile descriptor */ +extern const FuriHalBleProfileTemplate* ble_profile_hid; + +/** Press keyboard button + * + * @param profile profile instance + * @param button button code from HID specification + * + * @return true on success + */ +bool ble_profile_hid_kb_press(FuriHalBleProfileBase* profile, uint16_t button); + +/** Release keyboard button + * + * @param profile profile instance + * @param button button code from HID specification + * + * @return true on success + */ +bool ble_profile_hid_kb_release(FuriHalBleProfileBase* profile, uint16_t button); + +/** Release all keyboard buttons + * + * @param profile profile instance + * @return true on success + */ +bool ble_profile_hid_kb_release_all(FuriHalBleProfileBase* profile); + +/** Set the following consumer key to pressed state and send HID report + * + * @param profile profile instance + * @param button key code + */ +bool ble_profile_hid_consumer_key_press(FuriHalBleProfileBase* profile, uint16_t button); + +/** Set the following consumer key to released state and send HID report + * + * @param profile profile instance + * @param button key code + */ +bool ble_profile_hid_consumer_key_release(FuriHalBleProfileBase* profile, uint16_t button); + +/** Set consumer key to released state and send HID report + * + * @param profile profile instance + * @param button key code + */ +bool ble_profile_hid_consumer_key_release_all(FuriHalBleProfileBase* profile); + +/** Set mouse movement and send HID report + * + * @param profile profile instance + * @param dx x coordinate delta + * @param dy y coordinate delta + */ +bool ble_profile_hid_mouse_move(FuriHalBleProfileBase* profile, int8_t dx, int8_t dy); + +/** Set mouse button to pressed state and send HID report + * + * @param profile profile instance + * @param button key code + */ +bool ble_profile_hid_mouse_press(FuriHalBleProfileBase* profile, uint8_t button); + +/** Set mouse button to released state and send HID report + * + * @param profile profile instance + * @param button key code + */ +bool ble_profile_hid_mouse_release(FuriHalBleProfileBase* profile, uint8_t button); + +/** Set mouse button to released state and send HID report + * + * @param profile profile instance + * @param button key code + */ +bool ble_profile_hid_mouse_release_all(FuriHalBleProfileBase* profile); + +/** Set mouse wheel position and send HID report + * + * @param profile profile instance + * @param delta number of scroll steps + */ +bool ble_profile_hid_mouse_scroll(FuriHalBleProfileBase* profile, int8_t delta); + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/bad_usb/helpers/ble_hid_service.c b/applications/main/bad_usb/helpers/ble_hid_service.c new file mode 100644 index 000000000..b546368dd --- /dev/null +++ b/applications/main/bad_usb/helpers/ble_hid_service.c @@ -0,0 +1,325 @@ +#include "ble_hid_service.h" + +// Based on + +#include "app_common.h" // IWYU pragma: keep +#include +#include +#include + +#include +#include + +#define TAG "BleHid" + +#define BLE_SVC_HID_REPORT_MAP_MAX_LEN (255) +#define BLE_SVC_HID_REPORT_MAX_LEN (255) +#define BLE_SVC_HID_REPORT_REF_LEN (2) +#define BLE_SVC_HID_INFO_LEN (4) +#define BLE_SVC_HID_CONTROL_POINT_LEN (1) + +#define BLE_SVC_HID_INPUT_REPORT_COUNT (3) +#define BLE_SVC_HID_OUTPUT_REPORT_COUNT (0) +#define BLE_SVC_HID_FEATURE_REPORT_COUNT (0) +#define BLE_SVC_HID_REPORT_COUNT \ + (BLE_SVC_HID_INPUT_REPORT_COUNT + BLE_SVC_HID_OUTPUT_REPORT_COUNT + \ + BLE_SVC_HID_FEATURE_REPORT_COUNT) + +typedef enum { + HidSvcGattCharacteristicProtocolMode = 0, + HidSvcGattCharacteristicReportMap, + HidSvcGattCharacteristicInfo, + HidSvcGattCharacteristicCtrlPoint, + HidSvcGattCharacteristicCount, +} HidSvcGattCharacteristicId; + +typedef struct { + uint8_t report_idx; + uint8_t report_type; +} HidSvcReportId; + +static_assert(sizeof(HidSvcReportId) == sizeof(uint16_t), "HidSvcReportId must be 2 bytes"); + +static const Service_UUID_t ble_svc_hid_uuid = { + .Service_UUID_16 = HUMAN_INTERFACE_DEVICE_SERVICE_UUID, +}; + +static bool ble_svc_hid_char_desc_data_callback( + const void* context, + const uint8_t** data, + uint16_t* data_len) { + const HidSvcReportId* report_id = context; + *data_len = sizeof(HidSvcReportId); + if(data) { + *data = (const uint8_t*)report_id; + } + return false; +} + +typedef struct { + const void* data_ptr; + uint16_t data_len; +} HidSvcDataWrapper; + +static bool ble_svc_hid_report_data_callback( + const void* context, + const uint8_t** data, + uint16_t* data_len) { + const HidSvcDataWrapper* report_data = context; + if(data) { + *data = report_data->data_ptr; + *data_len = report_data->data_len; + } else { + *data_len = BLE_SVC_HID_REPORT_MAP_MAX_LEN; + } + return false; +} + +static const BleGattCharacteristicParams ble_svc_hid_chars[HidSvcGattCharacteristicCount] = { + [HidSvcGattCharacteristicProtocolMode] = + {.name = "Protocol Mode", + .data_prop_type = FlipperGattCharacteristicDataFixed, + .data.fixed.length = 1, + .uuid.Char_UUID_16 = PROTOCOL_MODE_CHAR_UUID, + .uuid_type = UUID_TYPE_16, + .char_properties = CHAR_PROP_READ | CHAR_PROP_WRITE_WITHOUT_RESP, + .security_permissions = ATTR_PERMISSION_NONE, + .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE, + .is_variable = CHAR_VALUE_LEN_CONSTANT}, + [HidSvcGattCharacteristicReportMap] = + {.name = "Report Map", + .data_prop_type = FlipperGattCharacteristicDataCallback, + .data.callback.fn = ble_svc_hid_report_data_callback, + .data.callback.context = NULL, + .uuid.Char_UUID_16 = REPORT_MAP_CHAR_UUID, + .uuid_type = UUID_TYPE_16, + .char_properties = CHAR_PROP_READ, + .security_permissions = ATTR_PERMISSION_NONE, + .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, + .is_variable = CHAR_VALUE_LEN_VARIABLE}, + [HidSvcGattCharacteristicInfo] = + {.name = "HID Information", + .data_prop_type = FlipperGattCharacteristicDataFixed, + .data.fixed.length = BLE_SVC_HID_INFO_LEN, + .data.fixed.ptr = NULL, + .uuid.Char_UUID_16 = HID_INFORMATION_CHAR_UUID, + .uuid_type = UUID_TYPE_16, + .char_properties = CHAR_PROP_READ, + .security_permissions = ATTR_PERMISSION_NONE, + .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, + .is_variable = CHAR_VALUE_LEN_CONSTANT}, + [HidSvcGattCharacteristicCtrlPoint] = + {.name = "HID Control Point", + .data_prop_type = FlipperGattCharacteristicDataFixed, + .data.fixed.length = BLE_SVC_HID_CONTROL_POINT_LEN, + .uuid.Char_UUID_16 = HID_CONTROL_POINT_CHAR_UUID, + .uuid_type = UUID_TYPE_16, + .char_properties = CHAR_PROP_WRITE_WITHOUT_RESP, + .security_permissions = ATTR_PERMISSION_NONE, + .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE, + .is_variable = CHAR_VALUE_LEN_CONSTANT}, +}; + +static const BleGattCharacteristicDescriptorParams ble_svc_hid_char_descr_template = { + .uuid_type = UUID_TYPE_16, + .uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID, + .max_length = BLE_SVC_HID_REPORT_REF_LEN, + .data_callback.fn = ble_svc_hid_char_desc_data_callback, + .security_permissions = ATTR_PERMISSION_NONE, + .access_permissions = ATTR_ACCESS_READ_WRITE, + .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, + .is_variable = CHAR_VALUE_LEN_CONSTANT, +}; + +static const BleGattCharacteristicParams ble_svc_hid_report_template = { + .name = "Report", + .data_prop_type = FlipperGattCharacteristicDataCallback, + .data.callback.fn = ble_svc_hid_report_data_callback, + .data.callback.context = NULL, + .uuid.Char_UUID_16 = REPORT_CHAR_UUID, + .uuid_type = UUID_TYPE_16, + .char_properties = CHAR_PROP_READ | CHAR_PROP_NOTIFY, + .security_permissions = ATTR_PERMISSION_NONE, + .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, + .is_variable = CHAR_VALUE_LEN_VARIABLE, +}; + +struct BleServiceHid { + uint16_t svc_handle; + BleGattCharacteristicInstance chars[HidSvcGattCharacteristicCount]; + BleGattCharacteristicInstance input_report_chars[BLE_SVC_HID_INPUT_REPORT_COUNT]; + BleGattCharacteristicInstance output_report_chars[BLE_SVC_HID_OUTPUT_REPORT_COUNT]; + BleGattCharacteristicInstance feature_report_chars[BLE_SVC_HID_FEATURE_REPORT_COUNT]; + GapSvcEventHandler* event_handler; +}; + +static BleEventAckStatus ble_svc_hid_event_handler(void* event, void* context) { + UNUSED(context); + + BleEventAckStatus ret = BleEventNotAck; + hci_event_pckt* event_pckt = (hci_event_pckt*)(((hci_uart_pckt*)event)->data); + evt_blecore_aci* blecore_evt = (evt_blecore_aci*)event_pckt->data; + // aci_gatt_attribute_modified_event_rp0* attribute_modified; + + if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) { + if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) { + // Process modification events + ret = BleEventAckFlowEnable; + } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) { + // Process notification confirmation + ret = BleEventAckFlowEnable; + } + } + return ret; +} + +BleServiceHid* ble_svc_hid_start(void) { + BleServiceHid* hid_svc = malloc(sizeof(BleServiceHid)); + + // Register event handler + hid_svc->event_handler = + ble_event_dispatcher_register_svc_handler(ble_svc_hid_event_handler, hid_svc); + /** + * Add Human Interface Device Service + */ + if(!ble_gatt_service_add( + UUID_TYPE_16, + &ble_svc_hid_uuid, + PRIMARY_SERVICE, + 2 + /* protocol mode */ + (4 * BLE_SVC_HID_INPUT_REPORT_COUNT) + (3 * BLE_SVC_HID_OUTPUT_REPORT_COUNT) + + (3 * BLE_SVC_HID_FEATURE_REPORT_COUNT) + 1 + 2 + 2 + + 2, /* Service + Report Map + HID Information + HID Control Point */ + &hid_svc->svc_handle)) { + free(hid_svc); + return NULL; + } + + // Maintain previously defined characteristic order + ble_gatt_characteristic_init( + hid_svc->svc_handle, + &ble_svc_hid_chars[HidSvcGattCharacteristicProtocolMode], + &hid_svc->chars[HidSvcGattCharacteristicProtocolMode]); + + uint8_t protocol_mode = 1; + ble_gatt_characteristic_update( + hid_svc->svc_handle, + &hid_svc->chars[HidSvcGattCharacteristicProtocolMode], + &protocol_mode); + + // reports + BleGattCharacteristicDescriptorParams ble_svc_hid_char_descr; + BleGattCharacteristicParams report_char; + HidSvcReportId report_id; + + memcpy( + &ble_svc_hid_char_descr, &ble_svc_hid_char_descr_template, sizeof(ble_svc_hid_char_descr)); + memcpy(&report_char, &ble_svc_hid_report_template, sizeof(report_char)); + + ble_svc_hid_char_descr.data_callback.context = &report_id; + report_char.descriptor_params = &ble_svc_hid_char_descr; + + typedef struct { + uint8_t report_type; + uint8_t report_count; + BleGattCharacteristicInstance* chars; + } HidSvcReportCharProps; + + HidSvcReportCharProps hid_report_chars[] = { + {0x01, BLE_SVC_HID_INPUT_REPORT_COUNT, hid_svc->input_report_chars}, + {0x02, BLE_SVC_HID_OUTPUT_REPORT_COUNT, hid_svc->output_report_chars}, + {0x03, BLE_SVC_HID_FEATURE_REPORT_COUNT, hid_svc->feature_report_chars}, + }; + + for(size_t report_type_idx = 0; report_type_idx < COUNT_OF(hid_report_chars); + report_type_idx++) { + report_id.report_type = hid_report_chars[report_type_idx].report_type; + for(size_t report_idx = 0; report_idx < hid_report_chars[report_type_idx].report_count; + report_idx++) { + report_id.report_idx = report_idx + 1; + ble_gatt_characteristic_init( + hid_svc->svc_handle, + &report_char, + &hid_report_chars[report_type_idx].chars[report_idx]); + } + } + + // Setup remaining characteristics + for(size_t i = HidSvcGattCharacteristicReportMap; i < HidSvcGattCharacteristicCount; i++) { + ble_gatt_characteristic_init( + hid_svc->svc_handle, &ble_svc_hid_chars[i], &hid_svc->chars[i]); + } + + return hid_svc; +} + +bool ble_svc_hid_update_report_map(BleServiceHid* hid_svc, const uint8_t* data, uint16_t len) { + furi_assert(data); + furi_assert(hid_svc); + + HidSvcDataWrapper report_data = { + .data_ptr = data, + .data_len = len, + }; + return ble_gatt_characteristic_update( + hid_svc->svc_handle, &hid_svc->chars[HidSvcGattCharacteristicReportMap], &report_data); +} + +bool ble_svc_hid_update_input_report( + BleServiceHid* hid_svc, + uint8_t input_report_num, + uint8_t* data, + uint16_t len) { + furi_assert(data); + furi_assert(hid_svc); + furi_assert(input_report_num < BLE_SVC_HID_INPUT_REPORT_COUNT); + + HidSvcDataWrapper report_data = { + .data_ptr = data, + .data_len = len, + }; + + return ble_gatt_characteristic_update( + hid_svc->svc_handle, &hid_svc->input_report_chars[input_report_num], &report_data); +} + +bool ble_svc_hid_update_info(BleServiceHid* hid_svc, uint8_t* data) { + furi_assert(data); + furi_assert(hid_svc); + + return ble_gatt_characteristic_update( + hid_svc->svc_handle, &hid_svc->chars[HidSvcGattCharacteristicInfo], &data); +} + +void ble_svc_hid_stop(BleServiceHid* hid_svc) { + furi_assert(hid_svc); + ble_event_dispatcher_unregister_svc_handler(hid_svc->event_handler); + // Delete characteristics + for(size_t i = 0; i < HidSvcGattCharacteristicCount; i++) { + ble_gatt_characteristic_delete(hid_svc->svc_handle, &hid_svc->chars[i]); + } + + typedef struct { + uint8_t report_count; + BleGattCharacteristicInstance* chars; + } HidSvcReportCharProps; + + HidSvcReportCharProps hid_report_chars[] = { + {BLE_SVC_HID_INPUT_REPORT_COUNT, hid_svc->input_report_chars}, + {BLE_SVC_HID_OUTPUT_REPORT_COUNT, hid_svc->output_report_chars}, + {BLE_SVC_HID_FEATURE_REPORT_COUNT, hid_svc->feature_report_chars}, + }; + + for(size_t report_type_idx = 0; report_type_idx < COUNT_OF(hid_report_chars); + report_type_idx++) { + for(size_t report_idx = 0; report_idx < hid_report_chars[report_type_idx].report_count; + report_idx++) { + ble_gatt_characteristic_delete( + hid_svc->svc_handle, &hid_report_chars[report_type_idx].chars[report_idx]); + } + } + + // Delete service + ble_gatt_service_delete(hid_svc->svc_handle); + free(hid_svc); +} diff --git a/applications/main/bad_usb/helpers/ble_hid_service.h b/applications/main/bad_usb/helpers/ble_hid_service.h new file mode 100644 index 000000000..e1ac3b0be --- /dev/null +++ b/applications/main/bad_usb/helpers/ble_hid_service.h @@ -0,0 +1,31 @@ +#pragma once + +// Based on + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct BleServiceHid BleServiceHid; + +BleServiceHid* ble_svc_hid_start(void); + +void ble_svc_hid_stop(BleServiceHid* service); + +bool ble_svc_hid_update_report_map(BleServiceHid* service, const uint8_t* data, uint16_t len); + +bool ble_svc_hid_update_input_report( + BleServiceHid* service, + uint8_t input_report_num, + uint8_t* data, + uint16_t len); + +// Expects data to be of length BLE_SVC_HID_INFO_LEN (4 bytes) +bool ble_svc_hid_update_info(BleServiceHid* service, uint8_t* data); + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/bad_usb/helpers/ducky_script.c b/applications/main/bad_usb/helpers/ducky_script.c index 379c3e24a..a64629af2 100644 --- a/applications/main/bad_usb/helpers/ducky_script.c +++ b/applications/main/bad_usb/helpers/ducky_script.c @@ -25,6 +25,8 @@ typedef enum { } WorkerEvtFlags; static const char ducky_cmd_id[] = {"ID"}; +static const char ducky_cmd_bt_id[] = {"BT_ID"}; +static const char ducky_cmd_ble_id[] = {"BLE_ID"}; static const uint8_t numpad_keys[10] = { HID_KEYPAD_0, @@ -40,11 +42,8 @@ static const uint8_t numpad_keys[10] = { }; uint32_t ducky_get_command_len(const char* line) { - uint32_t len = strlen(line); - for(uint32_t i = 0; i < len; i++) { - if(line[i] == ' ') return i; - } - return 0; + char* first_space = strchr(line, ' '); + return first_space ? (first_space - line) : 0; } bool ducky_is_line_end(const char chr) { @@ -180,71 +179,100 @@ static bool ducky_string_next(BadUsbScript* bad_usb) { static int32_t ducky_parse_line(BadUsbScript* bad_usb, FuriString* line) { uint32_t line_len = furi_string_size(line); - const char* line_tmp = furi_string_get_cstr(line); + const char* line_cstr = furi_string_get_cstr(line); if(line_len == 0) { return SCRIPT_STATE_NEXT_LINE; // Skip empty lines } - FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp); + FURI_LOG_D(WORKER_TAG, "line:%s", line_cstr); // Ducky Lang Functions - int32_t cmd_result = ducky_execute_cmd(bad_usb, line_tmp); + int32_t cmd_result = ducky_execute_cmd(bad_usb, line_cstr); if(cmd_result != SCRIPT_STATE_CMD_UNKNOWN) { return cmd_result; } // Mouse Keys - uint16_t key = ducky_get_mouse_keycode_by_name(line_tmp); + uint16_t key = ducky_get_mouse_keycode_by_name(line_cstr); if(key != HID_MOUSE_INVALID) { bad_usb->hid->mouse_press(bad_usb->hid_inst, key); bad_usb->hid->mouse_release(bad_usb->hid_inst, key); return 0; } - // Special keys + modifiers - key = ducky_get_keycode(bad_usb, line_tmp, false); - if(key == HID_KEYBOARD_NONE) { - return ducky_error(bad_usb, "No keycode defined for %s", line_tmp); - } - if((key & 0xFF00) != 0) { - // It's a modifier key - uint32_t offset = ducky_get_command_len(line_tmp) + 1; - // ducky_get_command_len() returns 0 without space, so check for != 1 - if(offset != 1 && line_len > offset) { - // It's also a key combination - key |= ducky_get_keycode(bad_usb, line_tmp + offset, true); - } + // Parse chain of modifiers linked by spaces and hyphens + uint16_t modifiers = 0; + while(1) { + key = ducky_get_next_modifier_keycode_by_name(&line_cstr); + if(key == HID_KEYBOARD_NONE) break; + + modifiers |= key; + char next_char = *line_cstr; + if(next_char == ' ' || next_char == '-') line_cstr++; } + + // Main key + char next_char = *line_cstr; + uint16_t main_key = ducky_get_keycode_by_name(line_cstr); + if(!main_key && next_char) main_key = BADUSB_ASCII_TO_KEY(bad_usb, next_char); + key = modifiers | main_key; + + if(key == 0 && next_char) ducky_error(bad_usb, "No keycode defined for %s", line_cstr); + bad_usb->hid->kb_press(bad_usb->hid_inst, key); bad_usb->hid->kb_release(bad_usb->hid_inst, key); return 0; } static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) { - if(sscanf(line, "%lX:%lX", &bad_usb->hid_cfg.vid, &bad_usb->hid_cfg.pid) == 2) { - bad_usb->hid_cfg.manuf[0] = '\0'; - bad_usb->hid_cfg.product[0] = '\0'; + FuriHalUsbHidConfig* usb_hid_cfg = &bad_usb->hid_cfg->usb; + + if(sscanf(line, "%lX:%lX", &usb_hid_cfg->vid, &usb_hid_cfg->pid) == 2) { + usb_hid_cfg->manuf[0] = '\0'; + usb_hid_cfg->product[0] = '\0'; uint8_t id_len = ducky_get_command_len(line); if(!ducky_is_line_end(line[id_len + 1])) { sscanf( &line[id_len + 1], "%31[^\r\n:]:%31[^\r\n]", - bad_usb->hid_cfg.manuf, - bad_usb->hid_cfg.product); + usb_hid_cfg->manuf, + usb_hid_cfg->product); } FURI_LOG_D( WORKER_TAG, "set id: %04lX:%04lX mfr:%s product:%s", - bad_usb->hid_cfg.vid, - bad_usb->hid_cfg.pid, - bad_usb->hid_cfg.manuf, - bad_usb->hid_cfg.product); + usb_hid_cfg->vid, + usb_hid_cfg->pid, + usb_hid_cfg->manuf, + usb_hid_cfg->product); return true; } return false; } +static bool ducky_set_ble_id(BadUsbScript* bad_usb, const char* line) { + BleProfileHidParams* ble_hid_cfg = &bad_usb->hid_cfg->ble; + + size_t line_len = strlen(line); + size_t mac_len = sizeof(ble_hid_cfg->mac) * 3; // 2 hex chars + separator per byte + if(line_len < mac_len + 1) return false; // MAC + at least 1 char for name + + for(size_t i = 0; i < sizeof(ble_hid_cfg->mac); i++) { + const char* hex_byte = &line[i * 3]; + // This sscanf() doesn't work well with %02hhX, need to use a u32 + uint32_t temp_uint; + if(sscanf(hex_byte, "%02lX", &temp_uint) != 1) { + return false; + } + ble_hid_cfg->mac[sizeof(ble_hid_cfg->mac) - 1 - i] = temp_uint; + } + + strlcpy(ble_hid_cfg->name, line + mac_len, sizeof(ble_hid_cfg->name)); + FURI_LOG_D(WORKER_TAG, "set ble id: %s", line); + return true; +} + static void bad_usb_hid_state_callback(bool state, void* context) { furi_assert(context); BadUsbScript* bad_usb = context; @@ -283,17 +311,30 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) { } } while(ret > 0); - const char* line_tmp = furi_string_get_cstr(bad_usb->line); - bool id_set = false; // Looking for ID command at first line - if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) { - id_set = ducky_set_usb_id(bad_usb, &line_tmp[strlen(ducky_cmd_id) + 1]); + if(bad_usb->load_id_cfg) { + const char* line_tmp = furi_string_get_cstr(bad_usb->line); + BadUsbHidInterface interface = *bad_usb->interface; + // Look for ID/BLE_ID/BT_ID command on first line + if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) { + if(ducky_set_usb_id(bad_usb, &line_tmp[strlen(ducky_cmd_id) + 1])) { + interface = BadUsbHidInterfaceUsb; + } + } else if( + strncmp(line_tmp, ducky_cmd_ble_id, strlen(ducky_cmd_ble_id)) == 0 || + strncmp(line_tmp, ducky_cmd_bt_id, strlen(ducky_cmd_bt_id)) == 0) { + if(ducky_set_ble_id(bad_usb, &line_tmp[ducky_get_command_len(line_tmp) + 1])) { + interface = BadUsbHidInterfaceBle; + } + } + + // Auto-switch based on ID/BLE_ID/BT_ID command, user can override manually after + if(interface != *bad_usb->interface) { + *bad_usb->interface = interface; + bad_usb->hid = bad_usb_hid_get_interface(*bad_usb->interface); + } } - if(id_set) { - bad_usb->hid_inst = bad_usb->hid->init(&bad_usb->hid_cfg); - } else { - bad_usb->hid_inst = bad_usb->hid->init(NULL); - } + bad_usb->hid_inst = bad_usb->hid->init(bad_usb->hid_cfg); bad_usb->hid->set_state_callback(bad_usb->hid_inst, bad_usb_hid_state_callback, bad_usb); storage_file_seek(script_file, 0, true); @@ -396,9 +437,12 @@ static int32_t bad_usb_worker(void* context) { bad_usb->line = furi_string_alloc(); bad_usb->line_prev = furi_string_alloc(); bad_usb->string_print = furi_string_alloc(); + bad_usb->st.elapsed = 0; while(1) { + uint32_t start = furi_get_tick(); if(worker_state == BadUsbStateInit) { // State: initialization + start = 0; if(storage_file_open( script_file, furi_string_get_cstr(bad_usb->file_path), @@ -408,7 +452,7 @@ static int32_t bad_usb_worker(void* context) { if(bad_usb->hid->is_connected(bad_usb->hid_inst)) { worker_state = BadUsbStateIdle; // Ready to run } else { - worker_state = BadUsbStateNotConnected; // USB not connected + worker_state = BadUsbStateNotConnected; // Not connected } } else { worker_state = BadUsbStateScriptError; // Script preload error @@ -419,7 +463,8 @@ static int32_t bad_usb_worker(void* context) { } bad_usb->st.state = worker_state; - } else if(worker_state == BadUsbStateNotConnected) { // State: USB not connected + } else if(worker_state == BadUsbStateNotConnected) { // State: Not connected + start = 0; uint32_t flags = bad_usb_flags_get( WorkerEvtEnd | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtStartStop, FuriWaitForever); @@ -429,11 +474,12 @@ static int32_t bad_usb_worker(void* context) { } else if(flags & WorkerEvtConnect) { worker_state = BadUsbStateIdle; // Ready to run } else if(flags & WorkerEvtStartStop) { - worker_state = BadUsbStateWillRun; // Will run when USB is connected + worker_state = BadUsbStateWillRun; // Will run when connected } bad_usb->st.state = worker_state; } else if(worker_state == BadUsbStateIdle) { // State: ready to start + start = 0; uint32_t flags = bad_usb_flags_get( WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtDisconnect, FuriWaitForever); @@ -452,12 +498,14 @@ static int32_t bad_usb_worker(void* context) { bad_usb->file_end = false; storage_file_seek(script_file, 0, true); worker_state = BadUsbStateRunning; + bad_usb->st.elapsed = 0; } else if(flags & WorkerEvtDisconnect) { - worker_state = BadUsbStateNotConnected; // USB disconnected + worker_state = BadUsbStateNotConnected; // Disconnected } bad_usb->st.state = worker_state; } else if(worker_state == BadUsbStateWillRun) { // State: start on connection + start = 0; uint32_t flags = bad_usb_flags_get( WorkerEvtEnd | WorkerEvtConnect | WorkerEvtStartStop, FuriWaitForever); @@ -482,6 +530,7 @@ static int32_t bad_usb_worker(void* context) { if(flags == (unsigned)FuriFlagErrorTimeout) { // If nothing happened - start script execution worker_state = BadUsbStateRunning; + bad_usb->st.elapsed = 0; } else if(flags & WorkerEvtStartStop) { worker_state = BadUsbStateIdle; furi_thread_flags_clear(WorkerEvtStartStop); @@ -492,7 +541,7 @@ static int32_t bad_usb_worker(void* context) { bad_usb->st.state = worker_state; } else if(worker_state == BadUsbStateRunning) { // State: running - uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val); + uint16_t delay_cur = (delay_val > 100) ? (100) : (delay_val); uint32_t flags = furi_thread_flags_wait( WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect, FuriFlagWaitAny, @@ -506,19 +555,21 @@ static int32_t bad_usb_worker(void* context) { worker_state = BadUsbStateIdle; // Stop executing script bad_usb->hid->release_all(bad_usb->hid_inst); } else if(flags & WorkerEvtDisconnect) { - worker_state = BadUsbStateNotConnected; // USB disconnected + worker_state = BadUsbStateNotConnected; // Disconnected bad_usb->hid->release_all(bad_usb->hid_inst); } else if(flags & WorkerEvtPauseResume) { pause_state = BadUsbStateRunning; worker_state = BadUsbStatePaused; // Pause } bad_usb->st.state = worker_state; + bad_usb->st.elapsed += (furi_get_tick() - start); continue; } else if( (flags == (unsigned)FuriFlagErrorTimeout) || (flags == (unsigned)FuriFlagErrorResource)) { if(delay_val > 0) { bad_usb->st.delay_remain--; + bad_usb->st.elapsed += (furi_get_tick() - start); continue; } bad_usb->st.state = BadUsbStateRunning; @@ -533,6 +584,7 @@ static int32_t bad_usb_worker(void* context) { worker_state = BadUsbStateIdle; bad_usb->st.state = BadUsbStateDone; bad_usb->hid->release_all(bad_usb->hid_inst); + bad_usb->st.elapsed += (furi_get_tick() - start); continue; } else if(delay_val == SCRIPT_STATE_STRING_START) { // Start printing string with delays delay_val = bad_usb->defdelay; @@ -541,14 +593,15 @@ static int32_t bad_usb_worker(void* context) { } else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // set state to wait for user input worker_state = BadUsbStateWaitForBtn; bad_usb->st.state = BadUsbStateWaitForBtn; // Show long delays - } else if(delay_val > 1000) { + } else if(delay_val > 100) { bad_usb->st.state = BadUsbStateDelay; // Show long delays - bad_usb->st.delay_remain = delay_val / 1000; + bad_usb->st.delay_remain = delay_val / 100; } } else { furi_check((flags & FuriFlagError) == 0); } } else if(worker_state == BadUsbStateWaitForBtn) { // State: Wait for button Press + start = 0; uint32_t flags = bad_usb_flags_get( WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect, FuriWaitForever); @@ -559,13 +612,14 @@ static int32_t bad_usb_worker(void* context) { delay_val = 0; worker_state = BadUsbStateRunning; } else if(flags & WorkerEvtDisconnect) { - worker_state = BadUsbStateNotConnected; // USB disconnected + worker_state = BadUsbStateNotConnected; // Disconnected bad_usb->hid->release_all(bad_usb->hid_inst); } bad_usb->st.state = worker_state; continue; } } else if(worker_state == BadUsbStatePaused) { // State: Paused + start = 0; uint32_t flags = bad_usb_flags_get( WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect, FuriWaitForever); @@ -577,14 +631,14 @@ static int32_t bad_usb_worker(void* context) { bad_usb->st.state = worker_state; bad_usb->hid->release_all(bad_usb->hid_inst); } else if(flags & WorkerEvtDisconnect) { - worker_state = BadUsbStateNotConnected; // USB disconnected + worker_state = BadUsbStateNotConnected; // Disconnected bad_usb->st.state = worker_state; bad_usb->hid->release_all(bad_usb->hid_inst); } else if(flags & WorkerEvtPauseResume) { if(pause_state == BadUsbStateRunning) { if(delay_val > 0) { bad_usb->st.state = BadUsbStateDelay; - bad_usb->st.delay_remain = delay_val / 1000; + bad_usb->st.delay_remain = delay_val / 100; } else { bad_usb->st.state = BadUsbStateRunning; delay_val = 0; @@ -611,13 +665,14 @@ static int32_t bad_usb_worker(void* context) { worker_state = BadUsbStateIdle; // Stop executing script bad_usb->hid->release_all(bad_usb->hid_inst); } else if(flags & WorkerEvtDisconnect) { - worker_state = BadUsbStateNotConnected; // USB disconnected + worker_state = BadUsbStateNotConnected; // Disconnected bad_usb->hid->release_all(bad_usb->hid_inst); } else if(flags & WorkerEvtPauseResume) { pause_state = BadUsbStateStringDelay; worker_state = BadUsbStatePaused; // Pause } bad_usb->st.state = worker_state; + bad_usb->st.elapsed += (furi_get_tick() - start); continue; } else if( (flags == (unsigned)FuriFlagErrorTimeout) || @@ -633,6 +688,7 @@ static int32_t bad_usb_worker(void* context) { } else if( (worker_state == BadUsbStateFileError) || (worker_state == BadUsbStateScriptError)) { // State: error + start = 0; uint32_t flags = bad_usb_flags_get(WorkerEvtEnd, FuriWaitForever); // Waiting for exit command @@ -640,6 +696,9 @@ static int32_t bad_usb_worker(void* context) { break; } } + if(start) { + bad_usb->st.elapsed += (furi_get_tick() - start); + } } bad_usb->hid->set_state_callback(bad_usb->hid_inst, NULL, NULL); @@ -662,7 +721,11 @@ static void bad_usb_script_set_default_keyboard_layout(BadUsbScript* bad_usb) { memcpy(bad_usb->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_usb->layout))); } -BadUsbScript* bad_usb_script_open(FuriString* file_path, BadUsbHidInterface interface) { +BadUsbScript* bad_usb_script_open( + FuriString* file_path, + BadUsbHidInterface* interface, + BadUsbHidConfig* hid_cfg, + bool load_id_cfg) { furi_assert(file_path); BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript)); @@ -672,7 +735,10 @@ BadUsbScript* bad_usb_script_open(FuriString* file_path, BadUsbHidInterface inte bad_usb->st.state = BadUsbStateInit; bad_usb->st.error[0] = '\0'; - bad_usb->hid = bad_usb_hid_get_interface(interface); + bad_usb->interface = interface; + bad_usb->hid_cfg = hid_cfg; + bad_usb->load_id_cfg = load_id_cfg; + bad_usb->hid = bad_usb_hid_get_interface(*bad_usb->interface); bad_usb->thread = furi_thread_alloc_ex("BadUsbWorker", 2048, bad_usb_worker, bad_usb); furi_thread_start(bad_usb->thread); diff --git a/applications/main/bad_usb/helpers/ducky_script.h b/applications/main/bad_usb/helpers/ducky_script.h index 9519623f6..9131ef43e 100644 --- a/applications/main/bad_usb/helpers/ducky_script.h +++ b/applications/main/bad_usb/helpers/ducky_script.h @@ -30,11 +30,16 @@ typedef struct { uint32_t delay_remain; size_t error_line; char error[64]; + uint32_t elapsed; } BadUsbState; typedef struct BadUsbScript BadUsbScript; -BadUsbScript* bad_usb_script_open(FuriString* file_path, BadUsbHidInterface interface); +BadUsbScript* bad_usb_script_open( + FuriString* file_path, + BadUsbHidInterface* interface, + BadUsbHidConfig* hid_cfg, + bool load_id_cfg); void bad_usb_script_close(BadUsbScript* bad_usb); diff --git a/applications/main/bad_usb/helpers/ducky_script_commands.c b/applications/main/bad_usb/helpers/ducky_script_commands.c index 1b4ff55cb..6c6fe36c7 100644 --- a/applications/main/bad_usb/helpers/ducky_script_commands.c +++ b/applications/main/bad_usb/helpers/ducky_script_commands.c @@ -256,6 +256,8 @@ static int32_t ducky_fnc_mouse_move(BadUsbScript* bad_usb, const char* line, int static const DuckyCmd ducky_commands[] = { {"REM", NULL, -1}, {"ID", NULL, -1}, + {"BT_ID", NULL, -1}, + {"BLE_ID", NULL, -1}, {"DELAY", ducky_fnc_delay, -1}, {"STRING", ducky_fnc_string, 0}, {"STRINGLN", ducky_fnc_string, 1}, diff --git a/applications/main/bad_usb/helpers/ducky_script_i.h b/applications/main/bad_usb/helpers/ducky_script_i.h index fd95ecf58..d735a8407 100644 --- a/applications/main/bad_usb/helpers/ducky_script_i.h +++ b/applications/main/bad_usb/helpers/ducky_script_i.h @@ -22,7 +22,9 @@ extern "C" { #define HID_MOUSE_NONE 0 struct BadUsbScript { - FuriHalUsbHidConfig hid_cfg; + BadUsbHidInterface* interface; + BadUsbHidConfig* hid_cfg; + bool load_id_cfg; const BadUsbHidApi* hid; void* hid_inst; FuriThread* thread; @@ -54,6 +56,8 @@ uint32_t ducky_get_command_len(const char* line); bool ducky_is_line_end(const char chr); +uint16_t ducky_get_next_modifier_keycode_by_name(const char** param); + uint16_t ducky_get_keycode_by_name(const char* param); uint16_t ducky_get_media_keycode_by_name(const char* param); diff --git a/applications/main/bad_usb/helpers/ducky_script_keycodes.c b/applications/main/bad_usb/helpers/ducky_script_keycodes.c index 7dd2e4d16..ce957bb4e 100644 --- a/applications/main/bad_usb/helpers/ducky_script_keycodes.c +++ b/applications/main/bad_usb/helpers/ducky_script_keycodes.c @@ -6,21 +6,16 @@ typedef struct { uint16_t keycode; } DuckyKey; -static const DuckyKey ducky_keys[] = { - {"CTRL-ALT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT}, - {"CTRL-SHIFT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT}, - {"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT}, - {"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI}, - {"GUI-SHIFT", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT}, - {"GUI-CTRL", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_CTRL}, - +static const DuckyKey ducky_modifier_keys[] = { {"CTRL", KEY_MOD_LEFT_CTRL}, {"CONTROL", KEY_MOD_LEFT_CTRL}, {"SHIFT", KEY_MOD_LEFT_SHIFT}, {"ALT", KEY_MOD_LEFT_ALT}, {"GUI", KEY_MOD_LEFT_GUI}, {"WINDOWS", KEY_MOD_LEFT_GUI}, +}; +static const DuckyKey ducky_keys[] = { {"DOWNARROW", HID_KEYBOARD_DOWN_ARROW}, {"DOWN", HID_KEYBOARD_DOWN_ARROW}, {"LEFTARROW", HID_KEYBOARD_LEFT_ARROW}, @@ -119,6 +114,23 @@ static const DuckyKey ducky_mouse_keys[] = { {"WHEEL_CLICK", HID_MOUSE_BTN_WHEEL}, }; +uint16_t ducky_get_next_modifier_keycode_by_name(const char** param) { + const char* input_str = *param; + + for(size_t i = 0; i < COUNT_OF(ducky_modifier_keys); i++) { + size_t key_cmd_len = strlen(ducky_modifier_keys[i].name); + if((strncmp(input_str, ducky_modifier_keys[i].name, key_cmd_len) == 0)) { + char next_char_after_key = input_str[key_cmd_len]; + if(ducky_is_line_end(next_char_after_key) || (next_char_after_key == '-')) { + *param = &input_str[key_cmd_len]; + return ducky_modifier_keys[i].keycode; + } + } + } + + return HID_KEYBOARD_NONE; +} + uint16_t ducky_get_keycode_by_name(const char* param) { for(size_t i = 0; i < COUNT_OF(ducky_keys); i++) { size_t key_cmd_len = strlen(ducky_keys[i].name); diff --git a/applications/main/bad_usb/resources/badusb/assets/layouts/de-DE-mac.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/de-DE-mac.kl new file mode 100755 index 0000000000000000000000000000000000000000..471b7143e24c8351d253885436bd60fb7cc4a641 GIT binary patch literal 256 zcmaLL#|^?z0Kibog3t+}_mT#p2@aG2{wVA}17|My_6)xrIdS-1e|2W<#ydMxGw&9b z-n{YT&5PVUYc_1zk&=;9Q1bHWgS`(g#-U=>$eMKinterface == BadUsbHidInterfaceBle ? BadUsbHidInterfaceUsb : + BadUsbHidInterfaceBle); + variable_item_set_current_value_text( + item, bad_usb->interface == BadUsbHidInterfaceBle ? "BLE" : "USB"); + view_dispatcher_send_custom_event(bad_usb->view_dispatcher, ConfigIndexConnection); +} + +void bad_usb_scene_config_ble_persist_pairing_callback(VariableItem* item) { + BadUsbApp* bad_usb = variable_item_get_context(item); + bool value = variable_item_get_current_value_index(item); + const BadUsbHidApi* hid = bad_usb_hid_get_interface(bad_usb->interface); + // Apply to current script config + bad_usb->script_hid_cfg.ble.bonding = value; + hid->adjust_config(&bad_usb->script_hid_cfg); + // Set in user config to save in settings file + bad_usb->user_hid_cfg.ble.bonding = value; + variable_item_set_current_value_text(item, value ? "ON" : "OFF"); +} + +const char* const ble_pairing_mode_names[GapPairingCount] = { + "YesNo", + "PIN Type", + "PIN Y/N", +}; +void bad_usb_scene_config_ble_pairing_mode_callback(VariableItem* item) { + BadUsbApp* bad_usb = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + const BadUsbHidApi* hid = bad_usb_hid_get_interface(bad_usb->interface); + // Apply to current script config + bad_usb->script_hid_cfg.ble.pairing = index; + hid->adjust_config(&bad_usb->script_hid_cfg); + // Set in user config to save in settings file + bad_usb->user_hid_cfg.ble.pairing = index; + variable_item_set_current_value_text(item, ble_pairing_mode_names[index]); +} + void bad_usb_scene_config_select_callback(void* context, uint32_t index) { BadUsbApp* bad_usb = context; @@ -13,12 +71,59 @@ void bad_usb_scene_config_select_callback(void* context, uint32_t index) { static void draw_menu(BadUsbApp* bad_usb) { VariableItemList* var_item_list = bad_usb->var_item_list; + VariableItem* item; variable_item_list_reset(var_item_list); variable_item_list_add(var_item_list, "Keyboard Layout (global)", 0, NULL, NULL); - variable_item_list_add(var_item_list, "Remove Pairing", 0, NULL, NULL); + item = variable_item_list_add( + var_item_list, "Connection", 2, bad_usb_scene_config_connection_callback, bad_usb); + variable_item_set_current_value_index(item, bad_usb->interface == BadUsbHidInterfaceBle); + variable_item_set_current_value_text( + item, bad_usb->interface == BadUsbHidInterfaceBle ? "BLE" : "USB"); + + if(bad_usb->interface == BadUsbHidInterfaceBle) { + BleProfileHidParams* ble_hid_cfg = &bad_usb->script_hid_cfg.ble; + + item = variable_item_list_add( + var_item_list, + "Persist Pairing", + 2, + bad_usb_scene_config_ble_persist_pairing_callback, + bad_usb); + variable_item_set_current_value_index(item, ble_hid_cfg->bonding); + variable_item_set_current_value_text(item, ble_hid_cfg->bonding ? "ON" : "OFF"); + + item = variable_item_list_add( + var_item_list, + "Pairing Mode", + GapPairingCount, + bad_usb_scene_config_ble_pairing_mode_callback, + bad_usb); + variable_item_set_current_value_index(item, ble_hid_cfg->pairing); + variable_item_set_current_value_text(item, ble_pairing_mode_names[ble_hid_cfg->pairing]); + + variable_item_list_add(var_item_list, "Set Device Name", 0, NULL, NULL); + + variable_item_list_add(var_item_list, "Set MAC Address", 0, NULL, NULL); + + variable_item_list_add(var_item_list, "Randomize MAC Address", 0, NULL, NULL); + + variable_item_list_add(var_item_list, "Restore BLE Defaults", 0, NULL, NULL); + + variable_item_list_add(var_item_list, "Remove BLE Pairing", 0, NULL, NULL); + } else { + variable_item_list_add(var_item_list, "Set Manufacturer Name", 0, NULL, NULL); + + variable_item_list_add(var_item_list, "Set Product Name", 0, NULL, NULL); + + variable_item_list_add(var_item_list, "Set VID and PID", 0, NULL, NULL); + + variable_item_list_add(var_item_list, "Randomize VID and PID", 0, NULL, NULL); + + variable_item_list_add(var_item_list, "Restore USB Defaults", 0, NULL, NULL); + } } void bad_usb_scene_config_on_enter(void* context) { @@ -28,7 +133,8 @@ void bad_usb_scene_config_on_enter(void* context) { variable_item_list_set_enter_callback( var_item_list, bad_usb_scene_config_select_callback, bad_usb); draw_menu(bad_usb); - variable_item_list_set_selected_item(var_item_list, 0); + variable_item_list_set_selected_item( + var_item_list, scene_manager_get_scene_state(bad_usb->scene_manager, BadUsbSceneConfig)); view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewConfig); } @@ -38,13 +144,110 @@ bool bad_usb_scene_config_on_event(void* context, SceneManagerEvent event) { bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(bad_usb->scene_manager, BadUsbSceneConfig, event.event); consumed = true; - if(event.event == ConfigIndexKeyboardLayout) { + const BadUsbHidApi* hid = bad_usb_hid_get_interface(bad_usb->interface); + + switch(event.event) { + case ConfigIndexKeyboardLayout: scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigLayout); - } else if(event.event == ConfigIndexBleUnpair) { - scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfirmUnpair); + break; + case ConfigIndexConnection: + // Refresh default values for new interface + hid->adjust_config(&bad_usb->script_hid_cfg); + // Redraw menu with new interface options + draw_menu(bad_usb); + break; + default: + break; + } + if(bad_usb->interface == BadUsbHidInterfaceBle) { + switch(event.event) { + case ConfigIndexBleSetDeviceName: + scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigBleName); + break; + case ConfigIndexBleSetMacAddress: + scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigBleMac); + break; + case ConfigIndexBleRandomizeMacAddress: + // Apply to current script config + furi_hal_random_fill_buf( + bad_usb->script_hid_cfg.ble.mac, sizeof(bad_usb->script_hid_cfg.ble.mac)); + bad_usb->script_hid_cfg.ble.mac[sizeof(bad_usb->script_hid_cfg.ble.mac) - 1] |= + 0b11 << 6; // Set 2 MSB for Random Static Address + hid->adjust_config(&bad_usb->script_hid_cfg); + // Set in user config to save in settings file + memcpy( + bad_usb->user_hid_cfg.ble.mac, + bad_usb->script_hid_cfg.ble.mac, + sizeof(bad_usb->user_hid_cfg.ble.mac)); + scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneDone); + break; + case ConfigIndexBleRestoreDefaults: + // Apply to current script config + bad_usb->script_hid_cfg.ble.name[0] = '\0'; + memset( + bad_usb->script_hid_cfg.ble.mac, 0, sizeof(bad_usb->script_hid_cfg.ble.mac)); + bad_usb->script_hid_cfg.ble.bonding = true; + bad_usb->script_hid_cfg.ble.pairing = GapPairingPinCodeVerifyYesNo; + hid->adjust_config(&bad_usb->script_hid_cfg); + // Set in user config to save in settings file + memcpy( + &bad_usb->user_hid_cfg.ble, + &bad_usb->script_hid_cfg.ble, + sizeof(bad_usb->user_hid_cfg.ble)); + scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneDone); + break; + case ConfigIndexBleRemovePairing: + scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfirmUnpair); + break; + default: + break; + } } else { - furi_crash("Unknown key type"); + switch(event.event) { + case ConfigIndexUsbSetManufacturerName: + scene_manager_set_scene_state( + bad_usb->scene_manager, BadUsbSceneConfigUsbName, true); + scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigUsbName); + break; + case ConfigIndexUsbSetProductName: + scene_manager_set_scene_state( + bad_usb->scene_manager, BadUsbSceneConfigUsbName, false); + scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigUsbName); + break; + case ConfigIndexUsbSetVidPid: + scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigUsbVidPid); + break; + case ConfigIndexUsbRandomizeVidPid: + furi_hal_random_fill_buf( + (void*)bad_usb->usb_vidpid_buf, sizeof(bad_usb->usb_vidpid_buf)); + // Apply to current script config + bad_usb->script_hid_cfg.usb.vid = bad_usb->usb_vidpid_buf[0]; + bad_usb->script_hid_cfg.usb.pid = bad_usb->usb_vidpid_buf[1]; + hid->adjust_config(&bad_usb->script_hid_cfg); + // Set in user config to save in settings file + bad_usb->user_hid_cfg.usb.vid = bad_usb->script_hid_cfg.usb.vid; + bad_usb->user_hid_cfg.usb.pid = bad_usb->script_hid_cfg.usb.pid; + scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneDone); + break; + case ConfigIndexUsbRestoreDefaults: + // Apply to current script config + bad_usb->script_hid_cfg.usb.vid = 0; + bad_usb->script_hid_cfg.usb.pid = 0; + bad_usb->script_hid_cfg.usb.manuf[0] = '\0'; + bad_usb->script_hid_cfg.usb.product[0] = '\0'; + hid->adjust_config(&bad_usb->script_hid_cfg); + // Set in user config to save in settings file + memcpy( + &bad_usb->user_hid_cfg.usb, + &bad_usb->script_hid_cfg.usb, + sizeof(bad_usb->user_hid_cfg.usb)); + scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneDone); + break; + default: + break; + } } } diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config.h b/applications/main/bad_usb/scenes/bad_usb_scene_config.h index 3d1b8b1a7..2ea25e134 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_config.h +++ b/applications/main/bad_usb/scenes/bad_usb_scene_config.h @@ -3,5 +3,9 @@ ADD_SCENE(bad_usb, work, Work) ADD_SCENE(bad_usb, error, Error) ADD_SCENE(bad_usb, config, Config) ADD_SCENE(bad_usb, config_layout, ConfigLayout) +ADD_SCENE(bad_usb, config_ble_name, ConfigBleName) +ADD_SCENE(bad_usb, config_ble_mac, ConfigBleMac) +ADD_SCENE(bad_usb, config_usb_name, ConfigUsbName) +ADD_SCENE(bad_usb, config_usb_vidpid, ConfigUsbVidPid) ADD_SCENE(bad_usb, confirm_unpair, ConfirmUnpair) -ADD_SCENE(bad_usb, unpair_done, UnpairDone) +ADD_SCENE(bad_usb, done, Done) diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config_ble_mac.c b/applications/main/bad_usb/scenes/bad_usb_scene_config_ble_mac.c new file mode 100644 index 000000000..7ad4e3ed4 --- /dev/null +++ b/applications/main/bad_usb/scenes/bad_usb_scene_config_ble_mac.c @@ -0,0 +1,73 @@ +#include "../bad_usb_app_i.h" + +enum ByteInputResult { + ByteInputResultOk, +}; + +static void reverse_mac_addr(uint8_t mac_addr[GAP_MAC_ADDR_SIZE]) { + uint8_t tmp; + for(size_t i = 0; i < GAP_MAC_ADDR_SIZE / 2; i++) { + tmp = mac_addr[i]; + mac_addr[i] = mac_addr[GAP_MAC_ADDR_SIZE - 1 - i]; + mac_addr[GAP_MAC_ADDR_SIZE - 1 - i] = tmp; + } +} + +void bad_usb_scene_config_ble_mac_byte_input_callback(void* context) { + BadUsbApp* bad_usb = context; + + view_dispatcher_send_custom_event(bad_usb->view_dispatcher, ByteInputResultOk); +} + +void bad_usb_scene_config_ble_mac_on_enter(void* context) { + BadUsbApp* bad_usb = context; + ByteInput* byte_input = bad_usb->byte_input; + + memcpy(bad_usb->ble_mac_buf, bad_usb->script_hid_cfg.ble.mac, sizeof(bad_usb->ble_mac_buf)); + reverse_mac_addr(bad_usb->ble_mac_buf); + byte_input_set_header_text(byte_input, "Set BLE MAC address"); + + byte_input_set_result_callback( + byte_input, + bad_usb_scene_config_ble_mac_byte_input_callback, + NULL, + bad_usb, + bad_usb->ble_mac_buf, + sizeof(bad_usb->ble_mac_buf)); + + view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewByteInput); +} + +bool bad_usb_scene_config_ble_mac_on_event(void* context, SceneManagerEvent event) { + BadUsbApp* bad_usb = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == ByteInputResultOk) { + const BadUsbHidApi* hid = bad_usb_hid_get_interface(bad_usb->interface); + reverse_mac_addr(bad_usb->ble_mac_buf); + // Apply to current script config + memcpy( + bad_usb->script_hid_cfg.ble.mac, + bad_usb->ble_mac_buf, + sizeof(bad_usb->script_hid_cfg.ble.mac)); + hid->adjust_config(&bad_usb->script_hid_cfg); + // Set in user config to save in settings file + memcpy( + bad_usb->user_hid_cfg.ble.mac, + bad_usb->ble_mac_buf, + sizeof(bad_usb->user_hid_cfg.ble.mac)); + } + scene_manager_previous_scene(bad_usb->scene_manager); + } + return consumed; +} + +void bad_usb_scene_config_ble_mac_on_exit(void* context) { + BadUsbApp* bad_usb = context; + ByteInput* byte_input = bad_usb->byte_input; + + byte_input_set_result_callback(byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(byte_input, ""); +} diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config_ble_name.c b/applications/main/bad_usb/scenes/bad_usb_scene_config_ble_name.c new file mode 100644 index 000000000..af7913e7d --- /dev/null +++ b/applications/main/bad_usb/scenes/bad_usb_scene_config_ble_name.c @@ -0,0 +1,62 @@ +#include "../bad_usb_app_i.h" + +enum TextInputResult { + TextInputResultOk, +}; + +static void bad_usb_scene_config_ble_name_text_input_callback(void* context) { + BadUsbApp* bad_usb = context; + + view_dispatcher_send_custom_event(bad_usb->view_dispatcher, TextInputResultOk); +} + +void bad_usb_scene_config_ble_name_on_enter(void* context) { + BadUsbApp* bad_usb = context; + TextInput* text_input = bad_usb->text_input; + + strlcpy( + bad_usb->ble_name_buf, bad_usb->script_hid_cfg.ble.name, sizeof(bad_usb->ble_name_buf)); + text_input_set_header_text(text_input, "Set BLE device name"); + + text_input_set_result_callback( + text_input, + bad_usb_scene_config_ble_name_text_input_callback, + bad_usb, + bad_usb->ble_name_buf, + sizeof(bad_usb->ble_name_buf), + true); + + view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewTextInput); +} + +bool bad_usb_scene_config_ble_name_on_event(void* context, SceneManagerEvent event) { + BadUsbApp* bad_usb = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == TextInputResultOk) { + const BadUsbHidApi* hid = bad_usb_hid_get_interface(bad_usb->interface); + // Apply to current script config + strlcpy( + bad_usb->script_hid_cfg.ble.name, + bad_usb->ble_name_buf, + sizeof(bad_usb->script_hid_cfg.ble.name)); + hid->adjust_config(&bad_usb->script_hid_cfg); + // Set in user config to save in settings file + strlcpy( + bad_usb->user_hid_cfg.ble.name, + bad_usb->ble_name_buf, + sizeof(bad_usb->user_hid_cfg.ble.name)); + } + scene_manager_previous_scene(bad_usb->scene_manager); + } + return consumed; +} + +void bad_usb_scene_config_ble_name_on_exit(void* context) { + BadUsbApp* bad_usb = context; + TextInput* text_input = bad_usb->text_input; + + text_input_reset(text_input); +} diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config_layout.c b/applications/main/bad_usb/scenes/bad_usb_scene_config_layout.c index 3f01d7090..80ab44ab3 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_config_layout.c +++ b/applications/main/bad_usb/scenes/bad_usb_scene_config_layout.c @@ -29,21 +29,17 @@ static bool bad_usb_layout_select(BadUsbApp* bad_usb) { void bad_usb_scene_config_layout_on_enter(void* context) { BadUsbApp* bad_usb = context; - if(bad_usb_layout_select(bad_usb)) { - scene_manager_search_and_switch_to_previous_scene(bad_usb->scene_manager, BadUsbSceneWork); - } else { - scene_manager_previous_scene(bad_usb->scene_manager); - } + bad_usb_layout_select(bad_usb); + + scene_manager_previous_scene(bad_usb->scene_manager); } bool bad_usb_scene_config_layout_on_event(void* context, SceneManagerEvent event) { UNUSED(context); UNUSED(event); - // BadUsbApp* bad_usb = context; return false; } void bad_usb_scene_config_layout_on_exit(void* context) { UNUSED(context); - // BadUsbApp* bad_usb = context; } diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config_usb_name.c b/applications/main/bad_usb/scenes/bad_usb_scene_config_usb_name.c new file mode 100644 index 000000000..d0e136634 --- /dev/null +++ b/applications/main/bad_usb/scenes/bad_usb_scene_config_usb_name.c @@ -0,0 +1,86 @@ +#include "../bad_usb_app_i.h" + +enum TextInputResult { + TextInputResultOk, +}; + +static void bad_usb_scene_config_usb_name_text_input_callback(void* context) { + BadUsbApp* bad_usb = context; + + view_dispatcher_send_custom_event(bad_usb->view_dispatcher, TextInputResultOk); +} + +void bad_usb_scene_config_usb_name_on_enter(void* context) { + BadUsbApp* bad_usb = context; + TextInput* text_input = bad_usb->text_input; + + if(scene_manager_get_scene_state(bad_usb->scene_manager, BadUsbSceneConfigUsbName)) { + strlcpy( + bad_usb->usb_name_buf, + bad_usb->script_hid_cfg.usb.manuf, + sizeof(bad_usb->usb_name_buf)); + text_input_set_header_text(text_input, "Set USB manufacturer name"); + } else { + strlcpy( + bad_usb->usb_name_buf, + bad_usb->script_hid_cfg.usb.product, + sizeof(bad_usb->usb_name_buf)); + text_input_set_header_text(text_input, "Set USB product name"); + } + + text_input_set_result_callback( + text_input, + bad_usb_scene_config_usb_name_text_input_callback, + bad_usb, + bad_usb->usb_name_buf, + sizeof(bad_usb->usb_name_buf), + true); + + view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewTextInput); +} + +bool bad_usb_scene_config_usb_name_on_event(void* context, SceneManagerEvent event) { + BadUsbApp* bad_usb = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == TextInputResultOk) { + const BadUsbHidApi* hid = bad_usb_hid_get_interface(bad_usb->interface); + if(scene_manager_get_scene_state(bad_usb->scene_manager, BadUsbSceneConfigUsbName)) { + // Apply to current script config + strlcpy( + bad_usb->script_hid_cfg.usb.manuf, + bad_usb->usb_name_buf, + sizeof(bad_usb->script_hid_cfg.usb.manuf)); + hid->adjust_config(&bad_usb->script_hid_cfg); + // Set in user config to save in settings file + strlcpy( + bad_usb->user_hid_cfg.usb.manuf, + bad_usb->usb_name_buf, + sizeof(bad_usb->user_hid_cfg.usb.manuf)); + } else { + // Apply to current script config + strlcpy( + bad_usb->script_hid_cfg.usb.product, + bad_usb->usb_name_buf, + sizeof(bad_usb->script_hid_cfg.usb.product)); + hid->adjust_config(&bad_usb->script_hid_cfg); + // Set in user config to save in settings file + strlcpy( + bad_usb->user_hid_cfg.usb.product, + bad_usb->usb_name_buf, + sizeof(bad_usb->user_hid_cfg.usb.product)); + } + } + scene_manager_previous_scene(bad_usb->scene_manager); + } + return consumed; +} + +void bad_usb_scene_config_usb_name_on_exit(void* context) { + BadUsbApp* bad_usb = context; + TextInput* text_input = bad_usb->text_input; + + text_input_reset(text_input); +} diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config_usb_vidpid.c b/applications/main/bad_usb/scenes/bad_usb_scene_config_usb_vidpid.c new file mode 100644 index 000000000..ce0c51a47 --- /dev/null +++ b/applications/main/bad_usb/scenes/bad_usb_scene_config_usb_vidpid.c @@ -0,0 +1,59 @@ +#include "../bad_usb_app_i.h" + +enum ByteInputResult { + ByteInputResultOk, +}; + +void bad_usb_scene_config_usb_vidpid_byte_input_callback(void* context) { + BadUsbApp* bad_usb = context; + + view_dispatcher_send_custom_event(bad_usb->view_dispatcher, ByteInputResultOk); +} + +void bad_usb_scene_config_usb_vidpid_on_enter(void* context) { + BadUsbApp* bad_usb = context; + ByteInput* byte_input = bad_usb->byte_input; + + bad_usb->usb_vidpid_buf[0] = __builtin_bswap16(bad_usb->script_hid_cfg.usb.vid); + bad_usb->usb_vidpid_buf[1] = __builtin_bswap16(bad_usb->script_hid_cfg.usb.pid); + byte_input_set_header_text(byte_input, "Set USB VID:PID"); + + byte_input_set_result_callback( + byte_input, + bad_usb_scene_config_usb_vidpid_byte_input_callback, + NULL, + bad_usb, + (void*)bad_usb->usb_vidpid_buf, + sizeof(bad_usb->usb_vidpid_buf)); + + view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewByteInput); +} + +bool bad_usb_scene_config_usb_vidpid_on_event(void* context, SceneManagerEvent event) { + BadUsbApp* bad_usb = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == ByteInputResultOk) { + const BadUsbHidApi* hid = bad_usb_hid_get_interface(bad_usb->interface); + // Apply to current script config + bad_usb->script_hid_cfg.usb.vid = __builtin_bswap16(bad_usb->usb_vidpid_buf[0]); + bad_usb->script_hid_cfg.usb.pid = __builtin_bswap16(bad_usb->usb_vidpid_buf[1]); + hid->adjust_config(&bad_usb->script_hid_cfg); + // Set in user config to save in settings file + bad_usb->user_hid_cfg.usb.vid = bad_usb->script_hid_cfg.usb.vid; + bad_usb->user_hid_cfg.usb.pid = bad_usb->script_hid_cfg.usb.pid; + } + scene_manager_previous_scene(bad_usb->scene_manager); + } + return consumed; +} + +void bad_usb_scene_config_usb_vidpid_on_exit(void* context) { + BadUsbApp* bad_usb = context; + ByteInput* byte_input = bad_usb->byte_input; + + byte_input_set_result_callback(byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(byte_input, ""); +} diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_confirm_unpair.c b/applications/main/bad_usb/scenes/bad_usb_scene_confirm_unpair.c index b8fd993e2..cd600386c 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_confirm_unpair.c +++ b/applications/main/bad_usb/scenes/bad_usb_scene_confirm_unpair.c @@ -36,7 +36,8 @@ bool bad_usb_scene_confirm_unpair_on_event(void* context, SceneManagerEvent even if(event.type == SceneManagerEventTypeCustom) { consumed = true; if(event.event == GuiButtonTypeRight) { - scene_manager_next_scene(scene_manager, BadUsbSceneUnpairDone); + bad_usb_hid_ble_remove_pairing(); + scene_manager_next_scene(scene_manager, BadUsbSceneDone); } else if(event.event == GuiButtonTypeLeft) { scene_manager_previous_scene(scene_manager); } diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_unpair_done.c b/applications/main/bad_usb/scenes/bad_usb_scene_done.c similarity index 67% rename from applications/main/bad_usb/scenes/bad_usb_scene_unpair_done.c rename to applications/main/bad_usb/scenes/bad_usb_scene_done.c index 9583f9bfb..9a878d889 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_unpair_done.c +++ b/applications/main/bad_usb/scenes/bad_usb_scene_done.c @@ -1,19 +1,17 @@ #include "../bad_usb_app_i.h" -static void bad_usb_scene_unpair_done_popup_callback(void* context) { +static void bad_usb_scene_done_popup_callback(void* context) { BadUsbApp* bad_usb = context; scene_manager_search_and_switch_to_previous_scene(bad_usb->scene_manager, BadUsbSceneConfig); } -void bad_usb_scene_unpair_done_on_enter(void* context) { +void bad_usb_scene_done_on_enter(void* context) { BadUsbApp* bad_usb = context; Popup* popup = bad_usb->popup; - bad_usb_hid_ble_remove_pairing(); - popup_set_icon(popup, 48, 4, &I_DolphinDone_80x58); popup_set_header(popup, "Done", 20, 19, AlignLeft, AlignBottom); - popup_set_callback(popup, bad_usb_scene_unpair_done_popup_callback); + popup_set_callback(popup, bad_usb_scene_done_popup_callback); popup_set_context(popup, bad_usb); popup_set_timeout(popup, 1500); popup_enable_timeout(popup); @@ -21,7 +19,7 @@ void bad_usb_scene_unpair_done_on_enter(void* context) { view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewPopup); } -bool bad_usb_scene_unpair_done_on_event(void* context, SceneManagerEvent event) { +bool bad_usb_scene_done_on_event(void* context, SceneManagerEvent event) { BadUsbApp* bad_usb = context; UNUSED(bad_usb); UNUSED(event); @@ -30,7 +28,7 @@ bool bad_usb_scene_unpair_done_on_event(void* context, SceneManagerEvent event) return consumed; } -void bad_usb_scene_unpair_done_on_exit(void* context) { +void bad_usb_scene_done_on_exit(void* context) { BadUsbApp* bad_usb = context; Popup* popup = bad_usb->popup; UNUSED(popup); diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c b/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c index 5e2c3f14b..9aa6f3eea 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c +++ b/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c @@ -1,5 +1,4 @@ #include "../bad_usb_app_i.h" -#include #include static bool bad_usb_file_select(BadUsbApp* bad_usb) { @@ -27,6 +26,7 @@ void bad_usb_scene_file_select_on_enter(void* context) { } if(bad_usb_file_select(bad_usb)) { + scene_manager_set_scene_state(bad_usb->scene_manager, BadUsbSceneWork, true); scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneWork); } else { view_dispatcher_stop(bad_usb->view_dispatcher); @@ -36,11 +36,9 @@ void bad_usb_scene_file_select_on_enter(void* context) { bool bad_usb_scene_file_select_on_event(void* context, SceneManagerEvent event) { UNUSED(context); UNUSED(event); - // BadUsbApp* bad_usb = context; return false; } void bad_usb_scene_file_select_on_exit(void* context) { UNUSED(context); - // BadUsbApp* bad_usb = context; } diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_work.c b/applications/main/bad_usb/scenes/bad_usb_scene_work.c index 0382b0f8e..d57f7eb33 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_work.c +++ b/applications/main/bad_usb/scenes/bad_usb_scene_work.c @@ -20,11 +20,8 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) { bad_usb_script_close(app->bad_usb_script); app->bad_usb_script = NULL; - if(app->interface == BadUsbHidInterfaceBle) { - scene_manager_next_scene(app->scene_manager, BadUsbSceneConfig); - } else { - scene_manager_next_scene(app->scene_manager, BadUsbSceneConfigLayout); - } + scene_manager_set_scene_state(app->scene_manager, BadUsbSceneConfig, 0); + scene_manager_next_scene(app->scene_manager, BadUsbSceneConfig); } consumed = true; } else if(event.event == InputKeyOk) { @@ -37,7 +34,9 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) { app->interface == BadUsbHidInterfaceBle ? BadUsbHidInterfaceUsb : BadUsbHidInterfaceBle); bad_usb_script_close(app->bad_usb_script); - app->bad_usb_script = bad_usb_script_open(app->file_path, app->interface); + app->bad_usb_script = bad_usb_script_open( + app->file_path, &app->interface, &app->script_hid_cfg, false); + bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout); } else { bad_usb_script_pause_resume(app->bad_usb_script); } @@ -45,6 +44,7 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) { } } else if(event.type == SceneManagerEventTypeTick) { bad_usb_view_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script)); + bad_usb_view_set_interface(app->bad_usb_view, app->interface); } return consumed; } @@ -54,7 +54,18 @@ void bad_usb_scene_work_on_enter(void* context) { bad_usb_view_set_interface(app->bad_usb_view, app->interface); - app->bad_usb_script = bad_usb_script_open(app->file_path, app->interface); + // Opening script the first time: + // - copy user settings as base config + // - load ID/BLE_ID/BT_ID config if present + // Then disable this until next script selected so user can customize options + bool first_script_load = scene_manager_get_scene_state(app->scene_manager, BadUsbSceneWork); + if(first_script_load) { + memcpy(&app->script_hid_cfg, &app->user_hid_cfg, sizeof(app->script_hid_cfg)); + scene_manager_set_scene_state(app->scene_manager, BadUsbSceneWork, false); + } + // Interface and config are passed as pointers as ID/BLE_ID/BT_ID config can modify them + app->bad_usb_script = bad_usb_script_open( + app->file_path, &app->interface, &app->script_hid_cfg, first_script_load); bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout); FuriString* file_name; diff --git a/applications/main/bad_usb/views/bad_usb_view.c b/applications/main/bad_usb/views/bad_usb_view.c index 1a6f77958..4032ea974 100644 --- a/applications/main/bad_usb/views/bad_usb_view.c +++ b/applications/main/bad_usb/views/bad_usb_view.c @@ -24,8 +24,7 @@ typedef struct { static void bad_usb_draw_callback(Canvas* canvas, void* _model) { BadUsbModel* model = _model; - FuriString* disp_str; - disp_str = furi_string_alloc_set(model->file_name); + FuriString* disp_str = furi_string_alloc_set(model->file_name); elements_string_fit_width(canvas, disp_str, 128 - 2); canvas_set_font(canvas, FontSecondary); canvas_draw_str(canvas, 2, 8, furi_string_get_cstr(disp_str)); @@ -35,6 +34,8 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { } else { furi_string_printf(disp_str, "(%s)", model->layout); } + uint32_t e = model->state.elapsed; + furi_string_cat_printf(disp_str, " %02lu:%02lu.%ld", e / 60 / 1000, e / 1000, e % 1000); elements_string_fit_width(canvas, disp_str, 128 - 2); canvas_draw_str( canvas, 2, 8 + canvas_current_font_height(canvas), furi_string_get_cstr(disp_str)); @@ -52,13 +53,8 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { if((state == BadUsbStateIdle) || (state == BadUsbStateDone) || (state == BadUsbStateNotConnected)) { elements_button_center(canvas, "Run"); - if(model->interface == BadUsbHidInterfaceBle) { - elements_button_right(canvas, "USB"); - elements_button_left(canvas, "Config"); - } else { - elements_button_right(canvas, "BLE"); - elements_button_left(canvas, "Layout"); - } + elements_button_left(canvas, "Config"); + elements_button_right(canvas, model->interface == BadUsbHidInterfaceBle ? "USB" : "BLE"); } else if((state == BadUsbStateRunning) || (state == BadUsbStateDelay)) { elements_button_center(canvas, "Stop"); if(!model->pause_wait) { @@ -90,77 +86,85 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "ERROR"); } else if(state == BadUsbStateScriptError) { canvas_draw_icon(canvas, 4, 26, &I_Error_18x18); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 127, 33, AlignRight, AlignBottom, "ERROR:"); - canvas_set_font(canvas, FontSecondary); furi_string_printf(disp_str, "line %zu", model->state.error_line); canvas_draw_str_aligned( canvas, 127, 46, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); - furi_string_reset(disp_str); - furi_string_set_str(disp_str, model->state.error); elements_string_fit_width(canvas, disp_str, canvas_width(canvas)); canvas_draw_str_aligned( canvas, 127, 56, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); - furi_string_reset(disp_str); + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 127, 33, AlignRight, AlignBottom, "ERROR:"); } else if(state == BadUsbStateIdle) { canvas_draw_icon(canvas, 4, 26, &I_Smile_18x18); + furi_string_printf(disp_str, "0/%zu", model->state.line_nb); + canvas_draw_str_aligned( + canvas, 124, 47, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); canvas_set_font(canvas, FontBigNumbers); - canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "0"); - canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); + canvas_draw_str_aligned(canvas, 112, 37, AlignRight, AlignBottom, "0"); + canvas_draw_icon(canvas, 115, 23, &I_Percent_10x14); } else if(state == BadUsbStateRunning) { if(model->anim_frame == 0) { canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21); } else { canvas_draw_icon(canvas, 4, 23, &I_EviSmile2_18x21); } + furi_string_printf(disp_str, "%zu/%zu", model->state.line_cur, model->state.line_nb); + canvas_draw_str_aligned( + canvas, 124, 47, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); canvas_set_font(canvas, FontBigNumbers); furi_string_printf( disp_str, "%zu", ((model->state.line_cur - 1) * 100) / model->state.line_nb); canvas_draw_str_aligned( - canvas, 114, 40, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); - furi_string_reset(disp_str); - canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); + canvas, 112, 37, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); + canvas_draw_icon(canvas, 115, 23, &I_Percent_10x14); } else if(state == BadUsbStateDone) { canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21); + furi_string_printf(disp_str, "%zu/%zu", model->state.line_nb, model->state.line_nb); + canvas_draw_str_aligned( + canvas, 124, 47, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); canvas_set_font(canvas, FontBigNumbers); - canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "100"); - furi_string_reset(disp_str); - canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); + canvas_draw_str_aligned(canvas, 112, 37, AlignRight, AlignBottom, "100"); + canvas_draw_icon(canvas, 115, 23, &I_Percent_10x14); } else if(state == BadUsbStateDelay) { if(model->anim_frame == 0) { canvas_draw_icon(canvas, 4, 23, &I_EviWaiting1_18x21); } else { canvas_draw_icon(canvas, 4, 23, &I_EviWaiting2_18x21); } + uint32_t delay = model->state.delay_remain / 10; + if(delay) { + furi_string_printf(disp_str, "Delay %lus", delay); + canvas_draw_str_aligned( + canvas, 4, 61, AlignLeft, AlignBottom, furi_string_get_cstr(disp_str)); + } + furi_string_printf(disp_str, "%zu/%zu", model->state.line_cur, model->state.line_nb); + canvas_draw_str_aligned( + canvas, 124, 47, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); canvas_set_font(canvas, FontBigNumbers); furi_string_printf( disp_str, "%zu", ((model->state.line_cur - 1) * 100) / model->state.line_nb); canvas_draw_str_aligned( - canvas, 114, 40, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); - furi_string_reset(disp_str); - canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); - canvas_set_font(canvas, FontSecondary); - furi_string_printf(disp_str, "delay %lus", model->state.delay_remain); - canvas_draw_str_aligned( - canvas, 127, 50, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); - furi_string_reset(disp_str); + canvas, 112, 37, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); + canvas_draw_icon(canvas, 115, 23, &I_Percent_10x14); } else if((state == BadUsbStatePaused) || (state == BadUsbStateWaitForBtn)) { if(model->anim_frame == 0) { canvas_draw_icon(canvas, 4, 23, &I_EviWaiting1_18x21); } else { canvas_draw_icon(canvas, 4, 23, &I_EviWaiting2_18x21); } + if(state != BadUsbStateWaitForBtn) { + canvas_draw_str_aligned(canvas, 4, 61, AlignLeft, AlignBottom, "Paused"); + } + furi_string_printf(disp_str, "%zu/%zu", model->state.line_cur, model->state.line_nb); + canvas_draw_str_aligned( + canvas, 124, 47, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); canvas_set_font(canvas, FontBigNumbers); furi_string_printf( disp_str, "%zu", ((model->state.line_cur - 1) * 100) / model->state.line_nb); canvas_draw_str_aligned( - canvas, 114, 40, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); - furi_string_reset(disp_str); - canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned(canvas, 127, 50, AlignRight, AlignBottom, "Paused"); - furi_string_reset(disp_str); + canvas, 112, 37, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); + canvas_draw_icon(canvas, 115, 23, &I_Percent_10x14); } else { canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18); } diff --git a/lib/ble_profile/extra_profiles/hid_profile.c b/lib/ble_profile/extra_profiles/hid_profile.c index ea90d3114..ed67f44a1 100644 --- a/lib/ble_profile/extra_profiles/hid_profile.c +++ b/lib/ble_profile/extra_profiles/hid_profile.c @@ -9,12 +9,12 @@ #include #include -#define HID_INFO_BASE_USB_SPECIFICATION (0x0101) -#define HID_INFO_COUNTRY_CODE (0x00) -#define BLE_PROFILE_HID_INFO_FLAG_REMOTE_WAKE_MSK (0x01) +#define HID_INFO_BASE_USB_SPECIFICATION (0x0101) +#define HID_INFO_COUNTRY_CODE (0x00) +#define BLE_PROFILE_HID_INFO_FLAG_REMOTE_WAKE_MSK (0x01) #define BLE_PROFILE_HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK (0x02) -#define BLE_PROFILE_HID_KB_MAX_KEYS (6) +#define BLE_PROFILE_HID_KB_MAX_KEYS (6) #define BLE_PROFILE_CONSUMER_MAX_KEYS (1) // Report ids cant be 0 @@ -380,10 +380,11 @@ bool ble_profile_hid_mouse_scroll(FuriHalBleProfileBase* profile, int8_t delta) #define CONNECTION_INTERVAL_MAX (0x24) static GapConfig template_config = { - .adv_service = { - .UUID_Type = UUID_TYPE_16, - .Service_UUID_16 = HUMAN_INTERFACE_DEVICE_SERVICE_UUID, - }, + .adv_service = + { + .UUID_Type = UUID_TYPE_16, + .Service_UUID_16 = HUMAN_INTERFACE_DEVICE_SERVICE_UUID, + }, .appearance_char = GAP_APPEARANCE_KEYBOARD, .bonding_mode = true, .pairing_method = GapPairingPinCodeVerifyYesNo, @@ -412,19 +413,17 @@ static void ble_profile_hid_get_config(GapConfig* config, FuriHalBleProfileParam } // Set advertise name - memset(config->adv_name, 0, sizeof(config->adv_name)); - FuriString* name = furi_string_alloc_set(furi_hal_version_get_ble_local_device_name_ptr()); - const char* clicker_str = "Control"; if(hid_profile_params && hid_profile_params->device_name_prefix) { clicker_str = hid_profile_params->device_name_prefix; } - furi_string_replace_str(name, "Flipper", clicker_str); - if(furi_string_size(name) >= sizeof(config->adv_name)) { - furi_string_left(name, sizeof(config->adv_name) - 1); - } - memcpy(config->adv_name, furi_string_get_cstr(name), furi_string_size(name)); - furi_string_free(name); + snprintf( + config->adv_name, + sizeof(config->adv_name), + "%c%s %s", + furi_hal_version_get_ble_local_device_name_ptr()[0], + clicker_str, + furi_hal_version_get_name_ptr()); } static const FuriHalBleProfileTemplate profile_callbacks = { diff --git a/targets/f7/furi_hal/furi_hal_usb_hid.c b/targets/f7/furi_hal/furi_hal_usb_hid.c index c83261226..04f2ae400 100644 --- a/targets/f7/furi_hal/furi_hal_usb_hid.c +++ b/targets/f7/furi_hal/furi_hal_usb_hid.c @@ -12,9 +12,6 @@ #define HID_INTERVAL 2 -#define HID_VID_DEFAULT 0x046D -#define HID_PID_DEFAULT 0xC529 - struct HidIntfDescriptor { struct usb_interface_descriptor hid; struct usb_hid_descriptor hid_desc; diff --git a/targets/furi_hal_include/furi_hal_usb_hid.h b/targets/furi_hal_include/furi_hal_usb_hid.h index af4a542de..19c9ed659 100644 --- a/targets/furi_hal_include/furi_hal_usb_hid.h +++ b/targets/furi_hal_include/furi_hal_usb_hid.h @@ -9,6 +9,11 @@ extern "C" { #endif +#define HID_MANUF_PRODUCT_NAME_LEN 32 + +#define HID_VID_DEFAULT 0x046D +#define HID_PID_DEFAULT 0xC529 + /** Max number of simultaneously pressed keys (keyboard) */ #define HID_KB_MAX_KEYS 6 /** Max number of simultaneously pressed keys (consumer control) */ @@ -166,10 +171,11 @@ static const uint16_t hid_asciimap[] = { }; typedef struct { + // Note: vid/pid should be uint16_t and are treated as such uint32_t vid; uint32_t pid; - char manuf[32]; - char product[32]; + char manuf[HID_MANUF_PRODUCT_NAME_LEN]; + char product[HID_MANUF_PRODUCT_NAME_LEN]; } FuriHalUsbHidConfig; typedef void (*HidStateCallback)(bool state, void* context); diff --git a/targets/furi_hal_include/furi_hal_version.h b/targets/furi_hal_include/furi_hal_version.h index 2c098d482..1d026539a 100644 --- a/targets/furi_hal_include/furi_hal_version.h +++ b/targets/furi_hal_include/furi_hal_version.h @@ -14,11 +14,12 @@ extern "C" { #endif -#define FURI_HAL_VERSION_NAME_LENGTH 8 -#define FURI_HAL_VERSION_ARRAY_NAME_LENGTH (FURI_HAL_VERSION_NAME_LENGTH + 1) -#define FURI_HAL_BT_ADV_NAME_LENGTH (18 + 1) // 18 characters + null terminator -#define FURI_HAL_VERSION_DEVICE_NAME_LENGTH \ - (1 + FURI_HAL_BT_ADV_NAME_LENGTH) // Used for custom BT name, BLE symbol + name +#define FURI_HAL_VERSION_NAME_LENGTH (8) +#define FURI_HAL_VERSION_ARRAY_NAME_LENGTH (FURI_HAL_VERSION_NAME_LENGTH + 1) +/** 31b BLE Adv - 3b flags - 2b name prefix - 4b service uuid - 3b tx power = 19, + 1b null terminator (not present in packet) */ +#define FURI_HAL_BT_ADV_NAME_LENGTH (20) +/** BLE symbol + name */ +#define FURI_HAL_VERSION_DEVICE_NAME_LENGTH (1 + FURI_HAL_BT_ADV_NAME_LENGTH) /** OTP Versions enum */ typedef enum { From 831e46c052a9256fd3baa2109c3f43e6b0106a0c Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 6 Apr 2025 06:18:30 +0300 Subject: [PATCH 068/125] upd changelog --- CHANGELOG.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 618589cf0..e98d1eeb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ ## Main changes -- Current API: 83.0 +- Current API: 85.0 * SubGHz: Add **Revers RB2 / RB2M Protocol** (static 64 bit) **full support** with add manually (by @xMasterX) * SubGHz: **Fix Hollarm protocol with more verification** * SubGHz: **Fix GangQi protocol** (by @DoberBit and @mishamyte (who spent 2 weeks on this)) @@ -9,6 +9,7 @@ * OFW: LFRFID - **EM4305 support** * OFW: **Universal IR signal selection** * OFW: **BadUSB: Mouse control** +* OFW PR 4136: BadUSB: Full USB/BLE parameter customization, UI improvements, and more (by @Willy-JL) * OFW: NFC - Added naming for DESFire cards + fix MF3ICD40 cards unable to be read * Apps: Add **FindMyFlipper to system apps and allow autostart** on system boot [app by @MatthewKuKanich](https://github.com/MatthewKuKanich/FindMyFlipper) and autoloader by @Willy-JL - to use app please check how to add keys in [app repo](https://github.com/MatthewKuKanich/FindMyFlipper) * README Update: Enhanced Visuals & Navigation (PR #871 #872 | by @m-xim) @@ -20,6 +21,19 @@ * SubGHz: Various bugfixes and experimental options (rolling counter overflow) (by @xMasterX) * Anims: Disable winter anims * NFC: mfclassic poller fix early key reuse in dictionary attack state machine (by @noproto) +* OFW: BadUSB arbitrary key combinations +* OFW: JS: Update and fix docs, fix Number.toString() with decimals +* OFW: New JS value destructuring +* OFW: Docs: Fix doxygen references from PR 4168 +* OFW: BLE advertising improvements +* OFW: **New CLI architecture** +* OFW: **CLI autocomplete and other sugar** +* OFW: CLI commands in fals and threads +* OFW: cli: fixed `free_blocks` command +* OFW: docs: badusb arbitrary modkey chains +* OFW: Separate cli_shell into toolbox +* OFW: Move JS modules to new arg parser +* OFW: Application chaining * OFW: Fix DWARF dead code elimination and linking * OFW: NFC: Fix crash on ISO15693-3 save when memory is empty or cannot be read * OFW: Reduced ieee754 parser size From ada8473932d804e17049fa05468498c9e9425c67 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 7 Apr 2025 01:06:14 +0300 Subject: [PATCH 069/125] upd changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e98d1eeb6..7a7ca55f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ * SubGHz: Various bugfixes and experimental options (rolling counter overflow) (by @xMasterX) * Anims: Disable winter anims * NFC: mfclassic poller fix early key reuse in dictionary attack state machine (by @noproto) +* OFW: NFC app now can launch MFKey32 * OFW: BadUSB arbitrary key combinations * OFW: JS: Update and fix docs, fix Number.toString() with decimals * OFW: New JS value destructuring From fa0962efebf9318066a771aa8dbd300f0b5fa8d0 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 7 Apr 2025 18:24:33 +0300 Subject: [PATCH 070/125] integrate mfkey to system apps --- applications/system/mfkey/application.fam | 28 + applications/system/mfkey/crypto1.c | 22 + applications/system/mfkey/crypto1.h | 256 ++++++ applications/system/mfkey/images/mfkey.png | Bin 0 -> 107 bytes applications/system/mfkey/init_plugin.c | 356 ++++++++ applications/system/mfkey/mfkey.c | 915 +++++++++++++++++++ applications/system/mfkey/mfkey.h | 108 +++ applications/system/mfkey/mfkey.png | Bin 0 -> 107 bytes applications/system/mfkey/plugin_interface.h | 13 + 9 files changed, 1698 insertions(+) create mode 100644 applications/system/mfkey/application.fam create mode 100644 applications/system/mfkey/crypto1.c create mode 100644 applications/system/mfkey/crypto1.h create mode 100644 applications/system/mfkey/images/mfkey.png create mode 100644 applications/system/mfkey/init_plugin.c create mode 100644 applications/system/mfkey/mfkey.c create mode 100644 applications/system/mfkey/mfkey.h create mode 100644 applications/system/mfkey/mfkey.png create mode 100644 applications/system/mfkey/plugin_interface.h diff --git a/applications/system/mfkey/application.fam b/applications/system/mfkey/application.fam new file mode 100644 index 000000000..dfd513847 --- /dev/null +++ b/applications/system/mfkey/application.fam @@ -0,0 +1,28 @@ +App( + appid="mfkey", + name="MFKey", + apptype=FlipperAppType.EXTERNAL, + targets=["f7"], + entry_point="mfkey_main", + requires=[ + "gui", + "storage", + ], + stack_size=1 * 1024, + fap_icon="mfkey.png", + fap_category="NFC", + fap_author="@noproto", + fap_icon_assets="images", + fap_weburl="https://github.com/noproto/FlipperMfkey", + fap_description="MIFARE Classic key recovery tool", + fap_version="3.0", +) + +App( + appid="mfkey_init_plugin", + apptype=FlipperAppType.PLUGIN, + entry_point="init_plugin_ep", + requires=["mfkey"], + sources=["init_plugin.c"], + fal_embedded=True, +) diff --git a/applications/system/mfkey/crypto1.c b/applications/system/mfkey/crypto1.c new file mode 100644 index 000000000..e862b14d1 --- /dev/null +++ b/applications/system/mfkey/crypto1.c @@ -0,0 +1,22 @@ +#pragma GCC optimize("O3") +#pragma GCC optimize("-funroll-all-loops") + +#include +#include "crypto1.h" +#include "mfkey.h" + +#define BIT(x, n) ((x) >> (n) & 1) + +void crypto1_get_lfsr(struct Crypto1State* state, MfClassicKey* lfsr) { + int i; + uint64_t lfsr_value = 0; + for(i = 23; i >= 0; --i) { + lfsr_value = lfsr_value << 1 | BIT(state->odd, i ^ 3); + lfsr_value = lfsr_value << 1 | BIT(state->even, i ^ 3); + } + + // Assign the key value to the MfClassicKey struct + for(i = 0; i < 6; ++i) { + lfsr->data[i] = (lfsr_value >> ((5 - i) * 8)) & 0xFF; + } +} diff --git a/applications/system/mfkey/crypto1.h b/applications/system/mfkey/crypto1.h new file mode 100644 index 000000000..9caf5b35e --- /dev/null +++ b/applications/system/mfkey/crypto1.h @@ -0,0 +1,256 @@ +#ifndef CRYPTO1_H +#define CRYPTO1_H + +#include +#include "mfkey.h" +#include +#include + +#define LF_POLY_ODD (0x29CE5C) +#define LF_POLY_EVEN (0x870804) +#define BIT(x, n) ((x) >> (n) & 1) +#define BEBIT(x, n) BIT(x, (n) ^ 24) +#define SWAPENDIAN(x) \ + ((x) = ((x) >> 8 & 0xff00ff) | ((x) & 0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16) + +static inline uint32_t prng_successor(uint32_t x, uint32_t n); +static inline int filter(uint32_t const x); +static inline uint8_t evenparity32(uint32_t x); +static inline void update_contribution(unsigned int data[], int item, int mask1, int mask2); +void crypto1_get_lfsr(struct Crypto1State* state, MfClassicKey* lfsr); +static inline uint32_t crypt_word(struct Crypto1State* s); +static inline void crypt_word_noret(struct Crypto1State* s, uint32_t in, int x); +static inline uint32_t crypt_word_ret(struct Crypto1State* s, uint32_t in, int x); +static uint32_t crypt_word_par( + struct Crypto1State* s, + uint32_t in, + int is_encrypted, + uint32_t nt_plain, + uint8_t* parity_keystream_bits); +static inline void rollback_word_noret(struct Crypto1State* s, uint32_t in, int x); +static inline uint8_t napi_lfsr_rollback_bit(struct Crypto1State* s, uint32_t in, int fb); +static inline uint32_t napi_lfsr_rollback_word(struct Crypto1State* s, uint32_t in, int fb); + +static const uint8_t lookup1[256] = { + 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, + 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, + 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, 8, 8, 24, 24, 8, 24, 8, 8, + 8, 24, 8, 8, 24, 24, 24, 24, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, + 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, + 0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, + 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, + 0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, + 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, 0, 0, 16, 16, 0, 16, 0, 0, + 0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, + 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24}; +static const uint8_t lookup2[256] = { + 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, + 4, 4, 4, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, + 2, 2, 6, 6, 6, 6, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 2, 2, 6, 6, 2, 6, 2, + 2, 2, 6, 2, 2, 6, 6, 6, 6, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 0, 0, 4, 4, + 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 2, + 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, + 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, + 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, + 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6}; + +static inline int filter(uint32_t const x) { + uint32_t f; + f = lookup1[x & 0xff] | lookup2[(x >> 8) & 0xff]; + f |= 0x0d938 >> (x >> 16 & 0xf) & 1; + return BIT(0xEC57E80A, f); +} + +#ifndef __ARM_ARCH_7EM__ +static inline uint8_t evenparity32(uint32_t x) { + return __builtin_parity(x); +} +#endif + +#ifdef __ARM_ARCH_7EM__ +static inline uint8_t evenparity32(uint32_t x) { + uint32_t result; + __asm__ volatile("eor r1, %[x], %[x], lsr #16 \n\t" // r1 = x ^ (x >> 16) + "eor r1, r1, r1, lsr #8 \n\t" // r1 = r1 ^ (r1 >> 8) + "eor r1, r1, r1, lsr #4 \n\t" // r1 = r1 ^ (r1 >> 4) + "eor r1, r1, r1, lsr #2 \n\t" // r1 = r1 ^ (r1 >> 2) + "eor r1, r1, r1, lsr #1 \n\t" // r1 = r1 ^ (r1 >> 1) + "and %[result], r1, #1 \n\t" // result = r1 & 1 + : [result] "=r"(result) + : [x] "r"(x) + : "r1"); + return result; +} +#endif + +static inline void update_contribution(unsigned int data[], int item, int mask1, int mask2) { + int p = data[item] >> 25; + p = p << 1 | evenparity32(data[item] & mask1); + p = p << 1 | evenparity32(data[item] & mask2); + data[item] = p << 24 | (data[item] & 0xffffff); +} + +static inline uint32_t crypt_word(struct Crypto1State* s) { + // "in" and "x" are always 0 (last iteration) + uint32_t res_ret = 0; + uint32_t feedin, t; + for(int i = 0; i <= 31; i++) { + res_ret |= (filter(s->odd) << (24 ^ i)); //-V629 + feedin = LF_POLY_EVEN & s->even; + feedin ^= LF_POLY_ODD & s->odd; + s->even = s->even << 1 | (evenparity32(feedin)); + t = s->odd, s->odd = s->even, s->even = t; + } + return res_ret; +} + +static inline void crypt_word_noret(struct Crypto1State* s, uint32_t in, int x) { + uint8_t ret; + uint32_t feedin, t, next_in; + for(int i = 0; i <= 31; i++) { + next_in = BEBIT(in, i); + ret = filter(s->odd); + feedin = ret & (!!x); + feedin ^= LF_POLY_EVEN & s->even; + feedin ^= LF_POLY_ODD & s->odd; + feedin ^= !!next_in; + s->even = s->even << 1 | (evenparity32(feedin)); + t = s->odd, s->odd = s->even, s->even = t; + } + return; +} + +static inline uint32_t crypt_word_ret(struct Crypto1State* s, uint32_t in, int x) { + uint32_t ret = 0; + uint32_t feedin, t, next_in; + uint8_t next_ret; + for(int i = 0; i <= 31; i++) { + next_in = BEBIT(in, i); + next_ret = filter(s->odd); + feedin = next_ret & (!!x); + feedin ^= LF_POLY_EVEN & s->even; + feedin ^= LF_POLY_ODD & s->odd; + feedin ^= !!next_in; + s->even = s->even << 1 | (evenparity32(feedin)); + t = s->odd, s->odd = s->even, s->even = t; + ret |= next_ret << (24 ^ i); + } + return ret; +} + +static uint8_t get_nth_byte(uint32_t value, int n) { + if(n < 0 || n > 3) { + // Handle invalid input + return 0; + } + return (value >> (8 * (3 - n))) & 0xFF; +} + +static uint8_t crypt_bit(struct Crypto1State* s, uint8_t in, int is_encrypted) { + uint32_t feedin, t; + uint8_t ret = filter(s->odd); + feedin = ret & !!is_encrypted; + feedin ^= !!in; + feedin ^= LF_POLY_ODD & s->odd; + feedin ^= LF_POLY_EVEN & s->even; + s->even = s->even << 1 | evenparity32(feedin); + t = s->odd, s->odd = s->even, s->even = t; + return ret; +} + +static inline uint32_t crypt_word_par( + struct Crypto1State* s, + uint32_t in, + int is_encrypted, + uint32_t nt_plain, + uint8_t* parity_keystream_bits) { + uint32_t ret = 0; + *parity_keystream_bits = 0; // Reset parity keystream bits + + for(int i = 0; i < 32; i++) { + uint8_t bit = crypt_bit(s, BEBIT(in, i), is_encrypted); + ret |= bit << (24 ^ i); + // Save keystream parity bit + if((i + 1) % 8 == 0) { + *parity_keystream_bits |= + (filter(s->odd) ^ nfc_util_even_parity8(get_nth_byte(nt_plain, i / 8))) + << (3 - (i / 8)); + } + } + return ret; +} + +static inline void rollback_word_noret(struct Crypto1State* s, uint32_t in, int x) { + uint8_t ret; + uint32_t feedin, t, next_in; + for(int i = 31; i >= 0; i--) { + next_in = BEBIT(in, i); + s->odd &= 0xffffff; + t = s->odd, s->odd = s->even, s->even = t; + ret = filter(s->odd); + feedin = ret & (!!x); + feedin ^= s->even & 1; + feedin ^= LF_POLY_EVEN & (s->even >>= 1); + feedin ^= LF_POLY_ODD & s->odd; + feedin ^= !!next_in; + s->even |= (evenparity32(feedin)) << 23; + } + return; +} + +// TODO: +/* +uint32_t rollback_word(struct Crypto1State *s, uint32_t in, int x) { + uint32_t res_ret = 0; + uint8_t ret; + uint32_t feedin, t, next_in; + for (int i = 31; i >= 0; i--) { + next_in = BEBIT(in, i); + s->odd &= 0xffffff; + t = s->odd, s->odd = s->even, s->even = t; + ret = filter(s->odd); + feedin = ret & (!!x); + feedin ^= s->even & 1; + feedin ^= LF_POLY_EVEN & (s->even >>= 1); + feedin ^= LF_POLY_ODD & s->odd; + feedin ^= !!next_in; + s->even |= (evenparity32(feedin)) << 23; + res_ret |= (ret << (24 ^ i)); + } + return res_ret; +} +*/ + +uint8_t napi_lfsr_rollback_bit(struct Crypto1State* s, uint32_t in, int fb) { + int out; + uint8_t ret; + uint32_t t; + s->odd &= 0xffffff; + t = s->odd, s->odd = s->even, s->even = t; + + out = s->even & 1; + out ^= LF_POLY_EVEN & (s->even >>= 1); + out ^= LF_POLY_ODD & s->odd; + out ^= !!in; + out ^= (ret = filter(s->odd)) & !!fb; + + s->even |= evenparity32(out) << 23; + return ret; +} + +uint32_t napi_lfsr_rollback_word(struct Crypto1State* s, uint32_t in, int fb) { + int i; + uint32_t ret = 0; + for(i = 31; i >= 0; --i) + ret |= napi_lfsr_rollback_bit(s, BEBIT(in, i), fb) << (i ^ 24); + return ret; +} + +static inline uint32_t prng_successor(uint32_t x, uint32_t n) { + SWAPENDIAN(x); + while(n--) + x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; + return SWAPENDIAN(x); +} + +#endif // CRYPTO1_H diff --git a/applications/system/mfkey/images/mfkey.png b/applications/system/mfkey/images/mfkey.png new file mode 100644 index 0000000000000000000000000000000000000000..f1694bb335a8619e53cd3b98651ba995cc7a1caf GIT binary patch literal 107 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2xGmzZ=C-xtZVhivIasB`QKad%E=yDy9Qt)(f z4B@z*{KD=)L3iUrapuFX*xK~i1d{R-5*QT~m>F7Tu$Q|1zuOE{%i!ti=d#Wzp$P!I C{~rec literal 0 HcmV?d00001 diff --git a/applications/system/mfkey/init_plugin.c b/applications/system/mfkey/init_plugin.c new file mode 100644 index 000000000..8540a8f2d --- /dev/null +++ b/applications/system/mfkey/init_plugin.c @@ -0,0 +1,356 @@ +#include +#include +#include +#include +#include +#include +#include "mfkey.h" +#include "crypto1.h" +#include "plugin_interface.h" +#include + +#define TAG "MFKey" + +// TODO: Remove defines that are not needed +#define MF_CLASSIC_NONCE_PATH EXT_PATH("nfc/.mfkey32.log") +#define MF_CLASSIC_NESTED_NONCE_PATH EXT_PATH("nfc/.nested.log") +#define MAX_NAME_LEN 32 +#define MAX_PATH_LEN 64 + +#define LF_POLY_ODD (0x29CE5C) +#define LF_POLY_EVEN (0x870804) +#define CONST_M1_1 (LF_POLY_EVEN << 1 | 1) +#define CONST_M2_1 (LF_POLY_ODD << 1) +#define CONST_M1_2 (LF_POLY_ODD) +#define CONST_M2_2 (LF_POLY_EVEN << 1 | 1) +#define BIT(x, n) ((x) >> (n) & 1) +#define BEBIT(x, n) BIT(x, (n) ^ 24) +#define SWAPENDIAN(x) \ + ((x) = ((x) >> 8 & 0xff00ff) | ((x) & 0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16) + +bool key_already_found_for_nonce_in_dict(KeysDict* dict, MfClassicNonce* nonce) { + // This function must not be passed the CUID dictionary + bool found = false; + uint8_t key_bytes[sizeof(MfClassicKey)]; + keys_dict_rewind(dict); + while(keys_dict_get_next_key(dict, key_bytes, sizeof(MfClassicKey))) { + uint64_t k = bit_lib_bytes_to_num_be(key_bytes, sizeof(MfClassicKey)); + struct Crypto1State temp = {0, 0}; + for(int i = 0; i < 24; i++) { + (&temp)->odd |= (BIT(k, 2 * i + 1) << (i ^ 3)); + (&temp)->even |= (BIT(k, 2 * i) << (i ^ 3)); + } + if(nonce->attack == mfkey32) { + crypt_word_noret(&temp, nonce->uid_xor_nt1, 0); + crypt_word_noret(&temp, nonce->nr1_enc, 1); + if(nonce->ar1_enc == (crypt_word(&temp) ^ nonce->p64b)) { + found = true; + break; + } + } else if(nonce->attack == static_nested || nonce->attack == static_encrypted) { + uint32_t expected_ks1 = crypt_word_ret(&temp, nonce->uid_xor_nt0, 0); + if(nonce->ks1_1_enc == expected_ks1) { + found = true; + break; + } + } + } + return found; +} + +bool napi_mf_classic_mfkey32_nonces_check_presence() { + Storage* storage = furi_record_open(RECORD_STORAGE); + + bool nonces_present = storage_common_stat(storage, MF_CLASSIC_NONCE_PATH, NULL) == FSE_OK; + + furi_record_close(RECORD_STORAGE); + + return nonces_present; +} + +bool napi_mf_classic_nested_nonces_check_presence() { + Storage* storage = furi_record_open(RECORD_STORAGE); + Stream* stream = buffered_file_stream_alloc(storage); + bool nonces_present = false; + FuriString* line = furi_string_alloc(); + + do { + if(!buffered_file_stream_open( + stream, MF_CLASSIC_NESTED_NONCE_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { + break; + } + + while(stream_read_line(stream, line)) { + if(furi_string_search_str(line, "dist 0") != FURI_STRING_FAILURE) { + nonces_present = true; + break; + } + } + + } while(false); + + furi_string_free(line); + buffered_file_stream_close(stream); + stream_free(stream); + furi_record_close(RECORD_STORAGE); + + return nonces_present; +} + +int binaryStringToInt(const char* binStr) { + int result = 0; + while(*binStr) { + result <<= 1; + if(*binStr == '1') { + result |= 1; + } + binStr++; + } + return result; +} + +bool load_mfkey32_nonces( + MfClassicNonceArray* nonce_array, + ProgramState* program_state, + KeysDict* system_dict, + bool system_dict_exists, + KeysDict* user_dict) { + bool array_loaded = false; + + do { + // https://github.com/flipperdevices/flipperzero-firmware/blob/5134f44c09d39344a8747655c0d59864bb574b96/applications/services/storage/filesystem_api_defines.h#L8-L22 + if(!buffered_file_stream_open( + nonce_array->stream, MF_CLASSIC_NONCE_PATH, FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) { + buffered_file_stream_close(nonce_array->stream); + break; + } + + // Check for newline ending + if(!stream_eof(nonce_array->stream)) { + if(!stream_seek(nonce_array->stream, -1, StreamOffsetFromEnd)) break; + uint8_t last_char = 0; + if(stream_read(nonce_array->stream, &last_char, 1) != 1) break; + if(last_char != '\n') { + //FURI_LOG_D(TAG, "Adding new line ending"); + if(stream_write_char(nonce_array->stream, '\n') != 1) break; + } + if(!stream_rewind(nonce_array->stream)) break; + } + + // Read total amount of nonces + FuriString* next_line; + next_line = furi_string_alloc(); + while(!(program_state->close_thread_please)) { + if(!stream_read_line(nonce_array->stream, next_line)) { + //FURI_LOG_T(TAG, "No nonces left"); + break; + } + /* + FURI_LOG_T( + TAG, + "Read line: %s, len: %zu", + furi_string_get_cstr(next_line), + furi_string_size(next_line)); + */ + if(!furi_string_start_with_str(next_line, "Sec")) continue; + const char* next_line_cstr = furi_string_get_cstr(next_line); + MfClassicNonce res = {0}; + res.attack = mfkey32; + int i = 0; + char* endptr; + for(i = 0; i <= 17; i++) { + if(i != 0) { + next_line_cstr = strchr(next_line_cstr, ' '); + if(next_line_cstr) { + next_line_cstr++; + } else { + break; + } + } + unsigned long value = strtoul(next_line_cstr, &endptr, 16); + switch(i) { + case 5: + res.uid = value; + break; + case 7: + res.nt0 = value; + break; + case 9: + res.nr0_enc = value; + break; + case 11: + res.ar0_enc = value; + break; + case 13: + res.nt1 = value; + break; + case 15: + res.nr1_enc = value; + break; + case 17: + res.ar1_enc = value; + break; + default: + break; // Do nothing + } + next_line_cstr = endptr; + } + res.p64 = prng_successor(res.nt0, 64); + res.p64b = prng_successor(res.nt1, 64); + res.uid_xor_nt0 = res.uid ^ res.nt0; + res.uid_xor_nt1 = res.uid ^ res.nt1; + + (program_state->total)++; + if((system_dict_exists && key_already_found_for_nonce_in_dict(system_dict, &res)) || + (key_already_found_for_nonce_in_dict(user_dict, &res))) { + (program_state->cracked)++; + (program_state->num_completed)++; + continue; + } + //FURI_LOG_I(TAG, "No key found for %8lx %8lx", res.uid, res.ar1_enc); + // TODO: Refactor + nonce_array->remaining_nonce_array = realloc( //-V701 + nonce_array->remaining_nonce_array, + sizeof(MfClassicNonce) * ((nonce_array->remaining_nonces) + 1)); + nonce_array->remaining_nonces++; + nonce_array->remaining_nonce_array[(nonce_array->remaining_nonces) - 1] = res; + nonce_array->total_nonces++; + } + furi_string_free(next_line); + buffered_file_stream_close(nonce_array->stream); + + array_loaded = true; + //FURI_LOG_I(TAG, "Loaded %lu Mfkey32 nonces", nonce_array->total_nonces); + } while(false); + + return array_loaded; +} + +bool load_nested_nonces( + MfClassicNonceArray* nonce_array, + ProgramState* program_state, + KeysDict* system_dict, + bool system_dict_exists, + KeysDict* user_dict) { + if(!buffered_file_stream_open( + nonce_array->stream, MF_CLASSIC_NESTED_NONCE_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { + return false; + } + + FuriString* next_line = furi_string_alloc(); + bool array_loaded = false; + + while(stream_read_line(nonce_array->stream, next_line)) { + const char* line = furi_string_get_cstr(next_line); + + // Only process lines ending with "dist 0" + if(!strstr(line, "dist 0")) { + continue; + } + + MfClassicNonce res = {0}; + res.attack = static_encrypted; + + int parsed = sscanf( + line, + "Sec %*d key %*c cuid %" PRIx32 " nt0 %" PRIx32 " ks0 %" PRIx32 + " par0 %4[01] nt1 %" PRIx32 " ks1 %" PRIx32 " par1 %4[01]", + &res.uid, + &res.nt0, + &res.ks1_1_enc, + res.par_1_str, + &res.nt1, + &res.ks1_2_enc, + res.par_2_str); + + if(parsed >= 4) { // At least one nonce is present + res.par_1 = binaryStringToInt(res.par_1_str); + res.uid_xor_nt0 = res.uid ^ res.nt0; + + if(parsed == 7) { // Both nonces are present + res.attack = static_nested; + res.par_2 = binaryStringToInt(res.par_2_str); + res.uid_xor_nt1 = res.uid ^ res.nt1; + } + + (program_state->total)++; + if((system_dict_exists && key_already_found_for_nonce_in_dict(system_dict, &res)) || + (key_already_found_for_nonce_in_dict(user_dict, &res))) { + (program_state->cracked)++; + (program_state->num_completed)++; + continue; + } + + nonce_array->remaining_nonce_array = realloc( + nonce_array->remaining_nonce_array, + sizeof(MfClassicNonce) * (nonce_array->remaining_nonces + 1)); + nonce_array->remaining_nonce_array[nonce_array->remaining_nonces] = res; + nonce_array->remaining_nonces++; + nonce_array->total_nonces++; + array_loaded = true; + } + } + + furi_string_free(next_line); + buffered_file_stream_close(nonce_array->stream); + + //FURI_LOG_I(TAG, "Loaded %lu Static Nested nonces", nonce_array->total_nonces); + return array_loaded; +} + +MfClassicNonceArray* napi_mf_classic_nonce_array_alloc( + KeysDict* system_dict, + bool system_dict_exists, + KeysDict* user_dict, + ProgramState* program_state) { + MfClassicNonceArray* nonce_array = malloc(sizeof(MfClassicNonceArray)); + MfClassicNonce* remaining_nonce_array_init = malloc(sizeof(MfClassicNonce) * 1); + nonce_array->remaining_nonce_array = remaining_nonce_array_init; + Storage* storage = furi_record_open(RECORD_STORAGE); + nonce_array->stream = buffered_file_stream_alloc(storage); + furi_record_close(RECORD_STORAGE); + + if(program_state->mfkey32_present) { + load_mfkey32_nonces( + nonce_array, program_state, system_dict, system_dict_exists, user_dict); + } + + if(program_state->nested_present) { + load_nested_nonces(nonce_array, program_state, system_dict, system_dict_exists, user_dict); + } + + return nonce_array; +} + +void napi_mf_classic_nonce_array_free(MfClassicNonceArray* nonce_array) { + // TODO: Track free state at the time this is called to ensure double free does not happen + furi_assert(nonce_array); + furi_assert(nonce_array->stream); + + // TODO: Already closed? + buffered_file_stream_close(nonce_array->stream); + stream_free(nonce_array->stream); + free(nonce_array); +} + +/* Actual implementation of app<>plugin interface */ +static const MfkeyPlugin init_plugin = { + .name = "Initialization Plugin", + .napi_mf_classic_mfkey32_nonces_check_presence = + &napi_mf_classic_mfkey32_nonces_check_presence, + .napi_mf_classic_nested_nonces_check_presence = &napi_mf_classic_nested_nonces_check_presence, + .napi_mf_classic_nonce_array_alloc = &napi_mf_classic_nonce_array_alloc, + .napi_mf_classic_nonce_array_free = &napi_mf_classic_nonce_array_free, +}; + +/* Plugin descriptor to comply with basic plugin specification */ +static const FlipperAppPluginDescriptor init_plugin_descriptor = { + .appid = PLUGIN_APP_ID, + .ep_api_version = PLUGIN_API_VERSION, + .entry_point = &init_plugin, +}; + +/* Plugin entry point - must return a pointer to const descriptor */ +const FlipperAppPluginDescriptor* init_plugin_ep() { + return &init_plugin_descriptor; +} diff --git a/applications/system/mfkey/mfkey.c b/applications/system/mfkey/mfkey.c new file mode 100644 index 000000000..ae5cc90f2 --- /dev/null +++ b/applications/system/mfkey/mfkey.c @@ -0,0 +1,915 @@ +#pragma GCC optimize("O3") +#pragma GCC optimize("-funroll-all-loops") + +// TODO: More efficient dictionary bruteforce by scanning through hardcoded very common keys and previously found dictionary keys first? +// (a cache for key_already_found_for_nonce_in_dict) +// TODO: Selectively unroll loops to reduce binary size +// TODO: Collect parity during Mfkey32 attacks to further optimize the attack +// TODO: Why different sscanf between Mfkey32 and Nested? +// TODO: "Read tag again with NFC app" message upon completion, "Complete. Keys added: " +// TODO: Separate Mfkey32 and Nested functions where possible to reduce branch statements +// TODO: Find ~1 KB memory leak +// TODO: Use seednt16 to reduce static encrypted key candidates: https://gist.github.com/noproto/8102f8f32546564cd674256e62ff76ea +// https://eprint.iacr.org/2024/1275.pdf section X +// TODO: Static Encrypted: Minimum RAM for adding to keys dict (avoid crashes) +// TODO: Static Encrypted: Optimize KeysDict or buffer keys to write in chunks + +#include +#include +#include +#include +#include "mfkey_icons.h" +#include +#include +#include +#include +#include +#include +#include +#include "mfkey.h" +#include "crypto1.h" +#include "plugin_interface.h" +#include +#include +#include + +#define TAG "MFKey" + +// TODO: Remove defines that are not needed +#define KEYS_DICT_SYSTEM_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc") +#define KEYS_DICT_USER_PATH EXT_PATH("nfc/assets/mf_classic_dict_user.nfc") +#define MAX_NAME_LEN 32 +#define MAX_PATH_LEN 64 + +#define LF_POLY_ODD (0x29CE5C) +#define LF_POLY_EVEN (0x870804) +#define CONST_M1_1 (LF_POLY_EVEN << 1 | 1) +#define CONST_M2_1 (LF_POLY_ODD << 1) +#define CONST_M1_2 (LF_POLY_ODD) +#define CONST_M2_2 (LF_POLY_EVEN << 1 | 1) +#define BIT(x, n) ((x) >> (n) & 1) +#define BEBIT(x, n) BIT(x, (n) ^ 24) +#define SWAPENDIAN(x) \ + ((x) = ((x) >> 8 & 0xff00ff) | ((x) & 0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16) +//#define SIZEOF(arr) sizeof(arr) / sizeof(*arr) + +static int eta_round_time = 44; +static int eta_total_time = 705; +// MSB_LIMIT: Chunk size (out of 256) +static int MSB_LIMIT = 16; + +static inline int + check_state(struct Crypto1State* t, MfClassicNonce* n, ProgramState* program_state) { + if(!(t->odd | t->even)) return 0; + if(n->attack == mfkey32) { + uint32_t rb = (napi_lfsr_rollback_word(t, 0, 0) ^ n->p64); + if(rb != n->ar0_enc) { + return 0; + } + rollback_word_noret(t, n->nr0_enc, 1); + rollback_word_noret(t, n->uid_xor_nt0, 0); + struct Crypto1State temp = {t->odd, t->even}; + crypt_word_noret(t, n->uid_xor_nt1, 0); + crypt_word_noret(t, n->nr1_enc, 1); + if(n->ar1_enc == (crypt_word(t) ^ n->p64b)) { + crypto1_get_lfsr(&temp, &(n->key)); + return 1; + } + } else if(n->attack == static_nested) { + struct Crypto1State temp = {t->odd, t->even}; + rollback_word_noret(t, n->uid_xor_nt1, 0); + if(n->ks1_1_enc == crypt_word_ret(t, n->uid_xor_nt0, 0)) { + rollback_word_noret(&temp, n->uid_xor_nt1, 0); + crypto1_get_lfsr(&temp, &(n->key)); + return 1; + } + } else if(n->attack == static_encrypted) { + // TODO: Parity bits from rollback_word? + if(n->ks1_1_enc == napi_lfsr_rollback_word(t, n->uid_xor_nt0, 0)) { + // Reduce with parity + uint8_t local_parity_keystream_bits; + struct Crypto1State temp = {t->odd, t->even}; + if((crypt_word_par(&temp, n->uid_xor_nt0, 0, n->nt0, &local_parity_keystream_bits) == + n->ks1_1_enc) && + (local_parity_keystream_bits == n->par_1)) { + // Found key candidate + crypto1_get_lfsr(t, &(n->key)); + program_state->num_candidates++; + keys_dict_add_key(program_state->cuid_dict, n->key.data, sizeof(MfClassicKey)); + } + } + } + return 0; +} + +static inline int state_loop( + unsigned int* states_buffer, + int xks, + int m1, + int m2, + unsigned int in, + uint8_t and_val) { + int states_tail = 0; + int round = 0, s = 0, xks_bit = 0, round_in = 0; + + for(round = 1; round <= 12; round++) { + xks_bit = BIT(xks, round); + if(round > 4) { + round_in = ((in >> (2 * (round - 4))) & and_val) << 24; + } + + for(s = 0; s <= states_tail; s++) { + states_buffer[s] <<= 1; + + if((filter(states_buffer[s]) ^ filter(states_buffer[s] | 1)) != 0) { + states_buffer[s] |= filter(states_buffer[s]) ^ xks_bit; + if(round > 4) { + update_contribution(states_buffer, s, m1, m2); + states_buffer[s] ^= round_in; + } + } else if(filter(states_buffer[s]) == xks_bit) { + // TODO: Refactor + if(round > 4) { + states_buffer[++states_tail] = states_buffer[s + 1]; + states_buffer[s + 1] = states_buffer[s] | 1; + update_contribution(states_buffer, s, m1, m2); + states_buffer[s++] ^= round_in; + update_contribution(states_buffer, s, m1, m2); + states_buffer[s] ^= round_in; + } else { + states_buffer[++states_tail] = states_buffer[++s]; + states_buffer[s] = states_buffer[s - 1] | 1; + } + } else { + states_buffer[s--] = states_buffer[states_tail--]; + } + } + } + + return states_tail; +} + +int binsearch(unsigned int data[], int start, int stop) { + int mid, val = data[stop] & 0xff000000; + while(start != stop) { + mid = (stop - start) >> 1; + if((data[start + mid] ^ 0x80000000) > (val ^ 0x80000000)) + stop = start + mid; + else + start += mid + 1; + } + return start; +} +void quicksort(unsigned int array[], int low, int high) { + //if (SIZEOF(array) == 0) + // return; + if(low >= high) return; + int middle = low + (high - low) / 2; + unsigned int pivot = array[middle]; + int i = low, j = high; + while(i <= j) { + while(array[i] < pivot) { + i++; + } + while(array[j] > pivot) { + j--; + } + if(i <= j) { // swap + int temp = array[i]; + array[i] = array[j]; + array[j] = temp; + i++; + j--; + } + } + if(low < j) { + quicksort(array, low, j); + } + if(high > i) { + quicksort(array, i, high); + } +} +int extend_table(unsigned int data[], int tbl, int end, int bit, int m1, int m2, unsigned int in) { + in <<= 24; + for(data[tbl] <<= 1; tbl <= end; data[++tbl] <<= 1) { + if((filter(data[tbl]) ^ filter(data[tbl] | 1)) != 0) { + data[tbl] |= filter(data[tbl]) ^ bit; + update_contribution(data, tbl, m1, m2); + data[tbl] ^= in; + } else if(filter(data[tbl]) == bit) { + data[++end] = data[tbl + 1]; + data[tbl + 1] = data[tbl] | 1; + update_contribution(data, tbl, m1, m2); + data[tbl++] ^= in; + update_contribution(data, tbl, m1, m2); + data[tbl] ^= in; + } else { + data[tbl--] = data[end--]; + } + } + return end; +} + +int old_recover( + unsigned int odd[], + int o_head, + int o_tail, + int oks, + unsigned int even[], + int e_head, + int e_tail, + int eks, + int rem, + int s, + MfClassicNonce* n, + unsigned int in, + int first_run, + ProgramState* program_state) { + int o, e, i; + if(rem == -1) { + for(e = e_head; e <= e_tail; ++e) { + even[e] = (even[e] << 1) ^ evenparity32(even[e] & LF_POLY_EVEN) ^ (!!(in & 4)); + for(o = o_head; o <= o_tail; ++o, ++s) { + struct Crypto1State temp = {0, 0}; + temp.even = odd[o]; + temp.odd = even[e] ^ evenparity32(odd[o] & LF_POLY_ODD); + if(check_state(&temp, n, program_state)) { + return -1; + } + } + } + return s; + } + if(first_run == 0) { + for(i = 0; (i < 4) && (rem-- != 0); i++) { + oks >>= 1; + eks >>= 1; + in >>= 2; + o_tail = extend_table( + odd, o_head, o_tail, oks & 1, LF_POLY_EVEN << 1 | 1, LF_POLY_ODD << 1, 0); + if(o_head > o_tail) return s; + e_tail = extend_table( + even, e_head, e_tail, eks & 1, LF_POLY_ODD, LF_POLY_EVEN << 1 | 1, in & 3); + if(e_head > e_tail) return s; + } + } + first_run = 0; + quicksort(odd, o_head, o_tail); + quicksort(even, e_head, e_tail); + while(o_tail >= o_head && e_tail >= e_head) { + if(((odd[o_tail] ^ even[e_tail]) >> 24) == 0) { + o_tail = binsearch(odd, o_head, o = o_tail); + e_tail = binsearch(even, e_head, e = e_tail); + s = old_recover( + odd, + o_tail--, + o, + oks, + even, + e_tail--, + e, + eks, + rem, + s, + n, + in, + first_run, + program_state); + if(s == -1) { + break; + } + } else if((odd[o_tail] ^ 0x80000000) > (even[e_tail] ^ 0x80000000)) { + o_tail = binsearch(odd, o_head, o_tail) - 1; + } else { + e_tail = binsearch(even, e_head, e_tail) - 1; + } + } + return s; +} + +static inline int sync_state(ProgramState* program_state) { + int ts = furi_hal_rtc_get_timestamp(); + int elapsed_time = ts - program_state->eta_timestamp; + if(elapsed_time < program_state->eta_round) { + program_state->eta_round -= elapsed_time; + } else { + program_state->eta_round = 0; + } + if(elapsed_time < program_state->eta_total) { + program_state->eta_total -= elapsed_time; + } else { + program_state->eta_total = 0; + } + program_state->eta_timestamp = ts; + if(program_state->close_thread_please) { + return 1; + } + return 0; +} + +int calculate_msb_tables( + int oks, + int eks, + int msb_round, + MfClassicNonce* n, + unsigned int* states_buffer, + struct Msb* odd_msbs, + struct Msb* even_msbs, + unsigned int* temp_states_odd, + unsigned int* temp_states_even, + unsigned int in, + ProgramState* program_state) { + //FURI_LOG_I(TAG, "MSB GO %i", msb_iter); // DEBUG + unsigned int msb_head = (MSB_LIMIT * msb_round); // msb_iter ranges from 0 to (256/MSB_LIMIT)-1 + unsigned int msb_tail = (MSB_LIMIT * (msb_round + 1)); + int states_tail = 0, tail = 0; + int i = 0, j = 0, semi_state = 0, found = 0; + unsigned int msb = 0; + in = ((in >> 16 & 0xff) | (in << 16) | (in & 0xff00)) << 1; + // TODO: Why is this necessary? + memset(odd_msbs, 0, MSB_LIMIT * sizeof(struct Msb)); + memset(even_msbs, 0, MSB_LIMIT * sizeof(struct Msb)); + + for(semi_state = 1 << 20; semi_state >= 0; semi_state--) { + if(semi_state % 32768 == 0) { + if(sync_state(program_state) == 1) { + return 0; + } + } + + if(filter(semi_state) == (oks & 1)) { //-V547 + states_buffer[0] = semi_state; + states_tail = state_loop(states_buffer, oks, CONST_M1_1, CONST_M2_1, 0, 0); + + for(i = states_tail; i >= 0; i--) { + msb = states_buffer[i] >> 24; + if((msb >= msb_head) && (msb < msb_tail)) { + found = 0; + for(j = 0; j < odd_msbs[msb - msb_head].tail - 1; j++) { + if(odd_msbs[msb - msb_head].states[j] == states_buffer[i]) { + found = 1; + break; + } + } + + if(!found) { + tail = odd_msbs[msb - msb_head].tail++; + odd_msbs[msb - msb_head].states[tail] = states_buffer[i]; + } + } + } + } + + if(filter(semi_state) == (eks & 1)) { //-V547 + states_buffer[0] = semi_state; + states_tail = state_loop(states_buffer, eks, CONST_M1_2, CONST_M2_2, in, 3); + + for(i = 0; i <= states_tail; i++) { + msb = states_buffer[i] >> 24; + if((msb >= msb_head) && (msb < msb_tail)) { + found = 0; + + for(j = 0; j < even_msbs[msb - msb_head].tail; j++) { + if(even_msbs[msb - msb_head].states[j] == states_buffer[i]) { + found = 1; + break; + } + } + + if(!found) { + tail = even_msbs[msb - msb_head].tail++; + even_msbs[msb - msb_head].states[tail] = states_buffer[i]; + } + } + } + } + } + + oks >>= 12; + eks >>= 12; + + for(i = 0; i < MSB_LIMIT; i++) { + if(sync_state(program_state) == 1) { + return 0; + } + // TODO: Why is this necessary? + memset(temp_states_even, 0, sizeof(unsigned int) * (1280)); + memset(temp_states_odd, 0, sizeof(unsigned int) * (1280)); + memcpy(temp_states_odd, odd_msbs[i].states, odd_msbs[i].tail * sizeof(unsigned int)); + memcpy(temp_states_even, even_msbs[i].states, even_msbs[i].tail * sizeof(unsigned int)); + int res = old_recover( + temp_states_odd, + 0, + odd_msbs[i].tail, + oks, + temp_states_even, + 0, + even_msbs[i].tail, + eks, + 3, + 0, + n, + in >> 16, + 1, + program_state); + if(res == -1) { + return 1; + } + //odd_msbs[i].tail = 0; + //even_msbs[i].tail = 0; + } + + return 0; +} + +void** allocate_blocks(const size_t* block_sizes, int num_blocks) { + void** block_pointers = malloc(num_blocks * sizeof(void*)); + + for(int i = 0; i < num_blocks; i++) { + if(memmgr_heap_get_max_free_block() < block_sizes[i]) { + // Not enough memory, free previously allocated blocks + for(int j = 0; j < i; j++) { + free(block_pointers[j]); + } + free(block_pointers); + return NULL; + } + + block_pointers[i] = malloc(block_sizes[i]); + } + + return block_pointers; +} + +bool is_full_speed() { + return MSB_LIMIT == 16; +} + +bool recover(MfClassicNonce* n, int ks2, unsigned int in, ProgramState* program_state) { + bool found = false; + const size_t block_sizes[] = {49216, 49216, 5120, 5120, 4096}; + const size_t reduced_block_sizes[] = {24608, 24608, 5120, 5120, 4096}; + const int num_blocks = sizeof(block_sizes) / sizeof(block_sizes[0]); + void** block_pointers = allocate_blocks(block_sizes, num_blocks); + if(block_pointers == NULL) { + // System has less than the guaranteed amount of RAM (140 KB) - adjust some parameters to run anyway at half speed + if(is_full_speed()) { + //eta_round_time *= 2; + eta_total_time *= 2; + MSB_LIMIT /= 2; + } + block_pointers = allocate_blocks(reduced_block_sizes, num_blocks); + if(block_pointers == NULL) { + // System has less than 70 KB of RAM - should never happen so we don't reduce speed further + program_state->err = InsufficientRAM; + program_state->mfkey_state = Error; + return false; + } + } + // Adjust estimates for static encrypted attacks + if(n->attack == static_encrypted) { + eta_round_time *= 4; + eta_total_time *= 4; + if(is_full_speed()) { + eta_round_time *= 4; + eta_total_time *= 4; + } + } + struct Msb* odd_msbs = block_pointers[0]; + struct Msb* even_msbs = block_pointers[1]; + unsigned int* temp_states_odd = block_pointers[2]; + unsigned int* temp_states_even = block_pointers[3]; + unsigned int* states_buffer = block_pointers[4]; + int oks = 0, eks = 0; + int i = 0, msb = 0; + for(i = 31; i >= 0; i -= 2) { + oks = oks << 1 | BEBIT(ks2, i); + } + for(i = 30; i >= 0; i -= 2) { + eks = eks << 1 | BEBIT(ks2, i); + } + int bench_start = furi_hal_rtc_get_timestamp(); + program_state->eta_total = eta_total_time; + program_state->eta_timestamp = bench_start; + for(msb = 0; msb <= ((256 / MSB_LIMIT) - 1); msb++) { + program_state->search = msb; + program_state->eta_round = eta_round_time; + program_state->eta_total = eta_total_time - (eta_round_time * msb); + if(calculate_msb_tables( + oks, + eks, + msb, + n, + states_buffer, + odd_msbs, + even_msbs, + temp_states_odd, + temp_states_even, + in, + program_state)) { + //int bench_stop = furi_hal_rtc_get_timestamp(); + //FURI_LOG_I(TAG, "Cracked in %i seconds", bench_stop - bench_start); + found = true; + break; + } + if(program_state->close_thread_please) { + break; + } + } + // Free the allocated blocks + for(int i = 0; i < num_blocks; i++) { + free(block_pointers[i]); + } + free(block_pointers); + return found; +} + +bool key_already_found_for_nonce_in_solved( + MfClassicKey* keyarray, + int keyarray_size, + MfClassicNonce* nonce) { + for(int k = 0; k < keyarray_size; k++) { + uint64_t key_as_int = bit_lib_bytes_to_num_be(keyarray[k].data, sizeof(MfClassicKey)); + struct Crypto1State temp = {0, 0}; + for(int i = 0; i < 24; i++) { + (&temp)->odd |= (BIT(key_as_int, 2 * i + 1) << (i ^ 3)); + (&temp)->even |= (BIT(key_as_int, 2 * i) << (i ^ 3)); + } + if(nonce->attack == mfkey32) { + crypt_word_noret(&temp, nonce->uid_xor_nt1, 0); + crypt_word_noret(&temp, nonce->nr1_enc, 1); + if(nonce->ar1_enc == (crypt_word(&temp) ^ nonce->p64b)) { + return true; + } + } else if(nonce->attack == static_nested) { + uint32_t expected_ks1 = crypt_word_ret(&temp, nonce->uid_xor_nt0, 0); + if(nonce->ks1_1_enc == expected_ks1) { + return true; + } + } + } + return false; +} + +#pragma GCC push_options +#pragma GCC optimize("Os") +static void finished_beep() { + // Beep to indicate completion + NotificationApp* notification = furi_record_open("notification"); + notification_message(notification, &sequence_audiovisual_alert); + notification_message(notification, &sequence_display_backlight_on); + furi_record_close("notification"); +} + +void mfkey(ProgramState* program_state) { + uint32_t ks_enc = 0, nt_xor_uid = 0; + MfClassicKey found_key; // Recovered key + size_t keyarray_size = 0; + MfClassicKey* keyarray = malloc(sizeof(MfClassicKey) * 1); + uint32_t i = 0, j = 0; + //FURI_LOG_I(TAG, "Free heap before alloc(): %zub", memmgr_get_free_heap()); + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperApplication* app = flipper_application_alloc(storage, firmware_api_interface); + flipper_application_preload(app, APP_ASSETS_PATH("plugins/mfkey_init_plugin.fal")); + flipper_application_map_to_memory(app); + const FlipperAppPluginDescriptor* app_descriptor = + flipper_application_plugin_get_descriptor(app); + const MfkeyPlugin* init_plugin = app_descriptor->entry_point; + // Check for nonces + program_state->mfkey32_present = init_plugin->napi_mf_classic_mfkey32_nonces_check_presence(); + program_state->nested_present = init_plugin->napi_mf_classic_nested_nonces_check_presence(); + if(!(program_state->mfkey32_present) && !(program_state->nested_present)) { + program_state->err = MissingNonces; + program_state->mfkey_state = Error; + flipper_application_free(app); + furi_record_close(RECORD_STORAGE); + free(keyarray); + return; + } + // Read dictionaries (optional) + KeysDict* system_dict = {0}; + bool system_dict_exists = keys_dict_check_presence(KEYS_DICT_SYSTEM_PATH); + KeysDict* user_dict = {0}; + bool user_dict_exists = keys_dict_check_presence(KEYS_DICT_USER_PATH); + uint32_t total_dict_keys = 0; + if(system_dict_exists) { + system_dict = + keys_dict_alloc(KEYS_DICT_SYSTEM_PATH, KeysDictModeOpenExisting, sizeof(MfClassicKey)); + total_dict_keys += keys_dict_get_total_keys(system_dict); + } + user_dict = keys_dict_alloc(KEYS_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey)); + if(user_dict_exists) { + total_dict_keys += keys_dict_get_total_keys(user_dict); + } + user_dict_exists = true; + program_state->dict_count = total_dict_keys; + program_state->mfkey_state = DictionaryAttack; + // Read nonces + MfClassicNonceArray* nonce_arr; + nonce_arr = init_plugin->napi_mf_classic_nonce_array_alloc( + system_dict, system_dict_exists, user_dict, program_state); + if(system_dict_exists) { + keys_dict_free(system_dict); + } + if(nonce_arr->total_nonces == 0) { + // Nothing to crack + program_state->err = ZeroNonces; + program_state->mfkey_state = Error; + init_plugin->napi_mf_classic_nonce_array_free(nonce_arr); + flipper_application_free(app); + furi_record_close(RECORD_STORAGE); + keys_dict_free(user_dict); + free(keyarray); + return; + } + flipper_application_free(app); + furi_record_close(RECORD_STORAGE); + // TODO: Track free state at the time this is called to ensure double free does not happen + furi_assert(nonce_arr); + furi_assert(nonce_arr->stream); + // TODO: Already closed? + buffered_file_stream_close(nonce_arr->stream); + stream_free(nonce_arr->stream); + //FURI_LOG_I(TAG, "Free heap after free(): %zub", memmgr_get_free_heap()); + program_state->mfkey_state = MFKeyAttack; + // TODO: Work backwards on this array and free memory + for(i = 0; i < nonce_arr->total_nonces; i++) { + MfClassicNonce next_nonce = nonce_arr->remaining_nonce_array[i]; + if(key_already_found_for_nonce_in_solved(keyarray, keyarray_size, &next_nonce)) { + nonce_arr->remaining_nonces--; + (program_state->cracked)++; + (program_state->num_completed)++; + continue; + } + //FURI_LOG_I(TAG, "Beginning recovery for %8lx", next_nonce.uid); + FuriString* cuid_dict_path; + switch(next_nonce.attack) { + case mfkey32: + ks_enc = next_nonce.ar0_enc ^ next_nonce.p64; + nt_xor_uid = 0; + break; + case static_nested: + ks_enc = next_nonce.ks1_2_enc; + nt_xor_uid = next_nonce.uid_xor_nt1; + break; + case static_encrypted: + ks_enc = next_nonce.ks1_1_enc; + nt_xor_uid = next_nonce.uid_xor_nt0; + cuid_dict_path = furi_string_alloc_printf( + "%s/mf_classic_dict_%08lx.nfc", EXT_PATH("nfc/assets"), next_nonce.uid); + // May need RECORD_STORAGE? + program_state->cuid_dict = keys_dict_alloc( + furi_string_get_cstr(cuid_dict_path), + KeysDictModeOpenAlways, + sizeof(MfClassicKey)); + break; + } + + if(!recover(&next_nonce, ks_enc, nt_xor_uid, program_state)) { + if((next_nonce.attack == static_encrypted) && (program_state->cuid_dict)) { + keys_dict_free(program_state->cuid_dict); + } + if(program_state->close_thread_please) { + break; + } + // No key found in recover() or static encrypted + (program_state->num_completed)++; + continue; + } + (program_state->cracked)++; + (program_state->num_completed)++; + found_key = next_nonce.key; + bool already_found = false; + for(j = 0; j < keyarray_size; j++) { + if(memcmp(keyarray[j].data, found_key.data, MF_CLASSIC_KEY_SIZE) == 0) { + already_found = true; + break; + } + } + if(already_found == false) { + // New key + keyarray = realloc(keyarray, sizeof(MfClassicKey) * (keyarray_size + 1)); //-V701 + keyarray_size += 1; + keyarray[keyarray_size - 1] = found_key; + (program_state->unique_cracked)++; + } + } + // TODO: Update display to show all keys were found + // TODO: Prepend found key(s) to user dictionary file + //FURI_LOG_I(TAG, "Unique keys found:"); + for(i = 0; i < keyarray_size; i++) { + //FURI_LOG_I(TAG, "%012" PRIx64, keyarray[i]); + keys_dict_add_key(user_dict, keyarray[i].data, sizeof(MfClassicKey)); + } + if(keyarray_size > 0) { + dolphin_deed(DolphinDeedNfcMfcAdd); + } + free(nonce_arr); + keys_dict_free(user_dict); + free(keyarray); + if(program_state->mfkey_state == Error) { + return; + } + //FURI_LOG_I(TAG, "mfkey function completed normally"); // DEBUG + program_state->mfkey_state = Complete; + // No need to alert the user if they asked it to stop + if(!(program_state->close_thread_please)) { + finished_beep(); + } + return; +} + +// Screen is 128x64 px +static void render_callback(Canvas* const canvas, void* ctx) { + furi_assert(ctx); + ProgramState* program_state = ctx; + furi_mutex_acquire(program_state->mutex, FuriWaitForever); + char draw_str[44] = {}; + + canvas_draw_frame(canvas, 0, 0, 128, 64); + canvas_draw_frame(canvas, 0, 15, 128, 64); + + // FontSecondary by default, title is drawn at the end + snprintf(draw_str, sizeof(draw_str), "RAM: %zub", memmgr_get_free_heap()); + canvas_draw_str_aligned(canvas, 48, 5, AlignLeft, AlignTop, draw_str); + canvas_draw_icon(canvas, 114, 4, &I_mfkey); + if(program_state->mfkey_state == MFKeyAttack) { + float eta_round = (float)1 - ((float)program_state->eta_round / (float)eta_round_time); + float eta_total = (float)1 - ((float)program_state->eta_total / (float)eta_total_time); + float progress = (float)program_state->num_completed / (float)program_state->total; + if(eta_round < 0 || eta_round > 1) { + // Round ETA miscalculated + eta_round = 1; + program_state->eta_round = 0; + } + if(eta_total < 0 || eta_round > 1) { + // Total ETA miscalculated + eta_total = 1; + program_state->eta_total = 0; + } + snprintf( + draw_str, + sizeof(draw_str), + "Cracking: %d/%d - in prog.", + program_state->num_completed, + program_state->total); + elements_progress_bar_with_text(canvas, 5, 18, 118, progress, draw_str); + snprintf( + draw_str, + sizeof(draw_str), + "Round: %d/%d - ETA %02d Sec", + (program_state->search) + 1, // Zero indexed + 256 / MSB_LIMIT, + program_state->eta_round); + elements_progress_bar_with_text(canvas, 5, 31, 118, eta_round, draw_str); + snprintf(draw_str, sizeof(draw_str), "Total ETA %03d Sec", program_state->eta_total); + elements_progress_bar_with_text(canvas, 5, 44, 118, eta_total, draw_str); + } else if(program_state->mfkey_state == DictionaryAttack) { + snprintf( + draw_str, sizeof(draw_str), "Dict solves: %d (in progress)", program_state->cracked); + canvas_draw_str_aligned(canvas, 10, 18, AlignLeft, AlignTop, draw_str); + snprintf(draw_str, sizeof(draw_str), "Keys in dict: %d", program_state->dict_count); + canvas_draw_str_aligned(canvas, 26, 28, AlignLeft, AlignTop, draw_str); + } else if(program_state->mfkey_state == Complete) { + // TODO: Scrollable list view to see cracked keys if user presses down + elements_progress_bar(canvas, 5, 18, 118, 1); + canvas_draw_str_aligned(canvas, 64, 31, AlignCenter, AlignTop, "Complete"); + snprintf( + draw_str, + sizeof(draw_str), + "Keys added to user dict: %d", + program_state->unique_cracked); + canvas_draw_str_aligned(canvas, 64, 41, AlignCenter, AlignTop, draw_str); + if(program_state->num_candidates > 0) { + snprintf( + draw_str, + sizeof(draw_str), + "SEN key candidates: %d", + program_state->num_candidates); + canvas_draw_str_aligned(canvas, 64, 51, AlignCenter, AlignTop, draw_str); + } + } else if(program_state->mfkey_state == Ready) { + canvas_draw_str_aligned(canvas, 50, 30, AlignLeft, AlignTop, "Ready"); + elements_button_center(canvas, "Start"); + elements_button_right(canvas, "Help"); + } else if(program_state->mfkey_state == Help) { + canvas_draw_str_aligned(canvas, 7, 20, AlignLeft, AlignTop, "Collect nonces by reading"); + canvas_draw_str_aligned(canvas, 7, 30, AlignLeft, AlignTop, "tag or reader in NFC app:"); + canvas_draw_str_aligned(canvas, 7, 40, AlignLeft, AlignTop, "https://docs.flipper.net/"); + canvas_draw_str_aligned(canvas, 7, 50, AlignLeft, AlignTop, "nfc/mfkey32"); + } else if(program_state->mfkey_state == Error) { + canvas_draw_str_aligned(canvas, 50, 25, AlignLeft, AlignTop, "Error"); + if(program_state->err == MissingNonces) { + canvas_draw_str_aligned(canvas, 25, 36, AlignLeft, AlignTop, "No nonces found"); + } else if(program_state->err == ZeroNonces) { + canvas_draw_str_aligned(canvas, 15, 36, AlignLeft, AlignTop, "Nonces already cracked"); + } else if(program_state->err == InsufficientRAM) { + canvas_draw_str_aligned(canvas, 35, 36, AlignLeft, AlignTop, "No free RAM"); + } else { + // Unhandled error + } + } else { + // Unhandled program state + } + // Title + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 5, 4, AlignLeft, AlignTop, "MFKey"); + furi_mutex_release(program_state->mutex); +} + +static void input_callback(InputEvent* input_event, void* event_queue) { + furi_assert(event_queue); + furi_message_queue_put((FuriMessageQueue*)event_queue, input_event, FuriWaitForever); +} + +static void mfkey_state_init(ProgramState* program_state) { + program_state->mfkey_state = Ready; + program_state->cracked = 0; + program_state->unique_cracked = 0; + program_state->num_completed = 0; + program_state->num_candidates = 0; + program_state->total = 0; + program_state->dict_count = 0; +} + +// Entrypoint for worker thread +static int32_t mfkey_worker_thread(void* ctx) { + ProgramState* program_state = ctx; + program_state->mfkey_state = Initializing; + mfkey(program_state); + return 0; +} + +int32_t mfkey_main() { + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); + + ProgramState* program_state = malloc(sizeof(ProgramState)); + + mfkey_state_init(program_state); + + program_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); + + // Set system callbacks + ViewPort* view_port = view_port_alloc(); + view_port_draw_callback_set(view_port, render_callback, program_state); + view_port_input_callback_set(view_port, input_callback, event_queue); + + // Open GUI and register view_port + Gui* gui = furi_record_open(RECORD_GUI); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + + program_state->mfkeythread = + furi_thread_alloc_ex("MFKeyWorker", 2048, mfkey_worker_thread, program_state); + + InputEvent input_event; + for(bool main_loop = true; main_loop;) { + FuriStatus event_status = furi_message_queue_get(event_queue, &input_event, 100); + + furi_mutex_acquire(program_state->mutex, FuriWaitForever); + + if(event_status == FuriStatusOk) { + if(input_event.type == InputTypePress) { + switch(input_event.key) { + case InputKeyRight: + if(program_state->mfkey_state == Ready) { + program_state->mfkey_state = Help; + } + break; + case InputKeyOk: + if(program_state->mfkey_state == Ready) { + furi_thread_start(program_state->mfkeythread); + } + break; + case InputKeyBack: + if(program_state->mfkey_state == Help) { + program_state->mfkey_state = Ready; + } else { + program_state->close_thread_please = true; + // Wait until thread is finished + furi_thread_join(program_state->mfkeythread); + main_loop = false; + } + break; + default: + break; + } + } + } + + furi_mutex_release(program_state->mutex); + view_port_update(view_port); + } + + // Thread joined in back event handler + furi_thread_free(program_state->mfkeythread); + view_port_enabled_set(view_port, false); + gui_remove_view_port(gui, view_port); + furi_record_close(RECORD_GUI); + view_port_free(view_port); + furi_message_queue_free(event_queue); + furi_mutex_free(program_state->mutex); + free(program_state); + + return 0; +} +#pragma GCC pop_options diff --git a/applications/system/mfkey/mfkey.h b/applications/system/mfkey/mfkey.h new file mode 100644 index 000000000..4a7ab3423 --- /dev/null +++ b/applications/system/mfkey/mfkey.h @@ -0,0 +1,108 @@ +#ifndef MFKEY_H +#define MFKEY_H + +#include +#include +#include +#include +#include +#include +#include + +struct Crypto1State { + uint32_t odd, even; +}; +struct Msb { + int tail; + uint32_t states[768]; +}; + +typedef enum { + MissingNonces, + ZeroNonces, + InsufficientRAM, +} MFKeyError; + +typedef enum { + Ready, + Initializing, + DictionaryAttack, + MFKeyAttack, + Complete, + Error, + Help, +} MFKeyState; + +// TODO: Can we eliminate any of the members of this struct? +typedef struct { + FuriMutex* mutex; + MFKeyError err; + MFKeyState mfkey_state; + int cracked; + int unique_cracked; + int num_completed; + int num_candidates; + int total; + int dict_count; + int search; + int eta_timestamp; + int eta_total; + int eta_round; + bool mfkey32_present; + bool nested_present; + bool close_thread_please; + FuriThread* mfkeythread; + KeysDict* cuid_dict; +} ProgramState; + +typedef enum { + mfkey32, + static_nested, + static_encrypted +} AttackType; + +typedef struct { + AttackType attack; + MfClassicKey key; // key + uint32_t uid; // serial number + uint32_t nt0; // tag challenge first + uint32_t nt1; // tag challenge second + uint32_t uid_xor_nt0; // uid ^ nt0 + uint32_t uid_xor_nt1; // uid ^ nt1 + union { + // Mfkey32 + struct { + uint32_t p64; // 64th successor of nt0 + uint32_t p64b; // 64th successor of nt1 + uint32_t nr0_enc; // first encrypted reader challenge + uint32_t ar0_enc; // first encrypted reader response + uint32_t nr1_enc; // second encrypted reader challenge + uint32_t ar1_enc; // second encrypted reader response + }; + // Nested + struct { + uint32_t ks1_1_enc; // first encrypted keystream + uint32_t ks1_2_enc; // second encrypted keystream + char par_1_str[5]; // first parity bits (string representation) + char par_2_str[5]; // second parity bits (string representation) + uint8_t par_1; // first parity bits + uint8_t par_2; // second parity bits + }; + }; +} MfClassicNonce; + +typedef struct { + Stream* stream; + uint32_t total_nonces; + MfClassicNonce* remaining_nonce_array; + size_t remaining_nonces; +} MfClassicNonceArray; + +struct KeysDict { + Stream* stream; + size_t key_size; + size_t key_size_symbols; + size_t total_keys; +}; + +#endif // MFKEY_H diff --git a/applications/system/mfkey/mfkey.png b/applications/system/mfkey/mfkey.png new file mode 100644 index 0000000000000000000000000000000000000000..f1694bb335a8619e53cd3b98651ba995cc7a1caf GIT binary patch literal 107 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2xGmzZ=C-xtZVhivIasB`QKad%E=yDy9Qt)(f z4B@z*{KD=)L3iUrapuFX*xK~i1d{R-5*QT~m>F7Tu$Q|1zuOE{%i!ti=d#Wzp$P!I C{~rec literal 0 HcmV?d00001 diff --git a/applications/system/mfkey/plugin_interface.h b/applications/system/mfkey/plugin_interface.h new file mode 100644 index 000000000..e7ca438b8 --- /dev/null +++ b/applications/system/mfkey/plugin_interface.h @@ -0,0 +1,13 @@ +#pragma once + +#define PLUGIN_APP_ID "mfkey" +#define PLUGIN_API_VERSION 1 + +typedef struct { + const char* name; + bool (*napi_mf_classic_mfkey32_nonces_check_presence)(); + bool (*napi_mf_classic_nested_nonces_check_presence)(); + MfClassicNonceArray* ( + *napi_mf_classic_nonce_array_alloc)(KeysDict*, bool, KeysDict*, ProgramState*); + void (*napi_mf_classic_nonce_array_free)(MfClassicNonceArray*); +} MfkeyPlugin; From efcad3a11884d6a971e440f4756692e20269a1e5 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 7 Apr 2025 18:53:52 +0300 Subject: [PATCH 071/125] ofw pr 4178 [ci skip] add prastel 42 by pmazzini --- lib/subghz/protocols/came.c | 44 +++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/lib/subghz/protocols/came.c b/lib/subghz/protocols/came.c index 645f5eee1..bbe3e487f 100644 --- a/lib/subghz/protocols/came.c +++ b/lib/subghz/protocols/came.c @@ -14,12 +14,13 @@ #define TAG "SubGhzProtocolCame" -#define CAME_12_COUNT_BIT 12 -#define CAME_24_COUNT_BIT 24 -#define PRASTEL_COUNT_BIT 25 -#define PRASTEL_NAME "Prastel" -#define AIRFORCE_COUNT_BIT 18 -#define AIRFORCE_NAME "Airforce" +#define CAME_12_COUNT_BIT 12 +#define CAME_24_COUNT_BIT 24 +#define PRASTEL_25_COUNT_BIT 25 +#define PRASTEL_42_COUNT_BIT 42 +#define PRASTEL_NAME "Prastel" +#define AIRFORCE_COUNT_BIT 18 +#define AIRFORCE_NAME "Airforce" static const SubGhzBlockConst subghz_protocol_came_const = { .te_short = 320, @@ -123,6 +124,7 @@ static bool subghz_protocol_encoder_came_get_upload(SubGhzProtocolEncoderCame* i switch(instance->generic.data_count_bit) { case CAME_24_COUNT_BIT: + case PRASTEL_42_COUNT_BIT: // CAME 24 Bit = 24320 us header_te = 76; break; @@ -131,7 +133,7 @@ static bool subghz_protocol_encoder_came_get_upload(SubGhzProtocolEncoderCame* i // CAME 12 Bit Original only! and Airforce protocol = 15040 us header_te = 47; break; - case PRASTEL_COUNT_BIT: + case PRASTEL_25_COUNT_BIT: // PRASTEL = 11520 us header_te = 36; break; @@ -174,7 +176,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - if(instance->generic.data_count_bit > PRASTEL_COUNT_BIT) { + if(instance->generic.data_count_bit > PRASTEL_42_COUNT_BIT) { FURI_LOG_E(TAG, "Wrong number of bits in key"); ret = SubGhzProtocolStatusErrorValueBitCount; break; @@ -268,7 +270,8 @@ void subghz_protocol_decoder_came_feed(void* context, bool level, uint32_t durat if((instance->decoder.decode_count_bit == subghz_protocol_came_const.min_count_bit_for_found) || (instance->decoder.decode_count_bit == AIRFORCE_COUNT_BIT) || - (instance->decoder.decode_count_bit == PRASTEL_COUNT_BIT) || + (instance->decoder.decode_count_bit == PRASTEL_25_COUNT_BIT) || + (instance->decoder.decode_count_bit == PRASTEL_42_COUNT_BIT) || (instance->decoder.decode_count_bit == CAME_24_COUNT_BIT)) { instance->generic.serial = 0x0; instance->generic.btn = 0x0; @@ -337,7 +340,7 @@ SubGhzProtocolStatus if(ret != SubGhzProtocolStatusOk) { break; } - if(instance->generic.data_count_bit > PRASTEL_COUNT_BIT) { + if(instance->generic.data_count_bit > PRASTEL_42_COUNT_BIT) { FURI_LOG_E(TAG, "Wrong number of bits in key"); ret = SubGhzProtocolStatusErrorValueBitCount; break; @@ -350,23 +353,30 @@ void subghz_protocol_decoder_came_get_string(void* context, FuriString* output) furi_assert(context); SubGhzProtocolDecoderCame* instance = context; - uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; + uint32_t code_found_lo = instance->generic.data & 0x000003ffffffffff; uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key( instance->generic.data, instance->generic.data_count_bit); - uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; + uint32_t code_found_reverse_lo = code_found_reverse & 0x000003ffffffffff; + + const char* name = instance->generic.protocol_name; + switch(instance->generic.data_count_bit) { + case PRASTEL_25_COUNT_BIT: + case PRASTEL_42_COUNT_BIT: + name = PRASTEL_NAME; + break; + case AIRFORCE_COUNT_BIT: + name = AIRFORCE_NAME; + break; + } furi_string_cat_printf( output, "%s %dbit\r\n" "Key:0x%08lX\r\n" "Yek:0x%08lX\r\n", - (instance->generic.data_count_bit == PRASTEL_COUNT_BIT ? - PRASTEL_NAME : - (instance->generic.data_count_bit == AIRFORCE_COUNT_BIT ? - AIRFORCE_NAME : - instance->generic.protocol_name)), + name, instance->generic.data_count_bit, code_found_lo, code_found_reverse_lo); From b90e7ab43c96a9b90c45b729ab445b05cbcf404e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 7 Apr 2025 18:54:09 +0300 Subject: [PATCH 072/125] fmt [ci skip] --- applications/main/ibutton/ibutton_cli.c | 6 +++--- applications/main/onewire/onewire_cli.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/main/ibutton/ibutton_cli.c b/applications/main/ibutton/ibutton_cli.c index 7765c0cae..0b9a59586 100644 --- a/applications/main/ibutton/ibutton_cli.c +++ b/applications/main/ibutton/ibutton_cli.c @@ -19,7 +19,7 @@ static void ibutton_cli_print_usage(void) { printf("\tCyfral (2 bytes key_data)\r\n"); printf("\tMetakom (4 bytes key_data), must contain correct parity\r\n"); printf("\t are hex-formatted\r\n"); -}; +} static bool ibutton_cli_parse_key(iButtonProtocols* protocols, iButtonKey* key, FuriString* args) { bool result = false; @@ -112,7 +112,7 @@ static void ibutton_cli_read(PipeSide* pipe) { ibutton_protocols_free(protocols); furi_event_flag_free(event); -}; +} typedef struct { FuriEventFlag* event; @@ -214,7 +214,7 @@ void ibutton_cli_emulate(PipeSide* pipe, FuriString* args) { ibutton_key_free(key); ibutton_worker_free(worker); ibutton_protocols_free(protocols); -}; +} static void execute(PipeSide* pipe, FuriString* args, void* context) { UNUSED(context); diff --git a/applications/main/onewire/onewire_cli.c b/applications/main/onewire/onewire_cli.c index 78ac75bac..193de76e4 100644 --- a/applications/main/onewire/onewire_cli.c +++ b/applications/main/onewire/onewire_cli.c @@ -11,7 +11,7 @@ static void onewire_cli_print_usage(void) { printf("Usage:\r\n"); printf("onewire search\r\n"); -}; +} static void onewire_cli_search(PipeSide* pipe) { UNUSED(pipe); From c4c5148992a08106fe51053ec7c3768c98364c53 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 7 Apr 2025 19:34:32 +0300 Subject: [PATCH 073/125] upd changelog --- CHANGELOG.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a7ca55f6..6561f4662 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,15 @@ * SubGHz: **Fix Hollarm protocol with more verification** * SubGHz: **Fix GangQi protocol** (by @DoberBit and @mishamyte (who spent 2 weeks on this)) * SubGHz: **Came Atomo button hold simulation with full cycle** simulation (to allow proper pairing with receiver) +* SubGHz: Add **Prastel (42bit static code)** support (OFW PR 4178 by @pmazzini) * System: **Night Shift Feature** (dimming backlight in selected time interval) (PR #885 | by @Dmitry422) * System: **Сombining RGB Backlight mod** (by @quen0n) and original backlight support **in one firmware** (+ Rainbow/Wave effect (based on @Willy-JL idea)) (PR #877 #881 | by @Dmitry422) - (**To enable RGB Backlight support go into Notifications settings with Debug mode - ON**) * OFW: LFRFID - **EM4305 support** * OFW: **Universal IR signal selection** * OFW: **BadUSB: Mouse control** +* OFW: **Pinning of settings options** +* OFW: NFC app now can launch MFKey32 +* OFW: BadUSB arbitrary key combinations * OFW PR 4136: BadUSB: Full USB/BLE parameter customization, UI improvements, and more (by @Willy-JL) * OFW: NFC - Added naming for DESFire cards + fix MF3ICD40 cards unable to be read * Apps: Add **FindMyFlipper to system apps and allow autostart** on system boot [app by @MatthewKuKanich](https://github.com/MatthewKuKanich/FindMyFlipper) and autoloader by @Willy-JL - to use app please check how to add keys in [app repo](https://github.com/MatthewKuKanich/FindMyFlipper) @@ -21,8 +25,8 @@ * SubGHz: Various bugfixes and experimental options (rolling counter overflow) (by @xMasterX) * Anims: Disable winter anims * NFC: mfclassic poller fix early key reuse in dictionary attack state machine (by @noproto) -* OFW: NFC app now can launch MFKey32 -* OFW: BadUSB arbitrary key combinations +* OFW: BLE: Slightly increase mfg_data size +* OFW: fbt: Deterministic STARTUP order & additional checks * OFW: JS: Update and fix docs, fix Number.toString() with decimals * OFW: New JS value destructuring * OFW: Docs: Fix doxygen references from PR 4168 From 16e48c8994143f07d2322ecf69e8e1cd195bb988 Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Mon, 7 Apr 2025 20:39:58 +0400 Subject: [PATCH 074/125] cli_vcp: handle tx/rx before connext/disconnect --- applications/services/cli/cli_vcp.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/applications/services/cli/cli_vcp.c b/applications/services/cli/cli_vcp.c index f4b539e26..97cd15df3 100644 --- a/applications/services/cli/cli_vcp.c +++ b/applications/services/cli/cli_vcp.c @@ -15,6 +15,7 @@ #define VCP_IF_NUM 0 #define VCP_MESSAGE_Q_LEN 8 +#define CLI_VCP_TRACE #ifdef CLI_VCP_TRACE #define VCP_TRACE(...) FURI_LOG_T(__VA_ARGS__) #else @@ -195,6 +196,17 @@ static void cli_vcp_internal_event_happened(void* context) { CliVcpInternalEvent event = furi_thread_flags_wait(CliVcpInternalEventAll, FuriFlagWaitAny, 0); furi_check(!(event & FuriFlagError)); + if(event & CliVcpInternalEventRx) { + VCP_TRACE(TAG, "Rx"); + cli_vcp_maybe_receive_data(cli_vcp); + } + + if(event & CliVcpInternalEventTxDone) { + VCP_TRACE(TAG, "TxDone"); + cli_vcp->is_currently_transmitting = false; + cli_vcp_maybe_send_data(cli_vcp); + } + if(event & CliVcpInternalEventDisconnected) { if(!cli_vcp->is_connected) return; FURI_LOG_D(TAG, "Disconnected"); @@ -234,17 +246,6 @@ static void cli_vcp_internal_event_happened(void* context) { cli_main_motd, NULL, cli_vcp->shell_pipe, cli_vcp->main_registry, &cli_main_ext_config); cli_shell_start(cli_vcp->shell); } - - if(event & CliVcpInternalEventRx) { - VCP_TRACE(TAG, "Rx"); - cli_vcp_maybe_receive_data(cli_vcp); - } - - if(event & CliVcpInternalEventTxDone) { - VCP_TRACE(TAG, "TxDone"); - cli_vcp->is_currently_transmitting = false; - cli_vcp_maybe_send_data(cli_vcp); - } } // ============ From 7f45050c87d0ea58283e02c98b6794fe85ddc867 Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Mon, 7 Apr 2025 20:40:34 +0400 Subject: [PATCH 075/125] cli_vcp: disable trace --- applications/services/cli/cli_vcp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/services/cli/cli_vcp.c b/applications/services/cli/cli_vcp.c index 97cd15df3..8c32c1bfa 100644 --- a/applications/services/cli/cli_vcp.c +++ b/applications/services/cli/cli_vcp.c @@ -15,7 +15,6 @@ #define VCP_IF_NUM 0 #define VCP_MESSAGE_Q_LEN 8 -#define CLI_VCP_TRACE #ifdef CLI_VCP_TRACE #define VCP_TRACE(...) FURI_LOG_T(__VA_ARGS__) #else From b39912af11a8b3efe8c6a8b6a78e12dc85b80e19 Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Mon, 7 Apr 2025 23:30:39 +0400 Subject: [PATCH 076/125] cli_perf: advanced error reporting --- .gitignore | 4 ++++ scripts/serial_cli_perf.py | 16 +++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 84b8e8319..79f2a8058 100644 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,7 @@ PVS-Studio.log # JS packages node_modules/ + +# cli_perf script output in case of errors +/block.bin +/return_block.bin diff --git a/scripts/serial_cli_perf.py b/scripts/serial_cli_perf.py index 0fed7c393..0db53dd6a 100644 --- a/scripts/serial_cli_perf.py +++ b/scripts/serial_cli_perf.py @@ -32,16 +32,25 @@ def main(): bytes_to_send = args.length block_size = 1024 + success = True while bytes_to_send: actual_size = min(block_size, bytes_to_send) # can't use 0x03 because that's ASCII ETX, or Ctrl+C - block = bytes([randint(4, 255) for _ in range(actual_size)]) + # block = bytes([randint(4, 255) for _ in range(actual_size)]) + block = bytes([4 + (i // 64) for i in range(actual_size)]) port.write(block) return_block = port.read(actual_size) if return_block != block: - logger.error("Incorrect block received") + with open("block.bin", "wb") as f: + f.write(block) + with open("return_block.bin", "wb") as f: + f.write(return_block) + + logger.error("Incorrect block received. Saved to `block.bin' and `return_block.bin'.") + logger.error(f"{bytes_to_send} bytes left. Aborting.") + success = False break bytes_to_send -= actual_size @@ -49,7 +58,8 @@ def main(): end_time = time() delta = end_time - start_time speed = args.length / delta - print(f"Speed: {speed/1024:.2f} KiB/s") + if success: + print(f"Speed: {speed/1024:.2f} KiB/s") port.write(b"\x03") # Ctrl+C port.close() From 33fa903f7ae7d4f14b48622187be7ccdad6f56c5 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 7 Apr 2025 22:33:56 +0300 Subject: [PATCH 077/125] fix swapped settings --- applications/settings/storage_settings/storage_settings.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/settings/storage_settings/storage_settings.c b/applications/settings/storage_settings/storage_settings.c index b4cde7b6b..07656431c 100644 --- a/applications/settings/storage_settings/storage_settings.c +++ b/applications/settings/storage_settings/storage_settings.c @@ -5,8 +5,8 @@ const SubmenuSettingsHelperDescriptor descriptor_template = { .options_cnt = 6, .options = { - {.name = "About Internal Storage", .scene_id = StorageSettingsSDInfo}, - {.name = "About SD Card", .scene_id = StorageSettingsInternalInfo}, + {.name = "About Internal Storage", .scene_id = StorageSettingsInternalInfo}, + {.name = "About SD Card", .scene_id = StorageSettingsSDInfo}, {.name = "Unmount SD Card", .scene_id = StorageSettingsUnmountConfirm}, {.name = "Format SD Card", .scene_id = StorageSettingsFormatConfirm}, {.name = "Benchmark SD Card", .scene_id = StorageSettingsBenchmarkConfirm}, From 29b865ed21d5e33cab14e444235218cfdd05ac9f Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Mon, 7 Apr 2025 23:54:13 +0400 Subject: [PATCH 078/125] cli_vcp: reset tx flag directly in event handler --- applications/services/cli/cli_vcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/services/cli/cli_vcp.c b/applications/services/cli/cli_vcp.c index 8c32c1bfa..f23f813a2 100644 --- a/applications/services/cli/cli_vcp.c +++ b/applications/services/cli/cli_vcp.c @@ -106,6 +106,7 @@ static void cli_vcp_signal_internal_event(CliVcp* cli_vcp, CliVcpInternalEvent e static void cli_vcp_cdc_tx_done(void* context) { CliVcp* cli_vcp = context; + cli_vcp->is_currently_transmitting = false; cli_vcp_signal_internal_event(cli_vcp, CliVcpInternalEventTxDone); } @@ -202,7 +203,6 @@ static void cli_vcp_internal_event_happened(void* context) { if(event & CliVcpInternalEventTxDone) { VCP_TRACE(TAG, "TxDone"); - cli_vcp->is_currently_transmitting = false; cli_vcp_maybe_send_data(cli_vcp); } From c8cf76f75e2bac68deeb99e646d2b147de8d8be5 Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Mon, 7 Apr 2025 23:56:09 +0400 Subject: [PATCH 079/125] fix formatting --- scripts/serial_cli_perf.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/serial_cli_perf.py b/scripts/serial_cli_perf.py index 0db53dd6a..3d612e6de 100644 --- a/scripts/serial_cli_perf.py +++ b/scripts/serial_cli_perf.py @@ -48,7 +48,9 @@ def main(): with open("return_block.bin", "wb") as f: f.write(return_block) - logger.error("Incorrect block received. Saved to `block.bin' and `return_block.bin'.") + logger.error( + "Incorrect block received. Saved to `block.bin' and `return_block.bin'." + ) logger.error(f"{bytes_to_send} bytes left. Aborting.") success = False break From e712375edc9515fae16f3909325055ed4c0ce65c Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Mon, 7 Apr 2025 23:59:10 +0400 Subject: [PATCH 080/125] cli_vcp: make tx flag volatile --- applications/services/cli/cli_vcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/services/cli/cli_vcp.c b/applications/services/cli/cli_vcp.c index f23f813a2..99f2d7880 100644 --- a/applications/services/cli/cli_vcp.c +++ b/applications/services/cli/cli_vcp.c @@ -50,7 +50,7 @@ struct CliVcp { PipeSide* own_pipe; PipeSide* shell_pipe; - bool is_currently_transmitting; + volatile bool is_currently_transmitting; size_t previous_tx_length; CliRegistry* main_registry; From 6b7a7c570922c50b4aee1b45eaae22fd05cb361f Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Tue, 8 Apr 2025 00:25:31 +0400 Subject: [PATCH 081/125] storage_settings: fix scene ids --- applications/settings/storage_settings/storage_settings.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/settings/storage_settings/storage_settings.c b/applications/settings/storage_settings/storage_settings.c index b4cde7b6b..07656431c 100644 --- a/applications/settings/storage_settings/storage_settings.c +++ b/applications/settings/storage_settings/storage_settings.c @@ -5,8 +5,8 @@ const SubmenuSettingsHelperDescriptor descriptor_template = { .options_cnt = 6, .options = { - {.name = "About Internal Storage", .scene_id = StorageSettingsSDInfo}, - {.name = "About SD Card", .scene_id = StorageSettingsInternalInfo}, + {.name = "About Internal Storage", .scene_id = StorageSettingsInternalInfo}, + {.name = "About SD Card", .scene_id = StorageSettingsSDInfo}, {.name = "Unmount SD Card", .scene_id = StorageSettingsUnmountConfirm}, {.name = "Format SD Card", .scene_id = StorageSettingsFormatConfirm}, {.name = "Benchmark SD Card", .scene_id = StorageSettingsBenchmarkConfirm}, From 75070588701cbb03338dded6107409b3b6e59c15 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Tue, 8 Apr 2025 18:00:10 +0700 Subject: [PATCH 082/125] Start working with LCD color inversion --- applications/services/gui/canvas.c | 47 +++++++++++++++++++ .../services/notification/notification_app.c | 10 ---- .../services/notification/notification_app.h | 5 +- .../notification_settings_app.c | 24 ++++++++++ lib/u8g2/u8g2.h | 1 + lib/u8g2/u8g2_buffer.c | 7 +++ 6 files changed, 83 insertions(+), 11 deletions(-) diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index 337789dd3..22addd9ff 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -6,6 +6,8 @@ #include #include +#include + const CanvasFontParameters canvas_font_params[FontTotalNumber] = { [FontPrimary] = {.leading_default = 12, .leading_min = 11, .height = 8, .descender = 2}, [FontSecondary] = {.leading_default = 11, .leading_min = 9, .height = 7, .descender = 2}, @@ -141,11 +143,39 @@ const CanvasFontParameters* canvas_get_font_params(const Canvas* canvas, Font fo void canvas_clear(Canvas* canvas) { furi_check(canvas); + furi_delay_ms (500); + NotificationApp* app = malloc (sizeof(NotificationApp)); + app = furi_record_open(RECORD_NOTIFICATION); + + // open Notification record for access to NotificationApp settings + // NotificationApp* app = malloc (sizeof(NotificationApp)); + // app = furi_record_open(RECORD_NOTIFICATION); + + if(app->settings.lcd_inverse) { + u8g2_FillBuffer(&canvas->fb); + } else { + u8g2_ClearBuffer(&canvas->fb); + } + u8g2_ClearBuffer(&canvas->fb); + // furi_record_close (RECORD_NOTIFICATION); + // free (app); } void canvas_set_color(Canvas* canvas, Color color) { furi_check(canvas); + furi_delay_ms (500); + // open Notification record for access to NotificationApp settings + NotificationApp* app = malloc (sizeof(NotificationApp)); + app = furi_record_open(RECORD_NOTIFICATION); + + if(app->settings.lcd_inverse) { + if(color == ColorBlack) { + color = ColorWhite; + } else if(color == ColorWhite) { + color = ColorBlack; + } + } u8g2_SetDrawColor(&canvas->fb, color); } @@ -155,6 +185,23 @@ void canvas_set_font_direction(Canvas* canvas, CanvasDirection dir) { } void canvas_invert_color(Canvas* canvas) { + + // // open Notification record for access to NotificationApp settings + // NotificationApp* app = malloc (sizeof(NotificationApp)); + // app = furi_record_open(RECORD_NOTIFICATION); + + // if((canvas->fb.draw_color == ColorXOR) && app->settings.lcd_inverse) { + // // ColorXOR = 0x02, inversion change it to White = 0x00 + // // but if we have lcd_inverse ON then we need Black =0x01 instead White 0x00 + // // so we force changing color to black + // canvas->fb.draw_color = ColorBlack; + // } else { + // canvas->fb.draw_color = !canvas->fb.draw_color; + // } + + // furi_record_close (RECORD_NOTIFICATION); + // free (app); + canvas->fb.draw_color = !canvas->fb.draw_color; } diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index b50017963..9a6b4a3da 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -56,10 +56,6 @@ void night_shift_timer_callback(void* context) { NotificationApp* app = context; DateTime current_date_time; - // IN DEVELOPMENT - // // save current night_shift; - // float old_night_shift = app->current_night_shift; - // take system time and convert to minutes furi_hal_rtc_get_datetime(¤t_date_time); uint32_t time = current_date_time.hour * 60 + current_date_time.minute; @@ -73,12 +69,6 @@ void night_shift_timer_callback(void* context) { app->current_night_shift = app->settings.night_shift; app->rgb_srv->current_night_shift = app->settings.night_shift; } - - // IN DEVELOPMENT - // // if night shift was changed then update stock and rgb backlight to new value - // if(old_night_shift != app->current_night_shift) { - // notification_message(app, &sequence_display_backlight_on); - // } } // --- NIGHT SHIFT END --- diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 2ef84ba95..d027bf200 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -34,7 +34,7 @@ typedef struct { Light light; } NotificationLedLayer; -#define NOTIFICATION_SETTINGS_VERSION 0x03 +#define NOTIFICATION_SETTINGS_VERSION 0x04 #define NOTIFICATION_SETTINGS_PATH INT_PATH(NOTIFICATION_SETTINGS_FILE_NAME) typedef struct { @@ -48,8 +48,11 @@ typedef struct { float night_shift; uint32_t night_shift_start; uint32_t night_shift_end; + bool lcd_inverse; } NotificationSettings; +//extern NotificationSettings settings; + struct NotificationApp { FuriMessageQueue* queue; FuriPubSub* event_record; diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 86176c8e5..7b239a077 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -270,6 +270,13 @@ const uint32_t night_shift_end_value[NIGHT_SHIFT_END_COUNT] = { // --- NIGHT SHIFT END --- +#define LCD_INVERSE_COUNT 2 +const char* const lcd_inverse_text[LCD_INVERSE_COUNT] = { + "OFF", + "ON", +}; +const bool lcd_inverse_value[LCD_INVERSE_COUNT] = {false, true}; + static void contrast_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -341,6 +348,16 @@ static void vibro_changed(VariableItem* item) { notification_message(app->notification, &sequence_single_vibro); } +static void lcd_inverse_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, lcd_inverse_text[index]); + app->notification->settings.lcd_inverse = lcd_inverse_value[index]; + notification_message(app->notification, &sequence_display_backlight_on); + +} + //--- RGB BACKLIGHT --- static void rgb_backlight_installed_changed(VariableItem* item) { @@ -721,6 +738,13 @@ static NotificationAppSettings* alloc_settings(void) { variable_item_set_current_value_text(item, vibro_text[value_index]); } + item = variable_item_list_add( + app->variable_item_list, "LCD Inverse", LCD_INVERSE_COUNT, lcd_inverse_changed, app); + value_index = value_index_bool( + app->notification->settings.lcd_inverse, lcd_inverse_value, LCD_INVERSE_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, lcd_inverse_text[value_index]); + //--- RGB BACKLIGHT --- app->variable_item_list_rgb = variable_item_list_alloc(); diff --git a/lib/u8g2/u8g2.h b/lib/u8g2/u8g2.h index c37f3b931..100b56d57 100644 --- a/lib/u8g2/u8g2.h +++ b/lib/u8g2/u8g2.h @@ -3548,6 +3548,7 @@ void u8g2_Setup_a2printer_384x240_f( void u8g2_SendBuffer(u8g2_t* u8g2); void u8g2_ClearBuffer(u8g2_t* u8g2); +void u8g2_FillBuffer(u8g2_t* u8g2); void u8g2_SetBufferCurrTileRow(u8g2_t* u8g2, uint8_t row) U8G2_NOINLINE; diff --git a/lib/u8g2/u8g2_buffer.c b/lib/u8g2/u8g2_buffer.c index 45855bd5d..57f4f84be 100644 --- a/lib/u8g2/u8g2_buffer.c +++ b/lib/u8g2/u8g2_buffer.c @@ -45,6 +45,13 @@ void u8g2_ClearBuffer(u8g2_t* u8g2) { memset(u8g2->tile_buf_ptr, 0, cnt); } +void u8g2_FillBuffer(u8g2_t* u8g2) { + size_t cnt; + cnt = u8g2_GetU8x8(u8g2)->display_info->tile_width; + cnt *= u8g2->tile_buf_height; + cnt *= 8; + memset(u8g2->tile_buf_ptr, 255, cnt); +} /*============================================*/ static void u8g2_send_tile_row(u8g2_t* u8g2, uint8_t src_tile_row, uint8_t dest_tile_row) { From 9a6aa17beee3e4c9cfe34dd3dc84cc445133aa0a Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Tue, 8 Apr 2025 16:02:33 +0400 Subject: [PATCH 083/125] cli_shell: add safety check to set_prompt --- lib/toolbox/cli/shell/cli_shell.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/toolbox/cli/shell/cli_shell.c b/lib/toolbox/cli/shell/cli_shell.c index daf5065ec..445a5f2aa 100644 --- a/lib/toolbox/cli/shell/cli_shell.c +++ b/lib/toolbox/cli/shell/cli_shell.c @@ -474,5 +474,6 @@ void cli_shell_join(CliShell* shell) { void cli_shell_set_prompt(CliShell* shell, const char* prompt) { furi_check(shell); + furi_check(furi_thread_get_state(shell->thread) == FuriThreadStateStopped); shell->prompt = prompt; } From c77c2d2bb0aec8f1dc825012a242c8a82bcaba9f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 8 Apr 2025 16:49:08 +0300 Subject: [PATCH 084/125] fix order --- applications/system/find_my_flipper/application.fam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/system/find_my_flipper/application.fam b/applications/system/find_my_flipper/application.fam index 380e2a941..c9b870282 100644 --- a/applications/system/find_my_flipper/application.fam +++ b/applications/system/find_my_flipper/application.fam @@ -20,5 +20,5 @@ App( apptype=FlipperAppType.STARTUP, entry_point="findmy_startup", sources=["findmy_startup.c", "findmy_state.c"], - order=1000, + order=1210, ) From 4140952605a60b42a8c282bc46a5ca6505eb9bf2 Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Tue, 8 Apr 2025 18:05:08 +0400 Subject: [PATCH 085/125] cli_registry: move from bptree to dict, fix memory leak --- lib/toolbox/cli/cli_registry.c | 32 +++++++++---------- lib/toolbox/cli/cli_registry_i.h | 18 +++-------- lib/toolbox/cli/shell/cli_shell.c | 14 ++++---- lib/toolbox/cli/shell/cli_shell_completions.c | 6 ++-- 4 files changed, 29 insertions(+), 41 deletions(-) diff --git a/lib/toolbox/cli/cli_registry.c b/lib/toolbox/cli/cli_registry.c index 35bed19f2..91f7c4046 100644 --- a/lib/toolbox/cli/cli_registry.c +++ b/lib/toolbox/cli/cli_registry.c @@ -3,16 +3,16 @@ #include #include -#define TAG "cli" +#define TAG "CliRegistry" struct CliRegistry { - CliCommandTree_t commands; + CliCommandDict_t commands; FuriMutex* mutex; }; CliRegistry* cli_registry_alloc(void) { CliRegistry* registry = malloc(sizeof(CliRegistry)); - CliCommandTree_init(registry->commands); + CliCommandDict_init(registry->commands); registry->mutex = furi_mutex_alloc(FuriMutexTypeRecursive); return registry; } @@ -20,7 +20,7 @@ CliRegistry* cli_registry_alloc(void) { void cli_registry_free(CliRegistry* registry) { furi_check(furi_mutex_acquire(registry->mutex, FuriWaitForever) == FuriStatusOk); furi_mutex_free(registry->mutex); - CliCommandTree_clear(registry->commands); + CliCommandDict_clear(registry->commands); free(registry); } @@ -61,7 +61,7 @@ void cli_registry_add_command_ex( }; furi_check(furi_mutex_acquire(registry->mutex, FuriWaitForever) == FuriStatusOk); - CliCommandTree_set_at(registry->commands, name_str, command); + CliCommandDict_set_at(registry->commands, name_str, command); furi_check(furi_mutex_release(registry->mutex) == FuriStatusOk); furi_string_free(name_str); @@ -79,7 +79,7 @@ void cli_registry_delete_command(CliRegistry* registry, const char* name) { } while(name_replace != FURI_STRING_FAILURE); furi_check(furi_mutex_acquire(registry->mutex, FuriWaitForever) == FuriStatusOk); - CliCommandTree_erase(registry->commands, name_str); + CliCommandDict_erase(registry->commands, name_str); furi_check(furi_mutex_release(registry->mutex) == FuriStatusOk); furi_string_free(name_str); @@ -91,7 +91,7 @@ bool cli_registry_get_command( CliRegistryCommand* result) { furi_assert(registry); furi_check(furi_mutex_acquire(registry->mutex, FuriWaitForever) == FuriStatusOk); - CliRegistryCommand* data = CliCommandTree_get(registry->commands, command); + CliRegistryCommand* data = CliCommandDict_get(registry->commands, command); if(data) *result = *data; furi_check(furi_mutex_release(registry->mutex) == FuriStatusOk); @@ -103,16 +103,14 @@ void cli_registry_remove_external_commands(CliRegistry* registry) { furi_check(registry); furi_check(furi_mutex_acquire(registry->mutex, FuriWaitForever) == FuriStatusOk); - // FIXME FL-3977: memory leak somewhere within this function - - CliCommandTree_t internal_cmds; - CliCommandTree_init(internal_cmds); + CliCommandDict_t internal_cmds; + CliCommandDict_init(internal_cmds); for - M_EACH(item, registry->commands, CliCommandTree_t) { - if(!(item->value_ptr->flags & CliCommandFlagExternal)) - CliCommandTree_set_at(internal_cmds, *item->key_ptr, *item->value_ptr); + M_EACH(item, registry->commands, CliCommandDict_t) { + if(!(item->value.flags & CliCommandFlagExternal)) + CliCommandDict_set_at(internal_cmds, item->key, item->value); } - CliCommandTree_move(registry->commands, internal_cmds); + CliCommandDict_move(registry->commands, internal_cmds); furi_check(furi_mutex_release(registry->mutex) == FuriStatusOk); } @@ -148,7 +146,7 @@ void cli_registry_reload_external_commands( .execute_callback = NULL, .flags = CliCommandFlagExternal, }; - CliCommandTree_set_at(registry->commands, plugin_name, command); + CliCommandDict_set_at(registry->commands, plugin_name, command); } furi_string_free(plugin_name); @@ -172,7 +170,7 @@ void cli_registry_unlock(CliRegistry* registry) { furi_mutex_release(registry->mutex); } -CliCommandTree_t* cli_registry_get_commands(CliRegistry* registry) { +CliCommandDict_t* cli_registry_get_commands(CliRegistry* registry) { furi_assert(registry); return ®istry->commands; } diff --git a/lib/toolbox/cli/cli_registry_i.h b/lib/toolbox/cli/cli_registry_i.h index 95b7c55da..31995832f 100644 --- a/lib/toolbox/cli/cli_registry_i.h +++ b/lib/toolbox/cli/cli_registry_i.h @@ -6,7 +6,7 @@ #pragma once #include -#include +#include #include "cli_registry.h" #ifdef __cplusplus @@ -22,19 +22,9 @@ typedef struct { size_t stack_depth; } CliRegistryCommand; -#define CLI_COMMANDS_TREE_RANK 4 +DICT_DEF2(CliCommandDict, FuriString*, FURI_STRING_OPLIST, CliRegistryCommand, M_POD_OPLIST); -// -V:BPTREE_DEF2:1103 -// -V:BPTREE_DEF2:524 -BPTREE_DEF2( - CliCommandTree, - CLI_COMMANDS_TREE_RANK, - FuriString*, - FURI_STRING_OPLIST, - CliRegistryCommand, - M_POD_OPLIST); - -#define M_OPL_CliCommandTree_t() BPTREE_OPLIST2(CliCommandTree, FURI_STRING_OPLIST, M_POD_OPLIST) +#define M_OPL_CliCommandDict_t() DICT_OPLIST(CliCommandDict, FURI_STRING_OPLIST, M_POD_OPLIST) bool cli_registry_get_command( CliRegistry* registry, @@ -48,7 +38,7 @@ void cli_registry_unlock(CliRegistry* registry); /** * @warning Surround calls to this function with `cli_registry_[un]lock` */ -CliCommandTree_t* cli_registry_get_commands(CliRegistry* registry); +CliCommandDict_t* cli_registry_get_commands(CliRegistry* registry); #ifdef __cplusplus } diff --git a/lib/toolbox/cli/shell/cli_shell.c b/lib/toolbox/cli/shell/cli_shell.c index 445a5f2aa..8aa7c387a 100644 --- a/lib/toolbox/cli/shell/cli_shell.c +++ b/lib/toolbox/cli/shell/cli_shell.c @@ -103,15 +103,15 @@ void cli_command_help(PipeSide* pipe, FuriString* args, void* context) { printf("Available commands:\r\n" ANSI_FG_GREEN); cli_registry_lock(registry); - CliCommandTree_t* commands = cli_registry_get_commands(registry); - size_t commands_count = CliCommandTree_size(*commands); + CliCommandDict_t* commands = cli_registry_get_commands(registry); + size_t commands_count = CliCommandDict_size(*commands); - CliCommandTree_it_t iterator; - CliCommandTree_it(iterator, *commands); + CliCommandDict_it_t iterator; + CliCommandDict_it(iterator, *commands); for(size_t i = 0; i < commands_count; i++) { - const CliCommandTree_itref_t* item = CliCommandTree_cref(iterator); - printf("%-30s", furi_string_get_cstr(*item->key_ptr)); - CliCommandTree_next(iterator); + const CliCommandDict_itref_t* item = CliCommandDict_cref(iterator); + printf("%-30s", furi_string_get_cstr(item->key)); + CliCommandDict_next(iterator); if(i % columns == columns - 1) printf("\r\n"); } diff --git a/lib/toolbox/cli/shell/cli_shell_completions.c b/lib/toolbox/cli/shell/cli_shell_completions.c index 823f91fb9..7a178705d 100644 --- a/lib/toolbox/cli/shell/cli_shell_completions.c +++ b/lib/toolbox/cli/shell/cli_shell_completions.c @@ -111,10 +111,10 @@ void cli_shell_completions_fill_variants(CliShellCompletions* completions) { if(segment.type == CliShellCompletionSegmentTypeCommand) { CliRegistry* registry = completions->registry; cli_registry_lock(registry); - CliCommandTree_t* commands = cli_registry_get_commands(registry); + CliCommandDict_t* commands = cli_registry_get_commands(registry); for - M_EACH(registered_command, *commands, CliCommandTree_t) { - FuriString* command_name = *registered_command->key_ptr; + M_EACH(registered_command, *commands, CliCommandDict_t) { + FuriString* command_name = registered_command->key; if(furi_string_start_with(command_name, input)) { CommandCompletions_push_back(completions->variants, command_name); } From bdf2c4ce241e9daaab8a5426bcd7c347db0ac7bc Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 8 Apr 2025 17:50:30 +0300 Subject: [PATCH 086/125] more order changes --- applications/services/namechanger/application.fam | 4 ++-- applications/services/rgb_backlight/application.fam | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/services/namechanger/application.fam b/applications/services/namechanger/application.fam index 0eaeab987..2edeb22df 100644 --- a/applications/services/namechanger/application.fam +++ b/applications/services/namechanger/application.fam @@ -4,5 +4,5 @@ App( entry_point="namechanger_on_system_start", requires=["storage", "cli", "bt"], conflicts=["updater"], - order=600, -) \ No newline at end of file + order=1300, +) diff --git a/applications/services/rgb_backlight/application.fam b/applications/services/rgb_backlight/application.fam index 631ca01d5..39954efaa 100644 --- a/applications/services/rgb_backlight/application.fam +++ b/applications/services/rgb_backlight/application.fam @@ -5,6 +5,6 @@ App( entry_point="rgb_backlight_srv", cdefines=["SRV_RGB_BACKLIGHT"], stack_size=1 * 1024, - order=95, + order=1290, sdk_headers=["rgb_backlight.h"], ) From 7286560c231ee69d699eeac8677bc728589c84f6 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 8 Apr 2025 17:52:27 +0300 Subject: [PATCH 087/125] upd changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6561f4662..26c36a642 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ * SubGHz: Various bugfixes and experimental options (rolling counter overflow) (by @xMasterX) * Anims: Disable winter anims * NFC: mfclassic poller fix early key reuse in dictionary attack state machine (by @noproto) +* OFW PR 4181: vcp, cli: Handle Tx/Rx events before Connect/Disconnect + extra fixes (by @portasynthinca3) * OFW: BLE: Slightly increase mfg_data size * OFW: fbt: Deterministic STARTUP order & additional checks * OFW: JS: Update and fix docs, fix Number.toString() with decimals From 4ec8f21e0928d3734c85f5923dab6f0b76cf2750 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Wed, 9 Apr 2025 22:23:55 +0700 Subject: [PATCH 088/125] still under construction --- applications/services/gui/canvas.c | 45 +++++-------------- .../services/notification/notification_app.c | 5 +++ .../services/notification/notification_app.h | 5 ++- .../notification_settings_app.c | 4 ++ 4 files changed, 22 insertions(+), 37 deletions(-) diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index 22addd9ff..33402ab3c 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -143,33 +143,18 @@ const CanvasFontParameters* canvas_get_font_params(const Canvas* canvas, Font fo void canvas_clear(Canvas* canvas) { furi_check(canvas); - furi_delay_ms (500); - NotificationApp* app = malloc (sizeof(NotificationApp)); - app = furi_record_open(RECORD_NOTIFICATION); - - // open Notification record for access to NotificationApp settings - // NotificationApp* app = malloc (sizeof(NotificationApp)); - // app = furi_record_open(RECORD_NOTIFICATION); - if(app->settings.lcd_inverse) { + if(lcd_inverted) { u8g2_FillBuffer(&canvas->fb); } else { u8g2_ClearBuffer(&canvas->fb); } - - u8g2_ClearBuffer(&canvas->fb); - // furi_record_close (RECORD_NOTIFICATION); - // free (app); } void canvas_set_color(Canvas* canvas, Color color) { furi_check(canvas); - furi_delay_ms (500); - // open Notification record for access to NotificationApp settings - NotificationApp* app = malloc (sizeof(NotificationApp)); - app = furi_record_open(RECORD_NOTIFICATION); - if(app->settings.lcd_inverse) { + if(lcd_inverted) { if(color == ColorBlack) { color = ColorWhite; } else if(color == ColorWhite) { @@ -185,24 +170,14 @@ void canvas_set_font_direction(Canvas* canvas, CanvasDirection dir) { } void canvas_invert_color(Canvas* canvas) { - - // // open Notification record for access to NotificationApp settings - // NotificationApp* app = malloc (sizeof(NotificationApp)); - // app = furi_record_open(RECORD_NOTIFICATION); - - // if((canvas->fb.draw_color == ColorXOR) && app->settings.lcd_inverse) { - // // ColorXOR = 0x02, inversion change it to White = 0x00 - // // but if we have lcd_inverse ON then we need Black =0x01 instead White 0x00 - // // so we force changing color to black - // canvas->fb.draw_color = ColorBlack; - // } else { - // canvas->fb.draw_color = !canvas->fb.draw_color; - // } - - // furi_record_close (RECORD_NOTIFICATION); - // free (app); - - canvas->fb.draw_color = !canvas->fb.draw_color; + if((canvas->fb.draw_color == ColorXOR) && lcd_inverted) { + // ColorXOR = 0x02, inversion change it to White = 0x00 + // but if we have lcd_inverse ON then we need Black =0x01 instead White 0x00 + // so we force changing color to black + canvas->fb.draw_color = ColorBlack; + } else { + canvas->fb.draw_color = !canvas->fb.draw_color; + } } void canvas_set_font(Canvas* canvas, Font font) { diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 9a6b4a3da..8a059586d 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -620,6 +620,8 @@ static NotificationApp* notification_app_alloc(void) { furi_timer_alloc(night_shift_timer_callback, FuriTimerTypePeriodic, app); // --- NIGHT SHIFT END --- + lcd_inverted = false; + return app; } @@ -650,6 +652,9 @@ static void notification_apply_settings(NotificationApp* app) { night_shift_timer_start(app); } // --- NIGHT SHIFT END --- + + //setup global variable "inverted" by settings value; + lcd_inverted = app->settings.lcd_inverse; } static void notification_init_settings(NotificationApp* app) { diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index d027bf200..30673f470 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -51,8 +51,6 @@ typedef struct { bool lcd_inverse; } NotificationSettings; -//extern NotificationSettings settings; - struct NotificationApp { FuriMessageQueue* queue; FuriPubSub* event_record; @@ -72,3 +70,6 @@ struct NotificationApp { void notification_message_save_settings(NotificationApp* app); void night_shift_timer_start(NotificationApp* app); void night_shift_timer_stop(NotificationApp* app); + +//global variable for using in canvac.c +extern bool lcd_inverted; diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 7b239a077..25fc264f8 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -354,6 +354,10 @@ static void lcd_inverse_changed(VariableItem* item) { variable_item_set_current_value_text(item, lcd_inverse_text[index]); app->notification->settings.lcd_inverse = lcd_inverse_value[index]; + + //setup global variable for using in canvas.c + lcd_inverted = lcd_inverse_value[index]; + notification_message(app->notification, &sequence_display_backlight_on); } From 224d4e060bea27a8ede8b45a27fc25d032401762 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Wed, 9 Apr 2025 23:37:30 +0700 Subject: [PATCH 089/125] LCD Inversion finished by MMX --- applications/services/gui/canvas.c | 22 +++++++++++++------ applications/services/gui/canvas.h | 4 ++++ applications/services/gui/canvas_i.h | 1 + .../services/notification/notification_app.c | 14 +++++++++--- .../services/notification/notification_app.h | 3 --- .../notification_settings_app.c | 6 ++--- targets/f7/api_symbols.csv | 4 +++- 7 files changed, 37 insertions(+), 17 deletions(-) diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index 33402ab3c..9c19853d3 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -6,8 +6,6 @@ #include #include -#include - const CanvasFontParameters canvas_font_params[FontTotalNumber] = { [FontPrimary] = {.leading_default = 12, .leading_min = 11, .height = 8, .descender = 2}, [FontSecondary] = {.leading_default = 11, .leading_min = 9, .height = 7, .descender = 2}, @@ -96,6 +94,16 @@ size_t canvas_get_buffer_size(const Canvas* canvas) { return u8g2_GetBufferTileWidth(&canvas->fb) * u8g2_GetBufferTileHeight(&canvas->fb) * 8; } +bool canvas_is_inverted_lcd(Canvas* canvas) { + furi_assert(canvas); + return canvas->lcd_inverse; +} + +void canvas_set_inverted_lcd(Canvas* canvas, bool inverted) { + furi_assert(canvas); + canvas->lcd_inverse = inverted; +} + void canvas_frame_set( Canvas* canvas, int32_t offset_x, @@ -143,8 +151,8 @@ const CanvasFontParameters* canvas_get_font_params(const Canvas* canvas, Font fo void canvas_clear(Canvas* canvas) { furi_check(canvas); - - if(lcd_inverted) { + + if(canvas->lcd_inverse) { u8g2_FillBuffer(&canvas->fb); } else { u8g2_ClearBuffer(&canvas->fb); @@ -154,7 +162,7 @@ void canvas_clear(Canvas* canvas) { void canvas_set_color(Canvas* canvas, Color color) { furi_check(canvas); - if(lcd_inverted) { + if(canvas->lcd_inverse) { if(color == ColorBlack) { color = ColorWhite; } else if(color == ColorWhite) { @@ -170,10 +178,10 @@ void canvas_set_font_direction(Canvas* canvas, CanvasDirection dir) { } void canvas_invert_color(Canvas* canvas) { - if((canvas->fb.draw_color == ColorXOR) && lcd_inverted) { + if((canvas->fb.draw_color == ColorXOR) && canvas->lcd_inverse) { // ColorXOR = 0x02, inversion change it to White = 0x00 // but if we have lcd_inverse ON then we need Black =0x01 instead White 0x00 - // so we force changing color to black + // so we force changing color to black canvas->fb.draw_color = ColorBlack; } else { canvas->fb.draw_color = !canvas->fb.draw_color; diff --git a/applications/services/gui/canvas.h b/applications/services/gui/canvas.h index efd314687..8257c481d 100644 --- a/applications/services/gui/canvas.h +++ b/applications/services/gui/canvas.h @@ -447,6 +447,10 @@ void canvas_draw_icon_bitmap( int16_t h, const Icon* icon); +bool canvas_is_inverted_lcd(Canvas* canvas); + +void canvas_set_inverted_lcd(Canvas* canvas, bool inverted); + #ifdef __cplusplus } #endif diff --git a/applications/services/gui/canvas_i.h b/applications/services/gui/canvas_i.h index 449db71db..d342c07f5 100644 --- a/applications/services/gui/canvas_i.h +++ b/applications/services/gui/canvas_i.h @@ -47,6 +47,7 @@ struct Canvas { CompressIcon* compress_icon; CanvasCallbackPairArray_t canvas_callback_pair; FuriMutex* mutex; + bool lcd_inverse; }; /** Allocate memory and initialize canvas diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 8a059586d..f57900fc5 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -620,7 +620,11 @@ static NotificationApp* notification_app_alloc(void) { furi_timer_alloc(night_shift_timer_callback, FuriTimerTypePeriodic, app); // --- NIGHT SHIFT END --- - lcd_inverted = false; + Gui* tmp_gui = furi_record_open(RECORD_GUI); + Canvas* tmp_canvas = gui_direct_draw_acquire(tmp_gui); + canvas_set_inverted_lcd(tmp_canvas, false); + gui_direct_draw_release(tmp_gui); + furi_record_close(RECORD_GUI); return app; } @@ -653,8 +657,12 @@ static void notification_apply_settings(NotificationApp* app) { } // --- NIGHT SHIFT END --- - //setup global variable "inverted" by settings value; - lcd_inverted = app->settings.lcd_inverse; + //setup canvas variable "inverse" by settings value; + Gui* tmp_gui = furi_record_open(RECORD_GUI); + Canvas* tmp_canvas = gui_direct_draw_acquire(tmp_gui); + canvas_set_inverted_lcd(tmp_canvas, app->settings.lcd_inverse); + gui_direct_draw_release(tmp_gui); + furi_record_close(RECORD_GUI); } static void notification_init_settings(NotificationApp* app) { diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 30673f470..c0b64b807 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -70,6 +70,3 @@ struct NotificationApp { void notification_message_save_settings(NotificationApp* app); void night_shift_timer_start(NotificationApp* app); void night_shift_timer_stop(NotificationApp* app); - -//global variable for using in canvac.c -extern bool lcd_inverted; diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 25fc264f8..d313714fc 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -355,11 +355,11 @@ static void lcd_inverse_changed(VariableItem* item) { variable_item_set_current_value_text(item, lcd_inverse_text[index]); app->notification->settings.lcd_inverse = lcd_inverse_value[index]; - //setup global variable for using in canvas.c - lcd_inverted = lcd_inverse_value[index]; + Canvas* tmp_canvas = gui_direct_draw_acquire(app->gui); + canvas_set_inverted_lcd(tmp_canvas, lcd_inverse_value[index]); + gui_direct_draw_release(app->gui); notification_message(app->notification, &sequence_display_backlight_on); - } //--- RGB BACKLIGHT --- diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 384ae1ea4..db6a1c242 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -852,12 +852,14 @@ Function,+,canvas_get_font_params,const CanvasFontParameters*,"const Canvas*, Fo Function,+,canvas_glyph_width,size_t,"Canvas*, uint16_t" Function,+,canvas_height,size_t,const Canvas* Function,+,canvas_invert_color,void,Canvas* +Function,+,canvas_is_inverted_lcd,_Bool,Canvas* Function,+,canvas_reset,void,Canvas* Function,+,canvas_set_bitmap_mode,void,"Canvas*, _Bool" Function,+,canvas_set_color,void,"Canvas*, Color" Function,+,canvas_set_custom_u8g2_font,void,"Canvas*, const uint8_t*" Function,+,canvas_set_font,void,"Canvas*, Font" Function,+,canvas_set_font_direction,void,"Canvas*, CanvasDirection" +Function,+,canvas_set_inverted_lcd,void,"Canvas*, _Bool" Function,+,canvas_string_width,uint16_t,"Canvas*, const char*" Function,+,canvas_width,size_t,const Canvas* Function,-,cbrt,double,double @@ -3663,8 +3665,8 @@ Function,+,subghz_worker_set_pair_callback,void,"SubGhzWorker*, SubGhzWorkerPair Function,+,subghz_worker_start,void,SubGhzWorker* Function,+,subghz_worker_stop,void,SubGhzWorker* Function,+,submenu_add_item,void,"Submenu*, const char*, uint32_t, SubmenuItemCallback, void*" -Function,+,submenu_add_lockable_item,void,"Submenu*, const char*, uint32_t, SubmenuItemCallback, void*, _Bool, const char*" Function,+,submenu_add_item_ex,void,"Submenu*, const char*, uint32_t, SubmenuItemCallbackEx, void*" +Function,+,submenu_add_lockable_item,void,"Submenu*, const char*, uint32_t, SubmenuItemCallback, void*, _Bool, const char*" Function,+,submenu_alloc,Submenu*, Function,+,submenu_change_item_label,void,"Submenu*, uint32_t, const char*" Function,+,submenu_free,void,Submenu* From 75c8cb9715244ea0213e8bdc6a2cea9129c6bc64 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Thu, 10 Apr 2025 00:55:02 +0700 Subject: [PATCH 090/125] Cosmetic code changes --- applications/services/gui/canvas.c | 12 +++++------ applications/services/gui/canvas_i.h | 2 +- .../services/notification/notification_app.c | 4 ++-- .../services/notification/notification_app.h | 2 +- .../notification_settings_app.c | 20 +++++++++---------- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index 9c19853d3..573ad185e 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -96,12 +96,12 @@ size_t canvas_get_buffer_size(const Canvas* canvas) { bool canvas_is_inverted_lcd(Canvas* canvas) { furi_assert(canvas); - return canvas->lcd_inverse; + return canvas->lcd_inversion; } void canvas_set_inverted_lcd(Canvas* canvas, bool inverted) { furi_assert(canvas); - canvas->lcd_inverse = inverted; + canvas->lcd_inversion = inverted; } void canvas_frame_set( @@ -152,7 +152,7 @@ const CanvasFontParameters* canvas_get_font_params(const Canvas* canvas, Font fo void canvas_clear(Canvas* canvas) { furi_check(canvas); - if(canvas->lcd_inverse) { + if(canvas->lcd_inversion) { u8g2_FillBuffer(&canvas->fb); } else { u8g2_ClearBuffer(&canvas->fb); @@ -162,7 +162,7 @@ void canvas_clear(Canvas* canvas) { void canvas_set_color(Canvas* canvas, Color color) { furi_check(canvas); - if(canvas->lcd_inverse) { + if(canvas->lcd_inversion) { if(color == ColorBlack) { color = ColorWhite; } else if(color == ColorWhite) { @@ -178,9 +178,9 @@ void canvas_set_font_direction(Canvas* canvas, CanvasDirection dir) { } void canvas_invert_color(Canvas* canvas) { - if((canvas->fb.draw_color == ColorXOR) && canvas->lcd_inverse) { + if((canvas->fb.draw_color == ColorXOR) && canvas->lcd_inversion) { // ColorXOR = 0x02, inversion change it to White = 0x00 - // but if we have lcd_inverse ON then we need Black =0x01 instead White 0x00 + // but if we have lcd_inversion ON then we need Black =0x01 instead White 0x00 // so we force changing color to black canvas->fb.draw_color = ColorBlack; } else { diff --git a/applications/services/gui/canvas_i.h b/applications/services/gui/canvas_i.h index d342c07f5..420b97e0f 100644 --- a/applications/services/gui/canvas_i.h +++ b/applications/services/gui/canvas_i.h @@ -47,7 +47,7 @@ struct Canvas { CompressIcon* compress_icon; CanvasCallbackPairArray_t canvas_callback_pair; FuriMutex* mutex; - bool lcd_inverse; + bool lcd_inversion; }; /** Allocate memory and initialize canvas diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index f57900fc5..d416c89f9 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -657,10 +657,10 @@ static void notification_apply_settings(NotificationApp* app) { } // --- NIGHT SHIFT END --- - //setup canvas variable "inverse" by settings value; + //setup canvas variable "inversion" by settings value; Gui* tmp_gui = furi_record_open(RECORD_GUI); Canvas* tmp_canvas = gui_direct_draw_acquire(tmp_gui); - canvas_set_inverted_lcd(tmp_canvas, app->settings.lcd_inverse); + canvas_set_inverted_lcd(tmp_canvas, app->settings.lcd_inversion); gui_direct_draw_release(tmp_gui); furi_record_close(RECORD_GUI); } diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index c0b64b807..7ac8528f2 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -48,7 +48,7 @@ typedef struct { float night_shift; uint32_t night_shift_start; uint32_t night_shift_end; - bool lcd_inverse; + bool lcd_inversion; } NotificationSettings; struct NotificationApp { diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index d313714fc..4362039f0 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -270,12 +270,12 @@ const uint32_t night_shift_end_value[NIGHT_SHIFT_END_COUNT] = { // --- NIGHT SHIFT END --- -#define LCD_INVERSE_COUNT 2 -const char* const lcd_inverse_text[LCD_INVERSE_COUNT] = { +#define LCD_INVERSION_COUNT 2 +const char* const lcd_inversion_text[LCD_INVERSION_COUNT] = { "OFF", "ON", }; -const bool lcd_inverse_value[LCD_INVERSE_COUNT] = {false, true}; +const bool lcd_inversion_value[LCD_INVERSION_COUNT] = {false, true}; static void contrast_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); @@ -348,15 +348,15 @@ static void vibro_changed(VariableItem* item) { notification_message(app->notification, &sequence_single_vibro); } -static void lcd_inverse_changed(VariableItem* item) { +static void lcd_inversion_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, lcd_inverse_text[index]); - app->notification->settings.lcd_inverse = lcd_inverse_value[index]; + variable_item_set_current_value_text(item, lcd_inversion_text[index]); + app->notification->settings.lcd_inversion = lcd_inversion_value[index]; Canvas* tmp_canvas = gui_direct_draw_acquire(app->gui); - canvas_set_inverted_lcd(tmp_canvas, lcd_inverse_value[index]); + canvas_set_inverted_lcd(tmp_canvas, lcd_inversion_value[index]); gui_direct_draw_release(app->gui); notification_message(app->notification, &sequence_display_backlight_on); @@ -743,11 +743,11 @@ static NotificationAppSettings* alloc_settings(void) { } item = variable_item_list_add( - app->variable_item_list, "LCD Inverse", LCD_INVERSE_COUNT, lcd_inverse_changed, app); + app->variable_item_list,"LCD inversion",LCD_INVERSION_COUNT,lcd_inversion_changed,app); value_index = value_index_bool( - app->notification->settings.lcd_inverse, lcd_inverse_value, LCD_INVERSE_COUNT); + app->notification->settings.lcd_inversion, lcd_inversion_value, LCD_INVERSION_COUNT); variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, lcd_inverse_text[value_index]); + variable_item_set_current_value_text(item, lcd_inversion_text[value_index]); //--- RGB BACKLIGHT --- From 5e7a8cf94fc0bab6a905c256765b5376cd4a6464 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 10 Apr 2025 03:08:36 +0300 Subject: [PATCH 091/125] bump desktop setting ver [ci skip] --- applications/services/desktop/desktop_settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/services/desktop/desktop_settings.c b/applications/services/desktop/desktop_settings.c index f5d0cf896..bc85b29b5 100644 --- a/applications/services/desktop/desktop_settings.c +++ b/applications/services/desktop/desktop_settings.c @@ -7,7 +7,7 @@ #define TAG "DesktopSettings" #define DESKTOP_SETTINGS_VER_14 (14) -#define DESKTOP_SETTINGS_VER (16) +#define DESKTOP_SETTINGS_VER (17) #define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME) #define DESKTOP_SETTINGS_MAGIC (0x17) From 1b8e87ad53a69ee937a02a18dd9cd70591e3b455 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 10 Apr 2025 03:26:01 +0300 Subject: [PATCH 092/125] upd changelog --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26c36a642..baeba24f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,15 @@ ## Main changes - Current API: 85.0 +**WARNING! After install of this version your Desktop (fav apps) and LCD & Notifications settings will be reset to default values, please configure them again after this update!** (this is required due to big updates on that parts and config struct changes) * SubGHz: Add **Revers RB2 / RB2M Protocol** (static 64 bit) **full support** with add manually (by @xMasterX) * SubGHz: **Fix Hollarm protocol with more verification** * SubGHz: **Fix GangQi protocol** (by @DoberBit and @mishamyte (who spent 2 weeks on this)) * SubGHz: **Came Atomo button hold simulation with full cycle** simulation (to allow proper pairing with receiver) * SubGHz: Add **Prastel (42bit static code)** support (OFW PR 4178 by @pmazzini) -* System: **Night Shift Feature** (dimming backlight in selected time interval) (PR #885 | by @Dmitry422) -* System: **Сombining RGB Backlight mod** (by @quen0n) and original backlight support **in one firmware** (+ Rainbow/Wave effect (based on @Willy-JL idea)) (PR #877 #881 | by @Dmitry422) - (**To enable RGB Backlight support go into Notifications settings with Debug mode - ON**) +* Desktop: **Add support for Favorite App - Ok Long** (Warning! Old favourites apps list will be reset!) (PR #886 | by @DrEverr) +* Display: **LCD Color Inversion** (Settings - LCD and Notifications - LCD inversion.) (PR #887 | by @Dmitry422) +* Display: **Night Shift Feature** (dimming backlight in selected time interval) (PR #885 | by @Dmitry422) +* Display: **Сombining RGB Backlight mod** (by @quen0n) and original backlight support **in one firmware** (+ Rainbow/Wave effect (based on @Willy-JL idea)) (PR #877 #881 | by @Dmitry422) - (**To enable RGB Backlight support go into Notifications settings with Debug mode - ON**) * OFW: LFRFID - **EM4305 support** * OFW: **Universal IR signal selection** * OFW: **BadUSB: Mouse control** From 5eacafa16dd7033547b82fec52205dc34c51b190 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Thu, 10 Apr 2025 18:01:47 +0700 Subject: [PATCH 093/125] Start moving RGB backlight back to Notification service --- applications/services/application.fam | 1 - .../services/notification/application.fam | 2 +- .../services/notification/notification_app.c | 241 +++++++++++++++- .../services/notification/notification_app.h | 35 ++- .../services/rgb_backlight/application.fam | 10 - .../services/rgb_backlight/rgb_backlight.c | 270 ------------------ .../services/rgb_backlight/rgb_backlight.h | 101 ------- .../rgb_backlight/rgb_backlight_settings.c | 109 ------- .../rgb_backlight/rgb_backlight_settings.h | 35 --- .../notification_settings_app.c | 154 +++++----- targets/f7/api_symbols.csv | 16 +- targets/f7/furi_hal/furi_hal_light.c | 2 +- 12 files changed, 333 insertions(+), 643 deletions(-) delete mode 100644 applications/services/rgb_backlight/application.fam delete mode 100644 applications/services/rgb_backlight/rgb_backlight.c delete mode 100644 applications/services/rgb_backlight/rgb_backlight.h delete mode 100644 applications/services/rgb_backlight/rgb_backlight_settings.c delete mode 100644 applications/services/rgb_backlight/rgb_backlight_settings.h diff --git a/applications/services/application.fam b/applications/services/application.fam index 04a2dd607..1b69d2388 100644 --- a/applications/services/application.fam +++ b/applications/services/application.fam @@ -12,6 +12,5 @@ App( "loader", "power", "namechanger_srv", - "rgb_backlight", ], ) diff --git a/applications/services/notification/application.fam b/applications/services/notification/application.fam index fbfdca848..82f94085a 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","rgb_backlight"], + requires=["input"], 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 d416c89f9..2b0fe40f7 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -9,9 +9,9 @@ #include "notification.h" #include "notification_messages.h" #include "notification_app.h" -#include "applications/services/rgb_backlight/rgb_backlight.h" #define TAG "NotificationSrv" +#define COLOR_COUNT (sizeof(colors) / sizeof(RGBBacklightColor)) static const uint8_t minimal_delay = 100; static const uint8_t led_off_values[NOTIFICATION_LED_COUNT] = {0x00, 0x00, 0x00}; @@ -33,6 +33,204 @@ static uint8_t notification_settings_get_display_brightness(NotificationApp* app static uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value); static uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app); + +// --- RGB BACKLIGHT --- + +typedef struct { + char* name; + uint8_t red; + uint8_t green; + uint8_t blue; +} RGBBacklightColor; + +// use one type RGBBacklightColor for current_leds_settings and for static colors definition +static RGBBacklightColor current_led[] = { + {"LED0", 0, 0, 0}, + {"LED1", 0, 0, 0}, + {"LED2", 0, 0, 0}, +}; + +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}, + {"OFF", 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_led_static_color(uint8_t led, uint8_t index) { + if(led < SK6805_get_led_count()) { + uint8_t r = colors[index].red; + uint8_t g = colors[index].green; + uint8_t b = colors[index].blue; + + current_led[led].red = r; + current_led[led].green = g; + current_led[led].blue = b; + + SK6805_set_led_color(led, r, g, b); + } +} + +// HSV to RGB based on +// https://www.radiokot.ru/forum/viewtopic.php?p=3000181&ysclid=m88wvoz34w244644702 +// https://radiolaba.ru/microcotrollers/tsvetnaya-lampa.html#comment-1790 +// https://alexgyver.ru/lessons/arduino-rgb/?ysclid=m88voflppa24464916 +// led number (0-2), hue (0..255), sat (0..255), val (0...1) +void rgb_backlight_set_led_custom_hsv_color(uint8_t led, uint16_t hue, uint8_t sat, float V) { + // init value + float r = 1.0f; + float g = 1.0f; + float b = 1.0f; + + // from (0..255) to (0..1) + float H = hue / 255.0f; + float S = sat / 255.0f; + + uint8_t i = trunc(H * 6); + float f = H * 6 - i; + float p = V * (1 - S); + float q = V * (1 - f * S); + float t = V * (1 - (1 - f) * S); + + switch(i) { + case 0: + r = V, g = t, b = p; + break; + case 1: + r = q, g = V, b = p; + break; + case 2: + r = p, g = V, b = t; + break; + case 3: + r = p, g = q, b = V; + break; + case 4: + r = t, g = p, b = V; + break; + case 5: + r = V, g = p, b = q; + break; + } + + // from (0..1) to (0..255) + current_led[led].red = r * 255; + current_led[led].green = g * 255; + current_led[led].blue = b * 255; +} + +// use RECORD for acces to rgb service instance, set current_* colors to led and update backlight +void rgb_backlight_update(float brightness) { + // RGBBacklightApp* app = furi_record_open(RECORD_RGB_BACKLIGHT); + + // if(app->settings.rgb.rgb_backlight_installed) { + for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { + uint8_t r = current_led[i].red * brightness * 1.0f; + uint8_t g = current_led[i].green * brightness * 1.0f; + uint8_t b = current_led[i].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(NotificationApp* app) { + if(furi_timer_is_running(app->rainbow_timer)) { + furi_timer_stop(app->rainbow_timer); + } + furi_timer_start(app->rainbow_timer, furi_ms_to_ticks(app->settings.rgb.rainbow_speed_ms)); +} + +// stop furi timer for rainbow +void rainbow_timer_stop(NotificationApp* app) { + if(furi_timer_is_running(app->rainbow_timer)) { + furi_timer_stop(app->rainbow_timer); + } +} + +// if rgb_backlight_installed then apply rainbow colors to backlight and start/restart/stop rainbow_timer +void rainbow_timer_starter(NotificationApp* app) { + if((app->settings.rgb.rainbow_mode > 0) && (app->settings.rgb.rgb_backlight_installed)) { + rainbow_timer_start(app); + } +} + +static void rainbow_timer_callback(void* context) { + furi_assert(context); + NotificationApp* app = context; + + if(app->settings.rgb.rgb_backlight_installed) { + app->rainbow_hue += app->settings.rgb.rainbow_step; + if(app->rainbow_hue > 254) { + app->rainbow_hue = 0; + } + + uint8_t wide = app->settings.rgb.rainbow_wide; + + switch(app->settings.rgb.rainbow_mode) { + //rainbow mode + case 1: + for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { + rgb_backlight_set_led_custom_hsv_color( + i, + app->rainbow_hue, + app->settings.rgb.rainbow_saturation, + app->settings.display_brightness); + } + break; + + //wave mode + case 2: + uint16_t j = app->rainbow_hue + wide; + uint16_t k = app->rainbow_hue + wide * 2; + + if(app->rainbow_hue > (254 - wide)) { + j = j - 255; + } + if(app->rainbow_hue > (254 - wide * 2)) { + k = k - 255; + } + + rgb_backlight_set_led_custom_hsv_color( + 0, app->rainbow_hue, app->settings.rgb.rainbow_saturation, app->settings.display_brightness); + rgb_backlight_set_led_custom_hsv_color( + 1, j, app->settings.rgb.rainbow_saturation, app->settings.display_brightness); + rgb_backlight_set_led_custom_hsv_color( + 2, k, app->settings.rgb.rainbow_saturation, app->settings.display_brightness); + break; + + default: + break; + } + + rgb_backlight_update(app->settings.led_brightness * app->current_night_shift); + } +} + +// --- RGB BACKLIGHT ENF--- + + // --- NIGHT SHIFT --- void night_shift_timer_start(NotificationApp* app) { @@ -64,10 +262,8 @@ void night_shift_timer_callback(void* context) { // set values to stock and rgb backlights if((time > app->settings.night_shift_end) && (time < app->settings.night_shift_start)) { app->current_night_shift = 1.0f; - app->rgb_srv->current_night_shift = 1.0f; } else { app->current_night_shift = app->settings.night_shift; - app->rgb_srv->current_night_shift = app->settings.night_shift; } } @@ -267,7 +463,7 @@ static void notification_process_notification_message( 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); + rainbow_timer_starter(app); // --- NIGHT SHIFT END --- } else { reset_mask &= ~reset_display_mask; @@ -276,8 +472,8 @@ static void notification_process_notification_message( 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); + if(furi_timer_is_running(app->rainbow_timer)) { + rainbow_timer_stop(app); } } break; @@ -610,8 +806,7 @@ static NotificationApp* notification_app_alloc(void) { notification_message(app, &sequence_display_backlight_on); // --- NIGHT SHIFT --- - app->rgb_srv = furi_record_open(RECORD_RGB_BACKLIGHT); - app->rgb_srv->current_night_shift = 1.0f; + app->current_night_shift = 1.0f; app->current_night_shift = 1.0f; app->settings.night_shift = 1.0f; app->settings.night_shift_start = 1020; @@ -620,6 +815,7 @@ static NotificationApp* notification_app_alloc(void) { furi_timer_alloc(night_shift_timer_callback, FuriTimerTypePeriodic, app); // --- NIGHT SHIFT END --- + // use RECORD for setup init values to canvas lcd_inverted Gui* tmp_gui = furi_record_open(RECORD_GUI); Canvas* tmp_canvas = gui_direct_draw_acquire(tmp_gui); canvas_set_inverted_lcd(tmp_canvas, false); @@ -682,6 +878,35 @@ int32_t notification_srv(void* p) { UNUSED(p); NotificationApp* app = notification_app_alloc(); + // --- RGB BACKLIGHT SECTION --- + + // define rainbow_timer and they callback + app->rainbow_timer = furi_timer_alloc(rainbow_timer_callback, FuriTimerTypePeriodic, app); + + // init values + app->rainbow_hue = 1; + app->current_night_shift = 1.0f; + + // if rgb_backlight_installed then start rainbow or set leds colors from saved settings (default index = 0) + if(app->settings.rgb.rgb_backlight_installed) { + if(app->settings.rgb.rainbow_mode > 0) { + rainbow_timer_start(app); + } else { + rgb_backlight_set_led_static_color(2, app->settings.rgb.led_2_color_index); + rgb_backlight_set_led_static_color(1, app->settings.rgb.led_1_color_index); + rgb_backlight_set_led_static_color(0, app->settings.rgb.led_0_color_index); + rgb_backlight_update(app->settings.display_brightness * app->current_night_shift); + } + // if rgb_backlight not installed then set default static orange color(index=0) to all leds (0-2) and force light on + } else { + rgb_backlight_set_led_static_color(2, 0); + rgb_backlight_set_led_static_color(1, 0); + rgb_backlight_set_led_static_color(0, 0); + SK6805_update(); + } + + // --- RGB BACKLIGHT SECTION END --- + notification_init_settings(app); notification_vibro_off(); diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 7ac8528f2..7396e695e 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -3,7 +3,8 @@ #include "notification.h" #include "notification_messages.h" #include "notification_settings_filename.h" -#include "applications/services/rgb_backlight/rgb_backlight.h" +#include +#include #define NOTIFICATION_LED_COUNT 3 #define NOTIFICATION_EVENT_COMPLETE 0x00000001U @@ -37,6 +38,23 @@ typedef struct { #define NOTIFICATION_SETTINGS_VERSION 0x04 #define NOTIFICATION_SETTINGS_PATH INT_PATH(NOTIFICATION_SETTINGS_FILE_NAME) +typedef struct { + //Common settings + uint8_t rgb_backlight_installed; + + // static gradient mode settings + uint8_t led_2_color_index; + uint8_t led_1_color_index; + uint8_t led_0_color_index; + + // rainbow mode setings + uint32_t rainbow_mode; + uint32_t rainbow_speed_ms; + uint16_t rainbow_step; + uint8_t rainbow_saturation; + uint8_t rainbow_wide; +} RGBBacklightSettings; + typedef struct { uint8_t version; float display_brightness; @@ -49,6 +67,7 @@ typedef struct { uint32_t night_shift_start; uint32_t night_shift_end; bool lcd_inversion; + RGBBacklightSettings rgb; } NotificationSettings; struct NotificationApp { @@ -61,12 +80,24 @@ struct NotificationApp { uint8_t display_led_lock; NotificationSettings settings; - RGBBacklightApp* rgb_srv; FuriTimer* night_shift_timer; float current_night_shift; + + FuriTimer* rainbow_timer; + uint16_t rainbow_hue; + uint8_t rainbow_red; + uint8_t rainbow_green; + uint8_t rainbow_blue; }; void notification_message_save_settings(NotificationApp* app); void night_shift_timer_start(NotificationApp* app); void night_shift_timer_stop(NotificationApp* app); +void rgb_backlight_update(float brightness); +void rgb_backlight_set_led_static_color(uint8_t led, uint8_t index); +void rainbow_timer_start(NotificationApp* app); +void rainbow_timer_stop(NotificationApp* app); +void rainbow_timer_starter(NotificationApp* app); +const char* rgb_backlight_get_color_text(uint8_t index); +uint8_t rgb_backlight_get_color_count(void); \ No newline at end of file diff --git a/applications/services/rgb_backlight/application.fam b/applications/services/rgb_backlight/application.fam deleted file mode 100644 index 39954efaa..000000000 --- a/applications/services/rgb_backlight/application.fam +++ /dev/null @@ -1,10 +0,0 @@ -App( - appid="rgb_backlight", - name="RgbBackLightSrv", - apptype=FlipperAppType.SERVICE, - entry_point="rgb_backlight_srv", - cdefines=["SRV_RGB_BACKLIGHT"], - stack_size=1 * 1024, - order=1290, - sdk_headers=["rgb_backlight.h"], -) diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c deleted file mode 100644 index 22628e3af..000000000 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - 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" -#include - -#define COLOR_COUNT (sizeof(colors) / sizeof(RGBBacklightColor)) - -#define TAG "RGB_BACKLIGHT_SRV" - -typedef struct { - char* name; - uint8_t red; - uint8_t green; - uint8_t blue; -} RGBBacklightColor; - -// use one type RGBBacklightColor for current_leds_settings and for static colors definition -static RGBBacklightColor current_led[] = { - {"LED0", 0, 0, 0}, - {"LED1", 0, 0, 0}, - {"LED2", 0, 0, 0}, -}; - -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}, - {"OFF", 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_led_static_color(uint8_t led, uint8_t index) { - if(led < SK6805_get_led_count()) { - uint8_t r = colors[index].red; - uint8_t g = colors[index].green; - uint8_t b = colors[index].blue; - - current_led[led].red = r; - current_led[led].green = g; - current_led[led].blue = b; - - SK6805_set_led_color(led, r, g, b); - } -} - -// HSV to RGB based on -// https://www.radiokot.ru/forum/viewtopic.php?p=3000181&ysclid=m88wvoz34w244644702 -// https://radiolaba.ru/microcotrollers/tsvetnaya-lampa.html#comment-1790 -// https://alexgyver.ru/lessons/arduino-rgb/?ysclid=m88voflppa24464916 -// led number (0-2), hue (0..255), sat (0..255), val (0...1) -void rgb_backlight_set_led_custom_hsv_color(uint8_t led, uint16_t hue, uint8_t sat, float V) { - // init value - float r = 1.0f; - float g = 1.0f; - float b = 1.0f; - - // from (0..255) to (0..1) - float H = hue / 255.0f; - float S = sat / 255.0f; - - uint8_t i = trunc(H * 6); - float f = H * 6 - i; - float p = V * (1 - S); - float q = V * (1 - f * S); - float t = V * (1 - (1 - f) * S); - - switch(i) { - case 0: - r = V, g = t, b = p; - break; - case 1: - r = q, g = V, b = p; - break; - case 2: - r = p, g = V, b = t; - break; - case 3: - r = p, g = q, b = V; - break; - case 4: - r = t, g = p, b = V; - break; - case 5: - r = V, g = p, b = q; - break; - } - - // from (0..1) to (0..255) - current_led[led].red = r * 255; - current_led[led].green = g * 255; - current_led[led].blue = b * 255; -} - -// use RECORD for acces to rgb service instance, set current_* colors to led and update backlight -void rgb_backlight_update(float brightness) { - RGBBacklightApp* app = furi_record_open(RECORD_RGB_BACKLIGHT); - - if(app->settings->rgb_backlight_installed) { - for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { - uint8_t r = current_led[i].red * brightness * 1.0f; - uint8_t g = current_led[i].green * brightness * 1.0f; - uint8_t b = current_led[i].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) { - if(furi_timer_is_running(app->rainbow_timer)) { - furi_timer_stop(app->rainbow_timer); - } - 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) { - if(furi_timer_is_running(app->rainbow_timer)) { - furi_timer_stop(app->rainbow_timer); - } -} - -// if rgb_backlight_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_backlight_installed)) { - rainbow_timer_start(app); - } -} - -static void rainbow_timer_callback(void* context) { - furi_assert(context); - RGBBacklightApp* app = context; - - if(app->settings->rgb_backlight_installed) { - app->rainbow_hue += app->settings->rainbow_step; - if(app->rainbow_hue > 254) { - app->rainbow_hue = 0; - } - - uint8_t wide = app->settings->rainbow_wide; - - switch(app->settings->rainbow_mode) { - //rainbow mode - case 1: - for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { - rgb_backlight_set_led_custom_hsv_color( - i, - app->rainbow_hue, - app->settings->rainbow_saturation, - app->settings->brightness); - } - break; - - //wave mode - case 2: - uint16_t j = app->rainbow_hue + wide; - uint16_t k = app->rainbow_hue + wide * 2; - - if(app->rainbow_hue > (254 - wide)) { - j = j - 255; - } - if(app->rainbow_hue > (254 - wide * 2)) { - k = k - 255; - } - - rgb_backlight_set_led_custom_hsv_color( - 0, app->rainbow_hue, app->settings->rainbow_saturation, app->settings->brightness); - rgb_backlight_set_led_custom_hsv_color( - 1, j, app->settings->rainbow_saturation, app->settings->brightness); - rgb_backlight_set_led_custom_hsv_color( - 2, k, app->settings->rainbow_saturation, app->settings->brightness); - break; - - default: - break; - } - - rgb_backlight_update(app->settings->brightness * app->current_night_shift); - } -} - -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)); - - // 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); - - app->rainbow_hue = 1; - app->current_night_shift = 1.0f; - - furi_record_create(RECORD_RGB_BACKLIGHT, app); - - // if rgb_backlight_installed then start rainbow or set leds colors from saved settings (default index = 0) - if(app->settings->rgb_backlight_installed) { - if(app->settings->rainbow_mode > 0) { - rainbow_timer_start(app); - } else { - rgb_backlight_set_led_static_color(2, app->settings->led_2_color_index); - rgb_backlight_set_led_static_color(1, app->settings->led_1_color_index); - rgb_backlight_set_led_static_color(0, app->settings->led_0_color_index); - rgb_backlight_update(app->settings->brightness * app->current_night_shift); - } - // if rgb_backlight not installed then set default static orange color(index=0) to all leds (0-2) and force light on - } else { - rgb_backlight_set_led_static_color(2, 0); - rgb_backlight_set_led_static_color(1, 0); - rgb_backlight_set_led_static_color(0, 0); - SK6805_update(); - } - - while(1) { - furi_delay_ms(5000); - if(app->settings->rgb_backlight_installed) { - FURI_LOG_D(TAG, "RGB backlight enabled - serivce is running"); - } else { - FURI_LOG_D(TAG, "RGB backlight DISABLED - serivce is running"); - } - } - return 0; -} diff --git a/applications/services/rgb_backlight/rgb_backlight.h b/applications/services/rgb_backlight/rgb_backlight.h deleted file mode 100644 index 1be252dc1..000000000 --- a/applications/services/rgb_backlight/rgb_backlight.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - 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 { - FuriTimer* rainbow_timer; - uint16_t rainbow_hue; - uint8_t rainbow_red; - uint8_t rainbow_green; - uint8_t rainbow_blue; - RGBBacklightSettings* settings; - // night_shift multiplicator for leds brightnes coming from Notificatoin app. - float current_night_shift; - -} RGBBacklightApp; - -#define RECORD_RGB_BACKLIGHT "rgb_backlight" - -/** Update leds colors from current_led[i].color and selected bright - * - * @param brightness - Brightness 0..1 - * @return - */ -void rgb_backlight_update(float brightness); - -/** Set current_led[i].color for one led by static color index - * - * @param led - Led number (0..2) - * @param index - Static color index number - * @return - */ -void rgb_backlight_set_led_static_color(uint8_t led, uint8_t index); - -/** Stop rainbow timer - * - * @param app - Instance of RGBBacklightApp from FURI RECORD - * @return - */ -void rainbow_timer_stop(RGBBacklightApp* app); - -/** Start rainbow timer - * - * @param app - Instance of RGBBacklightApp from FURI RECORD - * @return - */ - -/** Start rainbow timer - * - * @param app - Instance of RGBBacklightApp from FURI RECORD - * @return - */ -void rainbow_timer_start(RGBBacklightApp* app); - -/** Start rainbow timer only if all conditions meet (rgb_backlight_installed && rainbow ON) - * - * @param app - Instance of RGBBacklightApp from FURI RECORD - * @return - */ -void rainbow_timer_starter(RGBBacklightApp* app); - -/** Get name of static color by index - * - * @param index - Static colors index number - * @return - color name - */ -const char* rgb_backlight_get_color_text(uint8_t index); - -/** Get static colors count - * - * @param - * @return - colors count - */ -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 deleted file mode 100644 index baa573a77..000000000 --- a/applications/services/rgb_backlight/rgb_backlight_settings.c +++ /dev/null @@ -1,109 +0,0 @@ -#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 (4) // Previous version number -#define RGB_BACKLIGHT_SETTINGS_VER (5) // Current version number - -//pervious settings must be copyed from previous rgb_backlight_settings.h file -typedef struct { - //Common settings - uint8_t version; - uint8_t rgb_backlight_installed; - float brightness; - - // static gradient mode settings - uint8_t led_2_color_index; - uint8_t led_1_color_index; - uint8_t led_0_color_index; - - // rainbow mode setings - uint32_t rainbow_mode; - uint32_t rainbow_speed_ms; - uint16_t rainbow_step; - uint8_t rainbow_saturation; - uint8_t rainbow_wide; - -} 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; - settings->rainbow_saturation = 255; - settings->rainbow_wide = 50; - 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 deleted file mode 100644 index 3f3af005f..000000000 --- a/applications/services/rgb_backlight/rgb_backlight_settings.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include - -typedef struct { - //Common settings - uint8_t version; - uint8_t rgb_backlight_installed; - float brightness; - - // static gradient mode settings - uint8_t led_2_color_index; - uint8_t led_1_color_index; - uint8_t led_0_color_index; - - // rainbow mode setings - uint32_t rainbow_mode; - uint32_t rainbow_speed_ms; - uint16_t rainbow_step; - uint8_t rainbow_saturation; - uint8_t rainbow_wide; - -} 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/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 4362039f0..7907d167d 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -4,9 +4,9 @@ #include #include #include -#include "applications/services/rgb_backlight/rgb_backlight.h" -#define MAX_NOTIFICATION_SETTINGS 4 + +#define MAX_NOTIFICATION_SETTINGS 5 typedef struct { NotificationApp* notification; @@ -293,12 +293,6 @@ 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); } @@ -368,12 +362,9 @@ static void rgb_backlight_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_backlight_installed_text[index]); - app->notification->rgb_srv->settings->rgb_backlight_installed = + app->notification->settings.rgb.rgb_backlight_installed = rgb_backlight_installed_value[index]; - app->notification->rgb_srv->settings->brightness = - app->notification->settings.display_brightness; - // In case of user playing with rgb_backlight_installed swith: // if user swith_off rgb_backlight_installed (but may be he have mod installed) // then force set default orange color and stop rainbow timer @@ -382,18 +373,18 @@ static void rgb_backlight_installed_changed(VariableItem* item) { rgb_backlight_set_led_static_color(1, 0); rgb_backlight_set_led_static_color(0, 0); SK6805_update(); - rainbow_timer_stop(app->notification->rgb_srv); + rainbow_timer_stop(app->notification); // start rainbow (if its Enabled) or set saved static colors if user swith_on rgb_backlight_installed switch } else { - if(app->notification->rgb_srv->settings->rainbow_mode > 0) { - rainbow_timer_starter(app->notification->rgb_srv); + if(app->notification->settings.rgb.rainbow_mode > 0) { + rainbow_timer_starter(app->notification); } else { rgb_backlight_set_led_static_color( - 2, app->notification->rgb_srv->settings->led_2_color_index); + 2, app->notification->settings.rgb.led_2_color_index); rgb_backlight_set_led_static_color( - 1, app->notification->rgb_srv->settings->led_1_color_index); + 1, app->notification->settings.rgb.led_1_color_index); rgb_backlight_set_led_static_color( - 0, app->notification->rgb_srv->settings->led_0_color_index); + 0, app->notification->settings.rgb.led_0_color_index); rgb_backlight_update( app->notification->settings.display_brightness * app->notification->current_night_shift); @@ -413,8 +404,7 @@ static void rgb_backlight_installed_changed(VariableItem* item) { variable_item_set_locked(t_item, false, "RGB\nOFF!"); } } - - rgb_backlight_settings_save(app->notification->rgb_srv->settings); + notification_message_save_settings(app->notification); } static void led_2_color_changed(VariableItem* item) { @@ -422,17 +412,17 @@ static void led_2_color_changed(VariableItem* 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->led_2_color_index = index; + app->notification->settings.rgb.led_2_color_index = index; // dont update screen color if rainbow timer working - if(!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { + if(!furi_timer_is_running(app->notification->rainbow_timer)) { rgb_backlight_set_led_static_color(2, index); rgb_backlight_update( - app->notification->rgb_srv->settings->brightness * + app->notification->settings.display_brightness * app->notification->current_night_shift); } - rgb_backlight_settings_save(app->notification->rgb_srv->settings); + notification_message_save_settings(app->notification); } static void led_1_color_changed(VariableItem* item) { @@ -440,17 +430,17 @@ static void led_1_color_changed(VariableItem* 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->led_1_color_index = index; + app->notification->settings.rgb.led_1_color_index = index; // dont update screen color if rainbow timer working - if(!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { + if(!furi_timer_is_running(app->notification->rainbow_timer)) { rgb_backlight_set_led_static_color(1, index); rgb_backlight_update( - app->notification->rgb_srv->settings->brightness * + app->notification->settings.display_brightness * app->notification->current_night_shift); } - rgb_backlight_settings_save(app->notification->rgb_srv->settings); + notification_message_save_settings(app->notification); } static void led_0_color_changed(VariableItem* item) { @@ -458,17 +448,17 @@ static void led_0_color_changed(VariableItem* 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->led_0_color_index = index; + app->notification->settings.rgb.led_0_color_index = index; // dont update screen color if rainbow timer working - if(!furi_timer_is_running(app->notification->rgb_srv->rainbow_timer)) { + if(!furi_timer_is_running(app->notification->rainbow_timer)) { rgb_backlight_set_led_static_color(0, index); rgb_backlight_update( - app->notification->rgb_srv->settings->brightness * + app->notification->settings.display_brightness * app->notification->current_night_shift); } - rgb_backlight_settings_save(app->notification->rgb_srv->settings); + notification_message_save_settings(app->notification); } static void rgb_backlight_rainbow_changed(VariableItem* item) { @@ -476,25 +466,25 @@ static void rgb_backlight_rainbow_changed(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, rgb_backlight_rainbow_mode_text[index]); - app->notification->rgb_srv->settings->rainbow_mode = rgb_backlight_rainbow_mode_value[index]; + app->notification->settings.rgb.rainbow_mode = rgb_backlight_rainbow_mode_value[index]; // restore saved rgb backlight settings if we switch_off effects if(index == 0) { rgb_backlight_set_led_static_color( - 2, app->notification->rgb_srv->settings->led_2_color_index); + 2, app->notification->settings.rgb.led_2_color_index); rgb_backlight_set_led_static_color( - 1, app->notification->rgb_srv->settings->led_1_color_index); + 1, app->notification->settings.rgb.led_1_color_index); rgb_backlight_set_led_static_color( - 0, app->notification->rgb_srv->settings->led_0_color_index); + 0, app->notification->settings.rgb.led_0_color_index); rgb_backlight_update( - app->notification->rgb_srv->settings->brightness * + app->notification->settings.display_brightness * app->notification->current_night_shift); - rainbow_timer_stop(app->notification->rgb_srv); + rainbow_timer_stop(app->notification); } else { - rainbow_timer_starter(app->notification->rgb_srv); + rainbow_timer_starter(app->notification); } - rgb_backlight_settings_save(app->notification->rgb_srv->settings); + notification_message_save_settings(app->notification); } static void rgb_backlight_rainbow_speed_changed(VariableItem* item) { @@ -502,12 +492,12 @@ static void rgb_backlight_rainbow_speed_changed(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, rgb_backlight_rainbow_speed_text[index]); - app->notification->rgb_srv->settings->rainbow_speed_ms = + app->notification->settings.rgb.rainbow_speed_ms = rgb_backlight_rainbow_speed_value[index]; // save settings and restart timer with new speed value - rainbow_timer_starter(app->notification->rgb_srv); - rgb_backlight_settings_save(app->notification->rgb_srv->settings); + rainbow_timer_starter(app->notification); + notification_message_save_settings(app->notification); } static void rgb_backlight_rainbow_step_changed(VariableItem* item) { @@ -515,9 +505,9 @@ static void rgb_backlight_rainbow_step_changed(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, rgb_backlight_rainbow_step_text[index]); - app->notification->rgb_srv->settings->rainbow_step = rgb_backlight_rainbow_step_value[index]; + app->notification->settings.rgb.rainbow_step = rgb_backlight_rainbow_step_value[index]; - rgb_backlight_settings_save(app->notification->rgb_srv->settings); + notification_message_save_settings(app->notification); } static void rgb_backlight_rainbow_saturation_changed(VariableItem* item) { @@ -528,9 +518,9 @@ static void rgb_backlight_rainbow_saturation_changed(VariableItem* item) { char valtext[4] = {}; snprintf(valtext, sizeof(valtext), "%d", index); variable_item_set_current_value_text(item, valtext); - app->notification->rgb_srv->settings->rainbow_saturation = index; + app->notification->settings.rgb.rainbow_saturation = index; - rgb_backlight_settings_save(app->notification->rgb_srv->settings); + notification_message_save_settings(app->notification); } static void rgb_backlight_rainbow_wide_changed(VariableItem* item) { @@ -538,24 +528,24 @@ static void rgb_backlight_rainbow_wide_changed(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, rgb_backlight_rainbow_wide_text[index]); - app->notification->rgb_srv->settings->rainbow_wide = rgb_backlight_rainbow_wide_value[index]; + app->notification->settings.rgb.rainbow_wide = rgb_backlight_rainbow_wide_value[index]; - rgb_backlight_settings_save(app->notification->rgb_srv->settings); + notification_message_save_settings(app->notification); } -// open rgb_settings_view if user press OK on first (index=0) menu string and (debug mode or rgb_backlight_installed is true) +// open settings.rgb_view if user press OK on first (index=0) menu string and (debug mode or rgb_backlight_installed 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_backlight_installed) || + if(((app->notification->settings.rgb.rgb_backlight_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 +// switch to main view on exit from settings.rgb_view static uint32_t notification_app_rgb_settings_exit(void* context) { UNUSED(context); return MainViewId; @@ -571,14 +561,14 @@ static void night_shift_changed(VariableItem* item) { variable_item_set_current_value_text(item, night_shift_text[index]); app->notification->settings.night_shift = night_shift_value[index]; app->notification->current_night_shift = night_shift_value[index]; - app->notification->rgb_srv->current_night_shift = night_shift_value[index]; + app->notification->current_night_shift = night_shift_value[index]; // force demo night_shift brightness ot rgb backlight and stock backlight notification_message(app->notification, &sequence_display_backlight_on); int slide = 0; if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) || - (app->notification->rgb_srv->settings->rgb_backlight_installed)) { + (app->notification->settings.rgb.rgb_backlight_installed)) { slide = 1; } for(int i = 4 + slide; i < (6 + slide); i++) { @@ -646,7 +636,7 @@ static NotificationAppSettings* alloc_settings(void) { app->variable_item_list, variable_item_list_enter_callback, app); // Show RGB settings only when debug_mode or rgb_backlight_installed is active - if((app->notification->rgb_srv->settings->rgb_backlight_installed) || + if((app->notification->settings.rgb.rgb_backlight_installed) || (furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug))) { item = variable_item_list_add(app->variable_item_list, "RGB settings", 0, NULL, app); } @@ -743,7 +733,7 @@ static NotificationAppSettings* alloc_settings(void) { } item = variable_item_list_add( - app->variable_item_list,"LCD inversion",LCD_INVERSION_COUNT,lcd_inversion_changed,app); + app->variable_item_list, "LCD inversion", LCD_INVERSION_COUNT, lcd_inversion_changed, app); value_index = value_index_bool( app->notification->settings.lcd_inversion, lcd_inversion_value, LCD_INVERSION_COUNT); variable_item_set_current_value_index(item, value_index); @@ -754,7 +744,7 @@ static NotificationAppSettings* alloc_settings(void) { 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 exit from rgb_settings_menu + // set callback for exit from settings.rgb_menu view_set_previous_callback(view_rgb, notification_app_rgb_settings_exit); // Show rgb_backlight_installed swith only in Debug mode @@ -766,7 +756,7 @@ static NotificationAppSettings* alloc_settings(void) { rgb_backlight_installed_changed, app); value_index = value_index_bool( - app->notification->rgb_srv->settings->rgb_backlight_installed, + app->notification->settings.rgb.rgb_backlight_installed, rgb_backlight_installed_value, RGB_BACKLIGHT_INSTALLED_COUNT); variable_item_set_current_value_index(item, value_index); @@ -781,13 +771,11 @@ static NotificationAppSettings* alloc_settings(void) { rgb_backlight_get_color_count(), led_2_color_changed, app); - value_index = app->notification->rgb_srv->settings->led_2_color_index; + value_index = app->notification->settings.rgb.led_2_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->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); + item, (app->notification->settings.rgb.rgb_backlight_installed == 0), "RGB MOD \nOFF!"); // led_2 color item = variable_item_list_add( @@ -796,13 +784,11 @@ static NotificationAppSettings* alloc_settings(void) { rgb_backlight_get_color_count(), led_1_color_changed, app); - value_index = app->notification->rgb_srv->settings->led_1_color_index; + value_index = app->notification->settings.rgb.led_1_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->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); + item, (app->notification->settings.rgb.rgb_backlight_installed == 0), "RGB MOD \nOFF!"); // led 3 color item = variable_item_list_add( @@ -811,13 +797,11 @@ static NotificationAppSettings* alloc_settings(void) { rgb_backlight_get_color_count(), led_0_color_changed, app); - value_index = app->notification->rgb_srv->settings->led_0_color_index; + value_index = app->notification->settings.rgb.led_0_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->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); + item, (app->notification->settings.rgb.rgb_backlight_installed == 0), "RGB MOD \nOFF!"); // Efects item = variable_item_list_add( @@ -827,15 +811,13 @@ static NotificationAppSettings* alloc_settings(void) { rgb_backlight_rainbow_changed, app); value_index = value_index_uint32( - app->notification->rgb_srv->settings->rainbow_mode, + app->notification->settings.rgb.rainbow_mode, rgb_backlight_rainbow_mode_value, RGB_BACKLIGHT_RAINBOW_MODE_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, rgb_backlight_rainbow_mode_text[value_index]); variable_item_set_locked( - item, - (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); + item, (app->notification->settings.rgb.rgb_backlight_installed == 0), "RGB MOD \nOFF!"); item = variable_item_list_add( app->variable_item_list_rgb, @@ -844,15 +826,13 @@ static NotificationAppSettings* alloc_settings(void) { rgb_backlight_rainbow_speed_changed, app); value_index = value_index_uint32( - app->notification->rgb_srv->settings->rainbow_speed_ms, + app->notification->settings.rgb.rainbow_speed_ms, rgb_backlight_rainbow_speed_value, RGB_BACKLIGHT_RAINBOW_SPEED_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, rgb_backlight_rainbow_speed_text[value_index]); variable_item_set_locked( - item, - (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); + item, (app->notification->settings.rgb.rgb_backlight_installed == 0), "RGB MOD \nOFF!"); item = variable_item_list_add( app->variable_item_list_rgb, @@ -861,15 +841,13 @@ static NotificationAppSettings* alloc_settings(void) { rgb_backlight_rainbow_step_changed, app); value_index = value_index_uint32( - app->notification->rgb_srv->settings->rainbow_step, + app->notification->settings.rgb.rainbow_step, rgb_backlight_rainbow_step_value, RGB_BACKLIGHT_RAINBOW_STEP_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, rgb_backlight_rainbow_step_text[value_index]); variable_item_set_locked( - item, - (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); + item, (app->notification->settings.rgb.rgb_backlight_installed == 0), "RGB MOD \nOFF!"); item = variable_item_list_add( app->variable_item_list_rgb, @@ -877,15 +855,13 @@ static NotificationAppSettings* alloc_settings(void) { 255, rgb_backlight_rainbow_saturation_changed, app); - value_index = app->notification->rgb_srv->settings->rainbow_saturation; + value_index = app->notification->settings.rgb.rainbow_saturation; 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->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); + item, (app->notification->settings.rgb.rgb_backlight_installed == 0), "RGB MOD \nOFF!"); item = variable_item_list_add( app->variable_item_list_rgb, @@ -894,15 +870,13 @@ static NotificationAppSettings* alloc_settings(void) { rgb_backlight_rainbow_wide_changed, app); value_index = value_index_uint32( - app->notification->rgb_srv->settings->rainbow_wide, + app->notification->settings.rgb.rainbow_wide, rgb_backlight_rainbow_wide_value, RGB_BACKLIGHT_RAINBOW_WIDE_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, rgb_backlight_rainbow_wide_text[value_index]); variable_item_set_locked( - item, - (app->notification->rgb_srv->settings->rgb_backlight_installed == 0), - "RGB MOD \nOFF!"); + item, (app->notification->settings.rgb.rgb_backlight_installed == 0), "RGB MOD \nOFF!"); //--- RGB BACKLIGHT END --- diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index db6a1c242..beffffd35 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,85.0,, +Version,+,86.0,, 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,, @@ -38,7 +38,6 @@ 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,, @@ -415,10 +414,6 @@ 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 @@ -3138,9 +3133,6 @@ 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, @@ -3159,12 +3151,6 @@ 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_led_static_color,void,"uint8_t, 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 2d6b4bbfe..b9f34e445 100644 --- a/targets/f7/furi_hal/furi_hal_light.c +++ b/targets/f7/furi_hal/furi_hal_light.c @@ -3,7 +3,7 @@ #include #include #include -#include "applications/services/rgb_backlight/rgb_backlight.h" +#include #define LED_CURRENT_RED (50u) #define LED_CURRENT_GREEN (50u) From c88eaffa66986210367f8b68a3520e85ed6b3103 Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Thu, 10 Apr 2025 17:52:19 +0400 Subject: [PATCH 094/125] cli_vcp: go back to message queue for event signaling --- applications/services/cli/cli_vcp.c | 47 +++++++++++++++++------------ 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/applications/services/cli/cli_vcp.c b/applications/services/cli/cli_vcp.c index 99f2d7880..def1949e2 100644 --- a/applications/services/cli/cli_vcp.c +++ b/applications/services/cli/cli_vcp.c @@ -30,20 +30,16 @@ typedef struct { } CliVcpMessage; typedef enum { - CliVcpInternalEventConnected = (1 << 0), - CliVcpInternalEventDisconnected = (1 << 1), - CliVcpInternalEventTxDone = (1 << 2), - CliVcpInternalEventRx = (1 << 3), + CliVcpInternalEventConnected, + CliVcpInternalEventDisconnected, + CliVcpInternalEventTxDone, + CliVcpInternalEventRx, } CliVcpInternalEvent; -#define CliVcpInternalEventAll \ - (CliVcpInternalEventConnected | CliVcpInternalEventDisconnected | CliVcpInternalEventTxDone | \ - CliVcpInternalEventRx) - struct CliVcp { FuriEventLoop* event_loop; FuriMessageQueue* message_queue; // thread_id, event); + furi_check(furi_message_queue_put(cli_vcp->internal_evt_queue, &event, 0) == FuriStatusOk); } static void cli_vcp_cdc_tx_done(void* context) { @@ -191,22 +187,25 @@ static void cli_vcp_message_received(FuriEventLoopObject* object, void* context) /** * Processes messages arriving from CDC event callbacks */ -static void cli_vcp_internal_event_happened(void* context) { +static void cli_vcp_internal_event_happened(FuriEventLoopObject* object, void* context) { CliVcp* cli_vcp = context; - CliVcpInternalEvent event = furi_thread_flags_wait(CliVcpInternalEventAll, FuriFlagWaitAny, 0); - furi_check(!(event & FuriFlagError)); + CliVcpInternalEvent event; + furi_check(furi_message_queue_get(object, &event, 0) == FuriStatusOk); - if(event & CliVcpInternalEventRx) { + switch(event) { + case CliVcpInternalEventRx: { VCP_TRACE(TAG, "Rx"); cli_vcp_maybe_receive_data(cli_vcp); + break; } - if(event & CliVcpInternalEventTxDone) { + case CliVcpInternalEventTxDone: { VCP_TRACE(TAG, "TxDone"); cli_vcp_maybe_send_data(cli_vcp); + break; } - if(event & CliVcpInternalEventDisconnected) { + case CliVcpInternalEventDisconnected: { if(!cli_vcp->is_connected) return; FURI_LOG_D(TAG, "Disconnected"); cli_vcp->is_connected = false; @@ -215,9 +214,10 @@ static void cli_vcp_internal_event_happened(void* context) { pipe_detach_from_event_loop(cli_vcp->own_pipe); pipe_free(cli_vcp->own_pipe); cli_vcp->own_pipe = NULL; + break; } - if(event & CliVcpInternalEventConnected) { + case CliVcpInternalEventConnected: { if(cli_vcp->is_connected) return; FURI_LOG_D(TAG, "Connected"); cli_vcp->is_connected = true; @@ -244,6 +244,8 @@ static void cli_vcp_internal_event_happened(void* context) { cli_vcp->shell = cli_shell_alloc( cli_main_motd, NULL, cli_vcp->shell_pipe, cli_vcp->main_registry, &cli_main_ext_config); cli_shell_start(cli_vcp->shell); + break; + } } } @@ -253,7 +255,6 @@ static void cli_vcp_internal_event_happened(void* context) { static CliVcp* cli_vcp_alloc(void) { CliVcp* cli_vcp = malloc(sizeof(CliVcp)); - cli_vcp->thread_id = furi_thread_get_current_id(); cli_vcp->event_loop = furi_event_loop_alloc(); @@ -265,8 +266,14 @@ static CliVcp* cli_vcp_alloc(void) { cli_vcp_message_received, cli_vcp); - furi_event_loop_subscribe_thread_flags( - cli_vcp->event_loop, cli_vcp_internal_event_happened, cli_vcp); + cli_vcp->internal_evt_queue = + furi_message_queue_alloc(VCP_MESSAGE_Q_LEN, sizeof(CliVcpInternalEvent)); + furi_event_loop_subscribe_message_queue( + cli_vcp->event_loop, + cli_vcp->internal_evt_queue, + FuriEventLoopEventIn, + cli_vcp_internal_event_happened, + cli_vcp); cli_vcp->main_registry = furi_record_open(RECORD_CLI); From 3c18097025bf6554e1976044bea1b8dadb4d6fb7 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Thu, 10 Apr 2025 23:44:57 +0700 Subject: [PATCH 095/125] Moving RGB backlight back to Notification service finished. --- .../services/notification/notification_app.c | 77 ++++++++++++------- .../services/notification/notification_app.h | 5 +- .../notification_settings_app.c | 17 ++-- 3 files changed, 57 insertions(+), 42 deletions(-) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 2b0fe40f7..e57ebbda2 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -10,7 +10,7 @@ #include "notification_messages.h" #include "notification_app.h" -#define TAG "NotificationSrv" +#define TAG "NotificationSrv" #define COLOR_COUNT (sizeof(colors) / sizeof(RGBBacklightColor)) static const uint8_t minimal_delay = 100; @@ -33,9 +33,11 @@ static uint8_t notification_settings_get_display_brightness(NotificationApp* app static uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value); static uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app); - // --- RGB BACKLIGHT --- +// local variable for local use +uint8_t rgb_backlight_installed_variable = 0; + typedef struct { char* name; uint8_t red; @@ -75,7 +77,12 @@ 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 +// function for changind local variable from outside; +void set_rgb_backlight_installed_variable(uint8_t var) { + rgb_backlight_installed_variable = var; +} + +// update led current colors by static void rgb_backlight_set_led_static_color(uint8_t led, uint8_t index) { if(led < SK6805_get_led_count()) { uint8_t r = colors[index].red; @@ -138,11 +145,9 @@ void rgb_backlight_set_led_custom_hsv_color(uint8_t led, uint16_t hue, uint8_t s current_led[led].blue = b * 255; } -// use RECORD for acces to rgb service instance, set current_* colors to led and update backlight +// set current_* colors to led and update backlight void rgb_backlight_update(float brightness) { - // RGBBacklightApp* app = furi_record_open(RECORD_RGB_BACKLIGHT); - - // if(app->settings.rgb.rgb_backlight_installed) { + if(rgb_backlight_installed_variable > 0) { for(uint8_t i = 0; i < SK6805_get_led_count(); i++) { uint8_t r = current_led[i].red * brightness * 1.0f; uint8_t g = current_led[i].green * brightness * 1.0f; @@ -150,8 +155,7 @@ void rgb_backlight_update(float brightness) { SK6805_set_led_color(i, r, g, b); } SK6805_update(); - // } - // furi_record_close(RECORD_RGB_BACKLIGHT); + } } // start furi timer for rainbow @@ -213,7 +217,10 @@ static void rainbow_timer_callback(void* context) { } rgb_backlight_set_led_custom_hsv_color( - 0, app->rainbow_hue, app->settings.rgb.rainbow_saturation, app->settings.display_brightness); + 0, + app->rainbow_hue, + app->settings.rgb.rainbow_saturation, + app->settings.display_brightness); rgb_backlight_set_led_custom_hsv_color( 1, j, app->settings.rgb.rainbow_saturation, app->settings.display_brightness); rgb_backlight_set_led_custom_hsv_color( @@ -228,8 +235,7 @@ static void rainbow_timer_callback(void* context) { } } -// --- RGB BACKLIGHT ENF--- - +// --- RGB BACKLIGHT END--- // --- NIGHT SHIFT --- @@ -815,6 +821,20 @@ static NotificationApp* notification_app_alloc(void) { furi_timer_alloc(night_shift_timer_callback, FuriTimerTypePeriodic, app); // --- NIGHT SHIFT END --- + // init working variables + app->rainbow_hue = 1; + app->current_night_shift = 1.0f; + + // init rgb.segings values + app->settings.rgb.rgb_backlight_installed = 0; + app->settings.rgb.led_2_color_index = 0; + app->settings.rgb.led_1_color_index = 0; + app->settings.rgb.led_0_color_index = 0; + app->settings.rgb.rainbow_speed_ms = 100; + app->settings.rgb.rainbow_step = 1; + app->settings.rgb.rainbow_saturation = 255; + app->settings.rgb.rainbow_wide = 50; + // use RECORD for setup init values to canvas lcd_inverted Gui* tmp_gui = furi_record_open(RECORD_GUI); Canvas* tmp_canvas = gui_direct_draw_acquire(tmp_gui); @@ -847,7 +867,7 @@ static void notification_apply_settings(NotificationApp* app) { notification_apply_lcd_contrast(app); // --- NIGHT SHIFT --- - // if night_shift_enabled start timer for controlling current_night_shift multiplicator value depent from current time + // if night_shift enabled then start timer for controlling current_night_shift multiplicator value depent from current time if(app->settings.night_shift != 1) { night_shift_timer_start(app); } @@ -878,14 +898,24 @@ int32_t notification_srv(void* p) { UNUSED(p); NotificationApp* app = notification_app_alloc(); + notification_init_settings(app); + + notification_vibro_off(); + notification_sound_off(); + notification_apply_internal_led_layer(&app->display, 0x00); + notification_apply_internal_led_layer(&app->led[0], 0x00); + notification_apply_internal_led_layer(&app->led[1], 0x00); + notification_apply_internal_led_layer(&app->led[2], 0x00); + + furi_record_create(RECORD_NOTIFICATION, app); + // --- RGB BACKLIGHT SECTION --- + //setup local variable + set_rgb_backlight_installed_variable(app->settings.rgb.rgb_backlight_installed); + // define rainbow_timer and they callback app->rainbow_timer = furi_timer_alloc(rainbow_timer_callback, FuriTimerTypePeriodic, app); - - // init values - app->rainbow_hue = 1; - app->current_night_shift = 1.0f; // if rgb_backlight_installed then start rainbow or set leds colors from saved settings (default index = 0) if(app->settings.rgb.rgb_backlight_installed) { @@ -897,7 +927,7 @@ int32_t notification_srv(void* p) { rgb_backlight_set_led_static_color(0, app->settings.rgb.led_0_color_index); rgb_backlight_update(app->settings.display_brightness * app->current_night_shift); } - // if rgb_backlight not installed then set default static orange color(index=0) to all leds (0-2) and force light on + // if rgb_backlight not installed then set default static orange color(index=0) to all leds (0-2) and force light on } else { rgb_backlight_set_led_static_color(2, 0); rgb_backlight_set_led_static_color(1, 0); @@ -907,17 +937,6 @@ int32_t notification_srv(void* p) { // --- RGB BACKLIGHT SECTION END --- - notification_init_settings(app); - - notification_vibro_off(); - notification_sound_off(); - notification_apply_internal_led_layer(&app->display, 0x00); - notification_apply_internal_led_layer(&app->led[0], 0x00); - notification_apply_internal_led_layer(&app->led[1], 0x00); - notification_apply_internal_led_layer(&app->led[2], 0x00); - - furi_record_create(RECORD_NOTIFICATION, app); - NotificationAppMessage message; while(1) { furi_check(furi_message_queue_get(app->queue, &message, FuriWaitForever) == FuriStatusOk); diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 7396e695e..239bf69c0 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -35,7 +35,7 @@ typedef struct { Light light; } NotificationLedLayer; -#define NOTIFICATION_SETTINGS_VERSION 0x04 +#define NOTIFICATION_SETTINGS_VERSION 0x05 #define NOTIFICATION_SETTINGS_PATH INT_PATH(NOTIFICATION_SETTINGS_FILE_NAME) typedef struct { @@ -100,4 +100,5 @@ void rainbow_timer_start(NotificationApp* app); void rainbow_timer_stop(NotificationApp* app); void rainbow_timer_starter(NotificationApp* app); const char* rgb_backlight_get_color_text(uint8_t index); -uint8_t rgb_backlight_get_color_count(void); \ No newline at end of file +uint8_t rgb_backlight_get_color_count(void); +void set_rgb_backlight_installed_variable(uint8_t var); diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 7907d167d..8794c53f6 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -5,7 +5,6 @@ #include #include - #define MAX_NOTIFICATION_SETTINGS 5 typedef struct { @@ -362,8 +361,8 @@ static void rgb_backlight_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_backlight_installed_text[index]); - app->notification->settings.rgb.rgb_backlight_installed = - rgb_backlight_installed_value[index]; + app->notification->settings.rgb.rgb_backlight_installed = rgb_backlight_installed_value[index]; + set_rgb_backlight_installed_variable(rgb_backlight_installed_value[index]); // In case of user playing with rgb_backlight_installed swith: // if user swith_off rgb_backlight_installed (but may be he have mod installed) @@ -470,12 +469,9 @@ static void rgb_backlight_rainbow_changed(VariableItem* item) { // restore saved rgb backlight settings if we switch_off effects if(index == 0) { - rgb_backlight_set_led_static_color( - 2, app->notification->settings.rgb.led_2_color_index); - rgb_backlight_set_led_static_color( - 1, app->notification->settings.rgb.led_1_color_index); - rgb_backlight_set_led_static_color( - 0, app->notification->settings.rgb.led_0_color_index); + rgb_backlight_set_led_static_color(2, app->notification->settings.rgb.led_2_color_index); + rgb_backlight_set_led_static_color(1, app->notification->settings.rgb.led_1_color_index); + rgb_backlight_set_led_static_color(0, app->notification->settings.rgb.led_0_color_index); rgb_backlight_update( app->notification->settings.display_brightness * app->notification->current_night_shift); @@ -492,8 +488,7 @@ static void rgb_backlight_rainbow_speed_changed(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, rgb_backlight_rainbow_speed_text[index]); - app->notification->settings.rgb.rainbow_speed_ms = - rgb_backlight_rainbow_speed_value[index]; + app->notification->settings.rgb.rainbow_speed_ms = rgb_backlight_rainbow_speed_value[index]; // save settings and restart timer with new speed value rainbow_timer_starter(app->notification); From b4450946a4f05209415e09b7aa05efdb8e871109 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 10 Apr 2025 20:01:08 +0300 Subject: [PATCH 096/125] upd changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index baeba24f7..6a73e6936 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ * Desktop: **Add support for Favorite App - Ok Long** (Warning! Old favourites apps list will be reset!) (PR #886 | by @DrEverr) * Display: **LCD Color Inversion** (Settings - LCD and Notifications - LCD inversion.) (PR #887 | by @Dmitry422) * Display: **Night Shift Feature** (dimming backlight in selected time interval) (PR #885 | by @Dmitry422) -* Display: **Сombining RGB Backlight mod** (by @quen0n) and original backlight support **in one firmware** (+ Rainbow/Wave effect (based on @Willy-JL idea)) (PR #877 #881 | by @Dmitry422) - (**To enable RGB Backlight support go into Notifications settings with Debug mode - ON**) +* Display: **Сombining RGB Backlight mod** (by @quen0n) and original backlight support **in one firmware** (+ Rainbow/Wave effect (based on @Willy-JL idea)) (PR #877 #881 #890 | by @Dmitry422) - (**To enable RGB Backlight support go into Notifications settings with Debug mode - ON**) * OFW: LFRFID - **EM4305 support** * OFW: **Universal IR signal selection** * OFW: **BadUSB: Mouse control** From 98728fe93ce9d46a52a8873d0cbb402d2f0418f9 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 10 Apr 2025 21:03:59 +0300 Subject: [PATCH 097/125] fix api to ofw --- targets/f7/api_symbols.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index beffffd35..60df2aeb1 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,86.0,, +Version,+,85.0,, 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,, From 3c25c29decde28f7207dd1dcf4151e4b52c8c24e Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Fri, 11 Apr 2025 03:21:53 +0400 Subject: [PATCH 098/125] loader: move BeforeLoad event even earlier --- applications/services/loader/loader.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index d3cd0022e..737d03dd7 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -418,9 +418,6 @@ static void loader_start_internal_app( const FlipperInternalApplication* app, const char* args) { FURI_LOG_I(TAG, "Starting %s", app->name); - LoaderEvent event; - event.type = LoaderEventTypeApplicationBeforeLoad; - furi_pubsub_publish(loader->pubsub, &event); // store args furi_assert(loader->app.args == NULL); @@ -508,9 +505,6 @@ static LoaderMessageLoaderStatusResult loader_start_external_app( result.value = loader_make_success_status(error_message); result.error = LoaderStatusErrorUnknown; - LoaderEvent event; - event.type = LoaderEventTypeApplicationBeforeLoad; - furi_pubsub_publish(loader->pubsub, &event); do { loader->app.fap = flipper_application_alloc(storage, firmware_api_interface); @@ -566,6 +560,7 @@ static LoaderMessageLoaderStatusResult loader_start_external_app( if(result.value != LoaderStatusOk) { flipper_application_free(loader->app.fap); loader->app.fap = NULL; + LoaderEvent event; event.type = LoaderEventTypeApplicationLoadFailed; furi_pubsub_publish(loader->pubsub, &event); } @@ -615,6 +610,10 @@ static LoaderMessageLoaderStatusResult loader_do_start_by_name( status.value = loader_make_success_status(error_message); status.error = LoaderStatusErrorUnknown; + LoaderEvent event; + event.type = LoaderEventTypeApplicationBeforeLoad; + furi_pubsub_publish(loader->pubsub, &event); + do { // check lock if(loader_do_is_locked(loader)) { From 1b5a2496f58459d2c93b369fa324b2b26f2ae73d Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Fri, 11 Apr 2025 03:23:38 +0400 Subject: [PATCH 099/125] fix formatting --- applications/services/loader/loader.c | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index 737d03dd7..136b3c20b 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -505,7 +505,6 @@ static LoaderMessageLoaderStatusResult loader_start_external_app( result.value = loader_make_success_status(error_message); result.error = LoaderStatusErrorUnknown; - do { loader->app.fap = flipper_application_alloc(storage, firmware_api_interface); size_t start = furi_get_tick(); From 837abd7d51d4fee45fb5e57432b440fb18b48344 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 11 Apr 2025 03:00:03 +0300 Subject: [PATCH 100/125] upd changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a73e6936..13cc992c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,8 +21,8 @@ * Apps: Add **FindMyFlipper to system apps and allow autostart** on system boot [app by @MatthewKuKanich](https://github.com/MatthewKuKanich/FindMyFlipper) and autoloader by @Willy-JL - to use app please check how to add keys in [app repo](https://github.com/MatthewKuKanich/FindMyFlipper) * README Update: Enhanced Visuals & Navigation (PR #871 #872 | by @m-xim) * Docs: Update FAQ.md (PR #865 | by @mi-lrn) -* Input: Vibro on Button press option (PR #867 | by @Dmitry422) -* Power: Option to limit battery charging (suppress charging on selected charge level) (PR #867 | by @Dmitry422) (idea and example by @oltenxyz) +* Input: **Vibro on Button press option** (PR #867 | by @Dmitry422) +* Power: **Option to limit battery charging** (suppress charging on selected charge level) (PR #867 | by @Dmitry422) (idea and example by @oltenxyz) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes * SubGHz: Various bugfixes and experimental options (rolling counter overflow) (by @xMasterX) From 936096d2fc3f6d150b53a5e8bf4a6ce735d717cb Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Sat, 12 Apr 2025 01:58:28 +0400 Subject: [PATCH 101/125] cli_completions: fix null dereference --- lib/toolbox/cli/shell/cli_shell_completions.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/toolbox/cli/shell/cli_shell_completions.c b/lib/toolbox/cli/shell/cli_shell_completions.c index 7a178705d..6b6634dbb 100644 --- a/lib/toolbox/cli/shell/cli_shell_completions.c +++ b/lib/toolbox/cli/shell/cli_shell_completions.c @@ -265,6 +265,7 @@ void cli_shell_completions_render( } } else if(action == CliShellCompletionsActionSelectNoClose) { + if(!CommandCompletions_size(completions->variants)) return; // insert selection into prompt CliShellCompletionSegment segment = cli_shell_completions_segment(completions); FuriString* input = cli_shell_line_get_selected(completions->line); From 66a705022176af8faf7dada882fff4551aa302bc Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 12 Apr 2025 03:03:50 +0300 Subject: [PATCH 102/125] free up some ram for now, use settings user --- .../resources/subghz/assets/setting_user.example | 13 +++++++++++++ applications/main/subghz/subghz.c | 7 ++++--- lib/subghz/subghz_setting.c | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/applications/main/subghz/resources/subghz/assets/setting_user.example b/applications/main/subghz/resources/subghz/assets/setting_user.example index 5034659be..9f74ee379 100644 --- a/applications/main/subghz/resources/subghz/assets/setting_user.example +++ b/applications/main/subghz/resources/subghz/assets/setting_user.example @@ -20,6 +20,19 @@ Version: 1 # Custom preset # format for CC1101 "Custom_preset_data:" XX YY XX YY .. 00 00 ZZ ZZ ZZ ZZ ZZ ZZ ZZ ZZ, where: XX-register, YY - register data, 00 00 - end load register, ZZ - 8 byte Pa table register +#Custom_preset_name: FM95 +#Custom_preset_module: CC1101 +#Custom_preset_data: 02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 83 10 67 15 24 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00 + +#2-FSK 200khz BW / 135kHz Filter/ 15.86Khz Deviation + Ramping +#Custom_preset_name: FM15k +#Custom_preset_module: CC1101 +#Custom_preset_data: 02 0D 03 47 08 32 0B 06 15 32 14 00 13 00 12 00 11 32 10 A7 18 18 19 1D 1D 92 1C 00 1B 04 20 FB 22 17 21 B6 00 00 00 12 0E 34 60 C5 C1 C0 + +#Custom_preset_name: Pagers +#Custom_preset_module: CC1101 +#Custom_preset_data: 02 0D 07 04 08 32 0B 06 10 64 11 93 12 0C 13 02 14 00 15 15 18 18 19 16 1B 07 1C 00 1D 91 20 FB 21 56 22 10 00 00 C0 00 00 00 00 00 00 00 + #Custom_preset_name: AM_1 #Custom_preset_module: CC1101 #Custom_preset_data: 02 0D 03 07 08 32 0B 06 14 00 13 00 12 30 11 32 10 17 18 18 19 18 1D 91 1C 00 1B 07 20 FB 22 11 21 B6 00 00 00 C0 00 00 00 00 00 00 diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index cb4fc5504..d07eff2b3 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -56,11 +56,11 @@ static void subghz_rpc_command_callback(const RpcAppSystemEvent* event, void* co rpc_system_app_confirm(subghz->rpc_ctx, false); } } - +/* static void subghz_load_custom_presets(SubGhzSetting* setting) { furi_assert(setting); - const char* presets[][2] = { + const char* presets[3][2] = { {"FM95", "02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 83 10 67 15 24 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00"}, @@ -88,6 +88,7 @@ static void subghz_load_custom_presets(SubGhzSetting* setting) { subghz_setting_customs_presets_to_log(setting); #endif } +*/ SubGhz* subghz_alloc(bool alloc_for_tx_only) { SubGhz* subghz = malloc(sizeof(SubGhz)); @@ -194,7 +195,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); - subghz_load_custom_presets(setting); + //subghz_load_custom_presets(setting); // Load last used values for Read, Read RAW, etc. or default subghz->last_settings = subghz_last_settings_alloc(); diff --git a/lib/subghz/subghz_setting.c b/lib/subghz/subghz_setting.c index 2ee02c7f9..ab8c77910 100644 --- a/lib/subghz/subghz_setting.c +++ b/lib/subghz/subghz_setting.c @@ -296,6 +296,7 @@ void subghz_setting_load(SubGhzSetting* instance, const char* file_path) { FURI_LOG_E(TAG, "Rewind error"); break; } + furi_string_reset(temp_str); while(flipper_format_read_string(fff_data_file, "Custom_preset_name", temp_str)) { FURI_LOG_I(TAG, "Custom preset loaded %s", furi_string_get_cstr(temp_str)); subghz_setting_load_custom_preset( From d67734674ef0d502aa2ddb768bfc033e785a79cb Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 12 Apr 2025 03:04:04 +0300 Subject: [PATCH 103/125] ci fix ? --- .drone.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.drone.yml b/.drone.yml index 15c66192c..347ab1ce1 100644 --- a/.drone.yml +++ b/.drone.yml @@ -204,7 +204,7 @@ steps: - wget "https://raw.githubusercontent.com/fieu/discord.sh/2253303efc0e7211ac2777d2535054cbb872f1e0/discord.sh" - chmod +x ./discord.sh - sed -n '/## Main changes/,/## Other changes/p' CHANGELOG.md | sed -e 's/## Main changes//' -e 's/## Other changes//' > changelogcut.txt - - head -c 1544 changelogcut.txt > changelogcutfin.txt + - head -c 1200 changelogcut.txt > changelogcutfin.txt - truncate -s -1 changelogcutfin.txt - tail -c +2 changelogcutfin.txt > changelogready.txt - rm -f changelogcut.txt @@ -456,7 +456,7 @@ steps: - wget "https://raw.githubusercontent.com/fieu/discord.sh/2253303efc0e7211ac2777d2535054cbb872f1e0/discord.sh" - chmod +x ./discord.sh - sed -n '/## Main changes/,/## Other changes/p' CHANGELOG.md | sed -e 's/## Main changes//' -e 's/## Other changes//' > changelogcut.txt - - head -c 1544 changelogcut.txt > changelogcutfin.txt + - head -c 1200 changelogcut.txt > changelogcutfin.txt - truncate -s -1 changelogcutfin.txt - tail -c +2 changelogcutfin.txt > changelogready.txt - rm -f changelogcut.txt From 455bb8ab1fe6e85e5aa91f0c33b9ad42f62042bc Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 12 Apr 2025 03:07:04 +0300 Subject: [PATCH 104/125] upd changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13cc992c6..d462edff2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ * SubGHz: Various bugfixes and experimental options (rolling counter overflow) (by @xMasterX) * Anims: Disable winter anims * NFC: mfclassic poller fix early key reuse in dictionary attack state machine (by @noproto) +* OFW: Fix NULL dereference in CLI completions * OFW PR 4181: vcp, cli: Handle Tx/Rx events before Connect/Disconnect + extra fixes (by @portasynthinca3) * OFW: BLE: Slightly increase mfg_data size * OFW: fbt: Deterministic STARTUP order & additional checks From 75f5d6fec7715413c3792afa1c3633305abf2814 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 12 Apr 2025 03:11:03 +0300 Subject: [PATCH 105/125] force only default mods --- applications/main/subghz/subghz.c | 4 ++-- applications/main/subghz/subghz_last_settings.c | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index d07eff2b3..c68639c0d 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -199,8 +199,8 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { // Load last used values for Read, Read RAW, etc. or default subghz->last_settings = subghz_last_settings_alloc(); - size_t preset_count = subghz_setting_get_preset_count(setting); - subghz_last_settings_load(subghz->last_settings, preset_count); + //size_t preset_count = subghz_setting_get_preset_count(setting); + subghz_last_settings_load(subghz->last_settings, 0); // Set LED and Amp GPIO control state furi_hal_subghz_set_ext_leds_and_amp(subghz->last_settings->leds_and_amp); diff --git a/applications/main/subghz/subghz_last_settings.c b/applications/main/subghz/subghz_last_settings.c index 174a15a5b..6ffdc858e 100644 --- a/applications/main/subghz/subghz_last_settings.c +++ b/applications/main/subghz/subghz_last_settings.c @@ -31,6 +31,7 @@ void subghz_last_settings_free(SubGhzLastSettings* instance) { } void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count) { + UNUSED(preset_count); furi_assert(instance); // Default values (all others set to 0, if read from file fails these are used) @@ -148,7 +149,7 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count instance->frequency = SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY; } - if(instance->preset_index > (uint32_t)preset_count - 1) { + if(instance->preset_index > 3) { instance->preset_index = SUBGHZ_LAST_SETTING_DEFAULT_PRESET; } } From d5935dc814291a807e1a989b8b727e32461071c6 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 12 Apr 2025 03:11:35 +0300 Subject: [PATCH 106/125] fmt --- applications/services/notification/notification_app.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index e57ebbda2..2df27110e 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -927,7 +927,7 @@ int32_t notification_srv(void* p) { rgb_backlight_set_led_static_color(0, app->settings.rgb.led_0_color_index); rgb_backlight_update(app->settings.display_brightness * app->current_night_shift); } - // if rgb_backlight not installed then set default static orange color(index=0) to all leds (0-2) and force light on + // if rgb_backlight not installed then set default static orange color(index=0) to all leds (0-2) and force light on } else { rgb_backlight_set_led_static_color(2, 0); rgb_backlight_set_led_static_color(1, 0); From a72c5238faf77b36ae4ffa5205fd0cd6598d7b52 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 12 Apr 2025 03:19:57 +0300 Subject: [PATCH 107/125] oops --- applications/main/subghz/subghz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index c68639c0d..83e68229b 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -193,7 +193,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { //init TxRx & Protocol & History & KeyBoard subghz_unlock(subghz); - SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + //SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); //subghz_load_custom_presets(setting); From d542d7d75fc3c6c92ceeba9d045c08340c08f275 Mon Sep 17 00:00:00 2001 From: Mykhailo Shevchuk Date: Sat, 12 Apr 2025 19:25:45 +0300 Subject: [PATCH 108/125] Use default UL/UL-C pwd/key as default value for key input --- applications/main/nfc/helpers/mf_ultralight_auth.c | 6 ++++-- lib/nfc/protocols/mf_ultralight/mf_ultralight.h | 6 ++++++ lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h | 2 -- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/applications/main/nfc/helpers/mf_ultralight_auth.c b/applications/main/nfc/helpers/mf_ultralight_auth.c index e97649cb3..fccf50cdd 100644 --- a/applications/main/nfc/helpers/mf_ultralight_auth.c +++ b/applications/main/nfc/helpers/mf_ultralight_auth.c @@ -18,9 +18,11 @@ void mf_ultralight_auth_free(MfUltralightAuth* instance) { void mf_ultralight_auth_reset(MfUltralightAuth* instance) { furi_assert(instance); + uint32_t default_password = MF_ULTRALIGHT_DEFAULT_PASSWORD; + instance->type = MfUltralightAuthTypeNone; - memset(&instance->password, 0, sizeof(MfUltralightAuthPassword)); - memset(&instance->tdes_key, 0, sizeof(MfUltralightC3DesAuthKey)); + memcpy(&instance->password, &default_password, sizeof(MfUltralightAuthPassword)); + memcpy(&instance->tdes_key, MF_ULTRALIGHT_C_DEFAULT_KEY, sizeof(MfUltralightC3DesAuthKey)); memset(&instance->pack, 0, sizeof(MfUltralightAuthPack)); } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index caf25ceee..191deeda6 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -38,6 +38,7 @@ extern "C" { #define MF_ULTRALIGHT_TEARING_FLAG_NUM (3) #define MF_ULTRALIGHT_AUTH_PASSWORD_SIZE (4) #define MF_ULTRALIGHT_AUTH_PACK_SIZE (2) +#define MF_ULTRALIGHT_DEFAULT_PASSWORD (0xffffffffUL) #define MF_ULTRALIGHT_C_AUTH_RESPONSE_SIZE (9) #define MF_ULTRALIGHT_C_AUTH_DES_KEY_SIZE (16) @@ -47,6 +48,11 @@ extern "C" { #define MF_ULTRALIGHT_C_AUTH_RND_A_BLOCK_OFFSET (0) #define MF_ULTRALIGHT_C_AUTH_RND_B_BLOCK_OFFSET (8) #define MF_ULTRALIGHT_C_ENCRYPTED_PACK_SIZE (MF_ULTRALIGHT_C_AUTH_DATA_SIZE + 1) +#define MF_ULTRALIGHT_C_DEFAULT_KEY \ + (uint8_t[]) { \ + 0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, \ + 0x46 \ + } typedef enum { MfUltralightErrorNone, diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index b35c49aea..6880a0c43 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -11,8 +11,6 @@ extern "C" { #define MF_ULTRALIGHT_POLLER_STANDARD_FWT_FC (60000) #define MF_ULTRALIGHT_MAX_BUFF_SIZE (64) -#define MF_ULTRALIGHT_DEFAULT_PASSWORD (0xffffffffUL) - #define MF_ULTRALIGHT_IS_NTAG_I2C(type) \ (((type) == MfUltralightTypeNTAGI2C1K) || ((type) == MfUltralightTypeNTAGI2C2K) || \ ((type) == MfUltralightTypeNTAGI2CPlus1K) || ((type) == MfUltralightTypeNTAGI2CPlus2K)) From ab26469a05b8dca713e31d65ed82aed9e1d2751e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 12 Apr 2025 20:15:54 +0300 Subject: [PATCH 109/125] upd changelog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d462edff2..0b679620f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ ## Main changes -- Current API: 85.0 +- Current API: 86.0 **WARNING! After install of this version your Desktop (fav apps) and LCD & Notifications settings will be reset to default values, please configure them again after this update!** (this is required due to big updates on that parts and config struct changes) * SubGHz: Add **Revers RB2 / RB2M Protocol** (static 64 bit) **full support** with add manually (by @xMasterX) * SubGHz: **Fix Hollarm protocol with more verification** @@ -10,6 +10,7 @@ * Display: **LCD Color Inversion** (Settings - LCD and Notifications - LCD inversion.) (PR #887 | by @Dmitry422) * Display: **Night Shift Feature** (dimming backlight in selected time interval) (PR #885 | by @Dmitry422) * Display: **Сombining RGB Backlight mod** (by @quen0n) and original backlight support **in one firmware** (+ Rainbow/Wave effect (based on @Willy-JL idea)) (PR #877 #881 #890 | by @Dmitry422) - (**To enable RGB Backlight support go into Notifications settings with Debug mode - ON**) +* NFC: Use default UL/UL-C pwd/key as default value for key input (PR #891 | by @mishamyte) * OFW: LFRFID - **EM4305 support** * OFW: **Universal IR signal selection** * OFW: **BadUSB: Mouse control** @@ -25,9 +26,13 @@ * Power: **Option to limit battery charging** (suppress charging on selected charge level) (PR #867 | by @Dmitry422) (idea and example by @oltenxyz) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes +* SubGHz: Move hardcoded extra modulations to user config - uncomment them in setting_user.example and remove .example from filename * SubGHz: Various bugfixes and experimental options (rolling counter overflow) (by @xMasterX) * Anims: Disable winter anims * NFC: mfclassic poller fix early key reuse in dictionary attack state machine (by @noproto) +* OFW: FBT: Fix for Python 3.13 +* OFW: sdk: bump API to force re-upload for the catalog +* OFW: SDK: Fix missing RECORD_CLI define * OFW: Fix NULL dereference in CLI completions * OFW PR 4181: vcp, cli: Handle Tx/Rx events before Connect/Disconnect + extra fixes (by @portasynthinca3) * OFW: BLE: Slightly increase mfg_data size From 535afc41f30a3de5d89dc368a8f7b9db590a3fc9 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 13 Apr 2025 00:37:20 +0300 Subject: [PATCH 110/125] fix subghz cli --- applications/main/subghz/subghz_cli.c | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index 5158e17b8..947920964 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -823,7 +823,6 @@ void subghz_cli_command_tx_from_file(PipeSide* pipe, FuriString* args, void* con subghz_devices_deinit(); // Reset custom settings subghz_environment_reset_keeloq(environment); - faac_slh_reset_prog_mode(); subghz_custom_btns_reset(); // Free environment subghz_environment_free(environment); From 8a0fb5df36e3c6fb99b63205ddbaf917459ef695 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Sun, 13 Apr 2025 23:43:43 +0700 Subject: [PATCH 111/125] LCD Inversion refactoring --- applications/services/gui/canvas.c | 34 ++----------------- applications/services/gui/canvas.h | 3 -- .../services/notification/notification_app.c | 20 +++++------ .../notification_settings_app.c | 10 +++--- lib/u8g2/u8g2_buffer.c | 8 +---- lib/u8g2/u8g2_glue.c | 14 ++++++++ lib/u8g2/u8g2_glue.h | 2 ++ targets/f7/api_symbols.csv | 2 -- 8 files changed, 33 insertions(+), 60 deletions(-) diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index 573ad185e..337789dd3 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -94,16 +94,6 @@ size_t canvas_get_buffer_size(const Canvas* canvas) { return u8g2_GetBufferTileWidth(&canvas->fb) * u8g2_GetBufferTileHeight(&canvas->fb) * 8; } -bool canvas_is_inverted_lcd(Canvas* canvas) { - furi_assert(canvas); - return canvas->lcd_inversion; -} - -void canvas_set_inverted_lcd(Canvas* canvas, bool inverted) { - furi_assert(canvas); - canvas->lcd_inversion = inverted; -} - void canvas_frame_set( Canvas* canvas, int32_t offset_x, @@ -151,24 +141,11 @@ const CanvasFontParameters* canvas_get_font_params(const Canvas* canvas, Font fo void canvas_clear(Canvas* canvas) { furi_check(canvas); - - if(canvas->lcd_inversion) { - u8g2_FillBuffer(&canvas->fb); - } else { - u8g2_ClearBuffer(&canvas->fb); - } + u8g2_ClearBuffer(&canvas->fb); } void canvas_set_color(Canvas* canvas, Color color) { furi_check(canvas); - - if(canvas->lcd_inversion) { - if(color == ColorBlack) { - color = ColorWhite; - } else if(color == ColorWhite) { - color = ColorBlack; - } - } u8g2_SetDrawColor(&canvas->fb, color); } @@ -178,14 +155,7 @@ void canvas_set_font_direction(Canvas* canvas, CanvasDirection dir) { } void canvas_invert_color(Canvas* canvas) { - if((canvas->fb.draw_color == ColorXOR) && canvas->lcd_inversion) { - // ColorXOR = 0x02, inversion change it to White = 0x00 - // but if we have lcd_inversion ON then we need Black =0x01 instead White 0x00 - // so we force changing color to black - canvas->fb.draw_color = ColorBlack; - } else { - canvas->fb.draw_color = !canvas->fb.draw_color; - } + canvas->fb.draw_color = !canvas->fb.draw_color; } void canvas_set_font(Canvas* canvas, Font font) { diff --git a/applications/services/gui/canvas.h b/applications/services/gui/canvas.h index 8257c481d..88ae82283 100644 --- a/applications/services/gui/canvas.h +++ b/applications/services/gui/canvas.h @@ -447,9 +447,6 @@ void canvas_draw_icon_bitmap( int16_t h, const Icon* icon); -bool canvas_is_inverted_lcd(Canvas* canvas); - -void canvas_set_inverted_lcd(Canvas* canvas, bool inverted); #ifdef __cplusplus } diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 2df27110e..ef9677f31 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -835,12 +835,8 @@ static NotificationApp* notification_app_alloc(void) { app->settings.rgb.rainbow_saturation = 255; app->settings.rgb.rainbow_wide = 50; - // use RECORD for setup init values to canvas lcd_inverted - Gui* tmp_gui = furi_record_open(RECORD_GUI); - Canvas* tmp_canvas = gui_direct_draw_acquire(tmp_gui); - canvas_set_inverted_lcd(tmp_canvas, false); - gui_direct_draw_release(tmp_gui); - furi_record_close(RECORD_GUI); + // set inital value, later it will be rewriten by loading settings from file + app->settings.lcd_inversion = false; return app; } @@ -873,12 +869,12 @@ static void notification_apply_settings(NotificationApp* app) { } // --- NIGHT SHIFT END --- - //setup canvas variable "inversion" by settings value; - Gui* tmp_gui = furi_record_open(RECORD_GUI); - Canvas* tmp_canvas = gui_direct_draw_acquire(tmp_gui); - canvas_set_inverted_lcd(tmp_canvas, app->settings.lcd_inversion); - gui_direct_draw_release(tmp_gui); - furi_record_close(RECORD_GUI); + // check RECORD_GUI is exist (insurance on boot time) then use it to setup lcd inversion mode from loaded settings; + if(furi_record_exists(RECORD_GUI)) { + Gui* gui = furi_record_open(RECORD_GUI); + u8x8_d_st756x_set_inversion(&gui->canvas->fb.u8x8, app->settings.lcd_inversion); + furi_record_close(RECORD_GUI); + } } static void notification_init_settings(NotificationApp* app) { diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 8794c53f6..4139967c4 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include #define MAX_NOTIFICATION_SETTINGS 5 @@ -348,11 +350,11 @@ static void lcd_inversion_changed(VariableItem* item) { variable_item_set_current_value_text(item, lcd_inversion_text[index]); app->notification->settings.lcd_inversion = lcd_inversion_value[index]; - Canvas* tmp_canvas = gui_direct_draw_acquire(app->gui); - canvas_set_inverted_lcd(tmp_canvas, lcd_inversion_value[index]); - gui_direct_draw_release(app->gui); + Gui* gui = furi_record_open(RECORD_GUI); + u8x8_d_st756x_set_inversion(&gui->canvas->fb.u8x8, lcd_inversion_value[index]); + furi_record_close(RECORD_GUI); - notification_message(app->notification, &sequence_display_backlight_on); + notification_message_save_settings(app->notification); } //--- RGB BACKLIGHT --- diff --git a/lib/u8g2/u8g2_buffer.c b/lib/u8g2/u8g2_buffer.c index 57f4f84be..cd4e67972 100644 --- a/lib/u8g2/u8g2_buffer.c +++ b/lib/u8g2/u8g2_buffer.c @@ -37,6 +37,7 @@ #include /*============================================*/ + void u8g2_ClearBuffer(u8g2_t* u8g2) { size_t cnt; cnt = u8g2_GetU8x8(u8g2)->display_info->tile_width; @@ -45,13 +46,6 @@ void u8g2_ClearBuffer(u8g2_t* u8g2) { memset(u8g2->tile_buf_ptr, 0, cnt); } -void u8g2_FillBuffer(u8g2_t* u8g2) { - size_t cnt; - cnt = u8g2_GetU8x8(u8g2)->display_info->tile_width; - cnt *= u8g2->tile_buf_height; - cnt *= 8; - memset(u8g2->tile_buf_ptr, 255, cnt); -} /*============================================*/ static void u8g2_send_tile_row(u8g2_t* u8g2, uint8_t src_tile_row, uint8_t dest_tile_row) { diff --git a/lib/u8g2/u8g2_glue.c b/lib/u8g2/u8g2_glue.c index b3e74c229..57d73b22e 100644 --- a/lib/u8g2/u8g2_glue.c +++ b/lib/u8g2/u8g2_glue.c @@ -280,3 +280,17 @@ void u8g2_Setup_st756x_flipper( buf = u8g2_m_16_8_f(&tile_buf_height); u8g2_SetupBuffer(u8g2, buf, tile_buf_height, u8g2_ll_hvline_vertical_top_lsb, rotation); } + +void u8x8_d_st756x_set_inversion(u8x8_t* u8x8, bool arg) { + // if arg is true - set last bit to 1 (inversion ON) + if(arg) { + u8x8_cad_StartTransfer(u8x8); + u8x8_cad_SendCmd(u8x8, ST756X_CMD_INVERSE_DISPLAY | 0b01); + u8x8_cad_EndTransfer(u8x8); + // else use standart command with 0 in last bit + } else { + u8x8_cad_StartTransfer(u8x8); + u8x8_cad_SendCmd(u8x8, ST756X_CMD_INVERSE_DISPLAY); + u8x8_cad_EndTransfer(u8x8); + } +} diff --git a/lib/u8g2/u8g2_glue.h b/lib/u8g2/u8g2_glue.h index af236279e..16e7df75e 100644 --- a/lib/u8g2/u8g2_glue.h +++ b/lib/u8g2/u8g2_glue.h @@ -16,3 +16,5 @@ void u8g2_Setup_st756x_flipper( void u8x8_d_st756x_init(u8x8_t* u8x8, uint8_t contrast, uint8_t regulation_ratio, bool bias); void u8x8_d_st756x_set_contrast(u8x8_t* u8x8, int8_t contrast_offset); + +void u8x8_d_st756x_set_inversion(u8x8_t* u8x8, bool arg); \ No newline at end of file diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index af74003de..7c4dca564 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -848,14 +848,12 @@ Function,+,canvas_get_font_params,const CanvasFontParameters*,"const Canvas*, Fo Function,+,canvas_glyph_width,size_t,"Canvas*, uint16_t" Function,+,canvas_height,size_t,const Canvas* Function,+,canvas_invert_color,void,Canvas* -Function,+,canvas_is_inverted_lcd,_Bool,Canvas* Function,+,canvas_reset,void,Canvas* Function,+,canvas_set_bitmap_mode,void,"Canvas*, _Bool" Function,+,canvas_set_color,void,"Canvas*, Color" Function,+,canvas_set_custom_u8g2_font,void,"Canvas*, const uint8_t*" Function,+,canvas_set_font,void,"Canvas*, Font" Function,+,canvas_set_font_direction,void,"Canvas*, CanvasDirection" -Function,+,canvas_set_inverted_lcd,void,"Canvas*, _Bool" Function,+,canvas_string_width,uint16_t,"Canvas*, const char*" Function,+,canvas_width,size_t,const Canvas* Function,-,cbrt,double,double From 8a5129449d7b6a19f7cdba6635d5271782b05bda Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 14 Apr 2025 00:24:17 +0300 Subject: [PATCH 112/125] fix --- applications/services/gui/canvas.h | 1 - applications/services/gui/canvas_i.h | 1 - lib/u8g2/u8g2_glue.h | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/applications/services/gui/canvas.h b/applications/services/gui/canvas.h index 88ae82283..efd314687 100644 --- a/applications/services/gui/canvas.h +++ b/applications/services/gui/canvas.h @@ -447,7 +447,6 @@ void canvas_draw_icon_bitmap( int16_t h, const Icon* icon); - #ifdef __cplusplus } #endif diff --git a/applications/services/gui/canvas_i.h b/applications/services/gui/canvas_i.h index 420b97e0f..449db71db 100644 --- a/applications/services/gui/canvas_i.h +++ b/applications/services/gui/canvas_i.h @@ -47,7 +47,6 @@ struct Canvas { CompressIcon* compress_icon; CanvasCallbackPairArray_t canvas_callback_pair; FuriMutex* mutex; - bool lcd_inversion; }; /** Allocate memory and initialize canvas diff --git a/lib/u8g2/u8g2_glue.h b/lib/u8g2/u8g2_glue.h index 16e7df75e..858e8ec7f 100644 --- a/lib/u8g2/u8g2_glue.h +++ b/lib/u8g2/u8g2_glue.h @@ -17,4 +17,4 @@ void u8x8_d_st756x_init(u8x8_t* u8x8, uint8_t contrast, uint8_t regulation_ratio void u8x8_d_st756x_set_contrast(u8x8_t* u8x8, int8_t contrast_offset); -void u8x8_d_st756x_set_inversion(u8x8_t* u8x8, bool arg); \ No newline at end of file +void u8x8_d_st756x_set_inversion(u8x8_t* u8x8, bool arg); From e8e87c66e3dfebd3ac9f9415113f613dee8b8484 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 14 Apr 2025 00:29:39 +0300 Subject: [PATCH 113/125] upd changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b679620f..5a6477637 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ * SubGHz: **Came Atomo button hold simulation with full cycle** simulation (to allow proper pairing with receiver) * SubGHz: Add **Prastel (42bit static code)** support (OFW PR 4178 by @pmazzini) * Desktop: **Add support for Favorite App - Ok Long** (Warning! Old favourites apps list will be reset!) (PR #886 | by @DrEverr) -* Display: **LCD Color Inversion** (Settings - LCD and Notifications - LCD inversion.) (PR #887 | by @Dmitry422) +* Display: **LCD Color Inversion** (Settings - LCD and Notifications - LCD inversion.) (PR #887 #893 | by @Dmitry422) * Display: **Night Shift Feature** (dimming backlight in selected time interval) (PR #885 | by @Dmitry422) * Display: **Сombining RGB Backlight mod** (by @quen0n) and original backlight support **in one firmware** (+ Rainbow/Wave effect (based on @Willy-JL idea)) (PR #877 #881 #890 | by @Dmitry422) - (**To enable RGB Backlight support go into Notifications settings with Debug mode - ON**) * NFC: Use default UL/UL-C pwd/key as default value for key input (PR #891 | by @mishamyte) From 63cfa2d6845575b25217295b9e7838f94b48e5c4 Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Tue, 15 Apr 2025 03:45:16 +0400 Subject: [PATCH 114/125] cli_vcp: make enable/disable requests synchronous --- applications/services/cli/cli_vcp.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/applications/services/cli/cli_vcp.c b/applications/services/cli/cli_vcp.c index def1949e2..cea4de248 100644 --- a/applications/services/cli/cli_vcp.c +++ b/applications/services/cli/cli_vcp.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "cli_main_shell.h" #include "cli_main_commands.h" @@ -26,6 +27,7 @@ typedef struct { CliVcpMessageTypeEnable, CliVcpMessageTypeDisable, } type; + FuriApiLock api_lock; union {}; } CliVcpMessage; @@ -182,6 +184,8 @@ static void cli_vcp_message_received(FuriEventLoopObject* object, void* context) furi_hal_usb_set_config(cli_vcp->previous_interface, NULL); break; } + + api_lock_unlock(message.api_lock); } /** @@ -300,16 +304,24 @@ int32_t cli_vcp_srv(void* p) { // Public API // ========== +static void cli_vcp_synchronous_request(CliVcp* cli_vcp, CliVcpMessage* message) { + message->api_lock = api_lock_alloc_locked(); + furi_message_queue_put(cli_vcp->message_queue, message, FuriWaitForever); + api_lock_wait_unlock_and_free(message->api_lock); +} + void cli_vcp_enable(CliVcp* cli_vcp) { + furi_check(cli_vcp); CliVcpMessage message = { .type = CliVcpMessageTypeEnable, }; - furi_message_queue_put(cli_vcp->message_queue, &message, FuriWaitForever); + cli_vcp_synchronous_request(cli_vcp, &message); } void cli_vcp_disable(CliVcp* cli_vcp) { + furi_check(cli_vcp); CliVcpMessage message = { .type = CliVcpMessageTypeDisable, }; - furi_message_queue_put(cli_vcp->message_queue, &message, FuriWaitForever); + cli_vcp_synchronous_request(cli_vcp, &message); } From 086a9185fc0d438c020ca027997a22ab52f88abb Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Tue, 15 Apr 2025 03:45:37 +0400 Subject: [PATCH 115/125] usb_uart_bridge: open and close vcp record once --- applications/main/gpio/usb_uart_bridge.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/applications/main/gpio/usb_uart_bridge.c b/applications/main/gpio/usb_uart_bridge.c index 77cd02f63..3e1cefb93 100644 --- a/applications/main/gpio/usb_uart_bridge.c +++ b/applications/main/gpio/usb_uart_bridge.c @@ -60,6 +60,8 @@ struct UsbUartBridge { FuriApiLock cfg_lock; + CliVcp* cli_vcp; + uint8_t rx_buf[USB_CDC_PKT_LEN]; }; @@ -105,15 +107,11 @@ static void usb_uart_on_irq_rx_dma_cb( static void usb_uart_vcp_init(UsbUartBridge* usb_uart, uint8_t vcp_ch) { furi_hal_usb_unlock(); if(vcp_ch == 0) { - CliVcp* cli_vcp = furi_record_open(RECORD_CLI_VCP); - cli_vcp_disable(cli_vcp); - furi_record_close(RECORD_CLI_VCP); + cli_vcp_disable(usb_uart->cli_vcp); furi_check(furi_hal_usb_set_config(&usb_cdc_single, NULL) == true); } else { furi_check(furi_hal_usb_set_config(&usb_cdc_dual, NULL) == true); - CliVcp* cli_vcp = furi_record_open(RECORD_CLI_VCP); - cli_vcp_enable(cli_vcp); - furi_record_close(RECORD_CLI_VCP); + cli_vcp_enable(usb_uart->cli_vcp); } furi_hal_cdc_set_callbacks(vcp_ch, (CdcCallbacks*)&cdc_cb, usb_uart); } @@ -122,9 +120,7 @@ static void usb_uart_vcp_deinit(UsbUartBridge* usb_uart, uint8_t vcp_ch) { UNUSED(usb_uart); furi_hal_cdc_set_callbacks(vcp_ch, NULL, NULL); if(vcp_ch != 0) { - CliVcp* cli_vcp = furi_record_open(RECORD_CLI_VCP); - cli_vcp_disable(cli_vcp); - furi_record_close(RECORD_CLI_VCP); + cli_vcp_disable(usb_uart->cli_vcp); } } @@ -176,6 +172,8 @@ static int32_t usb_uart_worker(void* context) { memcpy(&usb_uart->cfg, &usb_uart->cfg_new, sizeof(UsbUartConfig)); + usb_uart->cli_vcp = furi_record_open(RECORD_CLI_VCP); + usb_uart->rx_stream = furi_stream_buffer_alloc(USB_UART_RX_BUF_SIZE, 1); usb_uart->tx_sem = furi_semaphore_alloc(1, 1); @@ -308,8 +306,8 @@ static int32_t usb_uart_worker(void* context) { furi_hal_usb_unlock(); furi_check(furi_hal_usb_set_config(&usb_cdc_single, NULL) == true); - CliVcp* cli_vcp = furi_record_open(RECORD_CLI_VCP); - cli_vcp_enable(cli_vcp); + cli_vcp_enable(usb_uart->cli_vcp); + furi_record_close(RECORD_CLI_VCP); return 0; From 008c5a8828993140aa48ff445973ae0692428bf0 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 15 Apr 2025 04:38:01 +0300 Subject: [PATCH 116/125] upd changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a6477637..2f96c8929 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ * SubGHz: Various bugfixes and experimental options (rolling counter overflow) (by @xMasterX) * Anims: Disable winter anims * NFC: mfclassic poller fix early key reuse in dictionary attack state machine (by @noproto) +* OFW PR 4189: USB-UART bridge fix (by @portasynthinca3) * OFW: FBT: Fix for Python 3.13 * OFW: sdk: bump API to force re-upload for the catalog * OFW: SDK: Fix missing RECORD_CLI define From 1d4db1ee2c3357c20dae0619d5e16bbcfd00dc90 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 18 Apr 2025 00:59:24 +0300 Subject: [PATCH 117/125] unhide rgb from debug --- .../notification_settings_app.c | 67 ++++++++----------- 1 file changed, 28 insertions(+), 39 deletions(-) diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 4139967c4..5ab15514b 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -393,10 +393,8 @@ static void rgb_backlight_installed_changed(VariableItem* item) { } // Lock/Unlock all rgb settings depent from rgb_backlight_installed switch - int slide = 0; - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { - slide = 1; - } + int slide = 1; + for(int i = slide; i < (slide + 8); i++) { VariableItem* t_item = variable_item_list_get(app->variable_item_list_rgb, i); if(index == 0) { @@ -535,9 +533,7 @@ void variable_item_list_enter_callback(void* context, uint32_t index) { UNUSED(context); NotificationAppSettings* app = context; - if(((app->notification->settings.rgb.rgb_backlight_installed) || - (furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug))) && - (index == 0)) { + if(index == 0) { view_dispatcher_switch_to_view(app->view_dispatcher, RGBViewId); } } @@ -563,17 +559,14 @@ static void night_shift_changed(VariableItem* item) { // force demo night_shift brightness ot rgb backlight and stock backlight notification_message(app->notification, &sequence_display_backlight_on); - int slide = 0; - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) || - (app->notification->settings.rgb.rgb_backlight_installed)) { - slide = 1; - } + int slide = 1; + for(int i = 4 + slide; i < (6 + slide); i++) { VariableItem* t_item = variable_item_list_get(app->variable_item_list, i); if(index == 0) { - variable_item_set_locked(t_item, true, "Night shift\nOFF!"); + variable_item_set_locked(t_item, true, "Night Shift\nOFF!"); } else { - variable_item_set_locked(t_item, false, "Night shift\nOFF!"); + variable_item_set_locked(t_item, false, "Night Shift\nOFF!"); } } @@ -633,10 +626,7 @@ static NotificationAppSettings* alloc_settings(void) { app->variable_item_list, variable_item_list_enter_callback, app); // Show RGB settings only when debug_mode or rgb_backlight_installed is active - if((app->notification->settings.rgb.rgb_backlight_installed) || - (furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug))) { - item = variable_item_list_add(app->variable_item_list, "RGB settings", 0, NULL, app); - } + item = variable_item_list_add(app->variable_item_list, "RGB Mod Settings", 0, NULL, app); //--- RGB BACKLIGHT END --- item = variable_item_list_add( @@ -662,7 +652,7 @@ static NotificationAppSettings* alloc_settings(void) { // --- NIGHT SHIFT --- item = variable_item_list_add( - app->variable_item_list, "Night shift", NIGHT_SHIFT_COUNT, night_shift_changed, app); + app->variable_item_list, "Night Shift", NIGHT_SHIFT_COUNT, night_shift_changed, app); value_index = value_index_float( app->notification->settings.night_shift, night_shift_value, NIGHT_SHIFT_COUNT); variable_item_set_current_value_index(item, value_index); @@ -681,7 +671,7 @@ static NotificationAppSettings* alloc_settings(void) { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, night_shift_start_text[value_index]); variable_item_set_locked( - item, (app->notification->settings.night_shift == 1), "Night shift \nOFF!"); + item, (app->notification->settings.night_shift == 1), "Night Shift \nOFF!"); item = variable_item_list_add( app->variable_item_list, " . End", NIGHT_SHIFT_END_COUNT, night_shift_end_changed, app); @@ -690,7 +680,7 @@ static NotificationAppSettings* alloc_settings(void) { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, night_shift_end_text[value_index]); variable_item_set_locked( - item, (app->notification->settings.night_shift == 1), "Night shift \nOFF!"); + item, (app->notification->settings.night_shift == 1), "Night Shift \nOFF!"); // --- NIGHT SHIFT END--- @@ -730,7 +720,7 @@ static NotificationAppSettings* alloc_settings(void) { } item = variable_item_list_add( - app->variable_item_list, "LCD inversion", LCD_INVERSION_COUNT, lcd_inversion_changed, app); + app->variable_item_list, "LCD Inversion", LCD_INVERSION_COUNT, lcd_inversion_changed, app); value_index = value_index_bool( app->notification->settings.lcd_inversion, lcd_inversion_value, LCD_INVERSION_COUNT); variable_item_set_current_value_index(item, value_index); @@ -745,26 +735,25 @@ static NotificationAppSettings* alloc_settings(void) { view_set_previous_callback(view_rgb, notification_app_rgb_settings_exit); // Show rgb_backlight_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 backlight installed", - RGB_BACKLIGHT_INSTALLED_COUNT, - rgb_backlight_installed_changed, - app); - value_index = value_index_bool( - app->notification->settings.rgb.rgb_backlight_installed, - rgb_backlight_installed_value, - RGB_BACKLIGHT_INSTALLED_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, rgb_backlight_installed_text[value_index]); - } + + item = variable_item_list_add( + app->variable_item_list_rgb, + "RGB backlight installed", + RGB_BACKLIGHT_INSTALLED_COUNT, + rgb_backlight_installed_changed, + app); + value_index = value_index_bool( + app->notification->settings.rgb.rgb_backlight_installed, + rgb_backlight_installed_value, + RGB_BACKLIGHT_INSTALLED_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, rgb_backlight_installed_text[value_index]); // We (humans) are numbering LEDs from left to right as 1..3, but hardware have another order from right to left 2..0 // led_1 color item = variable_item_list_add( app->variable_item_list_rgb, - "Led 1 Color", + "LED 1 Color", rgb_backlight_get_color_count(), led_2_color_changed, app); @@ -777,7 +766,7 @@ static NotificationAppSettings* alloc_settings(void) { // led_2 color item = variable_item_list_add( app->variable_item_list_rgb, - "Led 2 Color", + "LED 2 Color", rgb_backlight_get_color_count(), led_1_color_changed, app); @@ -790,7 +779,7 @@ static NotificationAppSettings* alloc_settings(void) { // led 3 color item = variable_item_list_add( app->variable_item_list_rgb, - "Led 3 Color", + "LED 3 Color", rgb_backlight_get_color_count(), led_0_color_changed, app); From 3fd059a45fbcd8a6f0c3adcdc7c2af7ddb544119 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 18 Apr 2025 01:06:10 +0300 Subject: [PATCH 118/125] upd changelog and docs --- CHANGELOG.md | 6 +++--- documentation/FAQ.md | 4 +--- documentation/HowToBuild.md | 14 ++------------ 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f96c8929..e693c777a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,9 @@ * SubGHz: **Came Atomo button hold simulation with full cycle** simulation (to allow proper pairing with receiver) * SubGHz: Add **Prastel (42bit static code)** support (OFW PR 4178 by @pmazzini) * Desktop: **Add support for Favorite App - Ok Long** (Warning! Old favourites apps list will be reset!) (PR #886 | by @DrEverr) -* Display: **LCD Color Inversion** (Settings - LCD and Notifications - LCD inversion.) (PR #887 #893 | by @Dmitry422) +* Display: **LCD Color Inversion** (Settings - LCD and Notifications - LCD Inversion) (PR #887 #893 | by @Dmitry422) * Display: **Night Shift Feature** (dimming backlight in selected time interval) (PR #885 | by @Dmitry422) -* Display: **Сombining RGB Backlight mod** (by @quen0n) and original backlight support **in one firmware** (+ Rainbow/Wave effect (based on @Willy-JL idea)) (PR #877 #881 #890 | by @Dmitry422) - (**To enable RGB Backlight support go into Notifications settings with Debug mode - ON**) +* Display: **Сombining RGB Backlight mod** (by @quen0n) and original backlight support **in one firmware** (+ Rainbow/Wave effect (based on @Willy-JL idea)) (PR #877 #881 #890 | by @Dmitry422) - (**To enable RGB Backlight support go into Notifications settings**) * NFC: Use default UL/UL-C pwd/key as default value for key input (PR #891 | by @mishamyte) * OFW: LFRFID - **EM4305 support** * OFW: **Universal IR signal selection** @@ -134,7 +134,7 @@ What build I should download and what this name means - `flipper-z-f7-update-(ve | `c` | | | | `e` | ✅ | ✅ | -**To enable RGB Backlight support go into Notifications settings with Debug mode = ON** +**To enable RGB Backlight support go into LCD & Notifications settings** ⚠️RGB backlight [hardware mod](https://github.com/quen0n/flipperzero-firmware-rgb#readme), works only on modded flippers! do not enable on non modded device! diff --git a/documentation/FAQ.md b/documentation/FAQ.md index cae0ba61c..7dea58c5d 100644 --- a/documentation/FAQ.md +++ b/documentation/FAQ.md @@ -18,9 +18,7 @@ Follow this link for [details](https://github.com/DarkFlippers/unleashed-firmwar You’ve enabled RGB backlight mod in settings made for custom RGB modded flippers.
Please, do not use that version if your flipper isn’t modded! -Disable in Settings -> Notifications -> RGB mod settings - -Make sure to have System -> Debug = ON before, otherwise first option (is mod installed) will not appear +Disable in Settings -> LCD & Notifications -> RGB mod settings If you have RGB backlight mod do the same but enable the mod instead diff --git a/documentation/HowToBuild.md b/documentation/HowToBuild.md index eec2e632a..b10c7493b 100644 --- a/documentation/HowToBuild.md +++ b/documentation/HowToBuild.md @@ -29,13 +29,8 @@ Check out `documentation/fbt.md` for details on building and flashing firmware. ./fbt COMPACT=1 DEBUG=0 launch_app APPSRC=applications_user/yourplugin ``` -### Compile everything for development -```sh -./fbt updater_package -``` - -### Compile everything for release + get updater package to update from microSD card +### Compile everything + get updater package to update from microSD card ```sh ./fbt COMPACT=1 DEBUG=0 updater_package @@ -49,13 +44,8 @@ Use `flipper-z-{target}-update-{suffix}.tgz` to flash your device. Check out `documentation/fbt.md` for details on building and flashing firmware. -### Compile everything for development -```powershell -./fbt.cmd updater_package -``` - -### Compile everything for release + get updater package to update from microSD card +### Compile everything + get updater package to update from microSD card ```powershell ./fbt.cmd COMPACT=1 DEBUG=0 updater_package From a92400b9b628206052c5ef39e66f8f4a637a87db Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 18 Apr 2025 20:45:48 +0300 Subject: [PATCH 119/125] upd changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e693c777a..128d64ca0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,8 @@ * SubGHz: Various bugfixes and experimental options (rolling counter overflow) (by @xMasterX) * Anims: Disable winter anims * NFC: mfclassic poller fix early key reuse in dictionary attack state machine (by @noproto) +* OFW: RC fixes +* OFW: Desktop: Fix freeze on boot if PIN set * OFW PR 4189: USB-UART bridge fix (by @portasynthinca3) * OFW: FBT: Fix for Python 3.13 * OFW: sdk: bump API to force re-upload for the catalog From 19351655910a0e9695e16bcfcb7643e30cecb355 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 19 Apr 2025 17:31:16 +0300 Subject: [PATCH 120/125] move to the last position --- .../notification_settings/notification_settings_app.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 5ab15514b..cb1d1048d 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -533,7 +533,7 @@ void variable_item_list_enter_callback(void* context, uint32_t index) { UNUSED(context); NotificationAppSettings* app = context; - if(index == 0) { + if(index == 10) { view_dispatcher_switch_to_view(app->view_dispatcher, RGBViewId); } } @@ -625,10 +625,6 @@ static NotificationAppSettings* alloc_settings(void) { 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_backlight_installed is active - 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 = @@ -727,6 +723,9 @@ static NotificationAppSettings* alloc_settings(void) { variable_item_set_current_value_text(item, lcd_inversion_text[value_index]); //--- RGB BACKLIGHT --- + // Show RGB settings only when debug_mode or rgb_backlight_installed is active + item = variable_item_list_add(app->variable_item_list, "RGB Mod Settings", 0, NULL, app); + //--- RGB BACKLIGHT END --- app->variable_item_list_rgb = variable_item_list_alloc(); View* view_rgb = variable_item_list_get_view(app->variable_item_list_rgb); From c5d8bdf500ea4feb0cce0023892f5f0c43441780 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 21 Apr 2025 19:23:51 +0300 Subject: [PATCH 121/125] add feron protocol [ci skip] --- lib/subghz/protocols/feron.c | 350 ++++++++++++++++++++++++++ lib/subghz/protocols/feron.h | 109 ++++++++ lib/subghz/protocols/protocol_items.c | 1 + lib/subghz/protocols/protocol_items.h | 1 + 4 files changed, 461 insertions(+) create mode 100644 lib/subghz/protocols/feron.c create mode 100644 lib/subghz/protocols/feron.h diff --git a/lib/subghz/protocols/feron.c b/lib/subghz/protocols/feron.c new file mode 100644 index 000000000..1096f07a7 --- /dev/null +++ b/lib/subghz/protocols/feron.c @@ -0,0 +1,350 @@ +#include "feron.h" +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolFeron" + +static const SubGhzBlockConst subghz_protocol_feron_const = { + .te_short = 350, + .te_long = 750, + .te_delta = 150, + .min_count_bit_for_found = 32, +}; + +struct SubGhzProtocolDecoderFeron { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderFeron { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + FeronDecoderStepReset = 0, + FeronDecoderStepSaveDuration, + FeronDecoderStepCheckDuration, +} FeronDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_feron_decoder = { + .alloc = subghz_protocol_decoder_feron_alloc, + .free = subghz_protocol_decoder_feron_free, + + .feed = subghz_protocol_decoder_feron_feed, + .reset = subghz_protocol_decoder_feron_reset, + + .get_hash_data = subghz_protocol_decoder_feron_get_hash_data, + .serialize = subghz_protocol_decoder_feron_serialize, + .deserialize = subghz_protocol_decoder_feron_deserialize, + .get_string = subghz_protocol_decoder_feron_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_feron_encoder = { + .alloc = subghz_protocol_encoder_feron_alloc, + .free = subghz_protocol_encoder_feron_free, + + .deserialize = subghz_protocol_encoder_feron_deserialize, + .stop = subghz_protocol_encoder_feron_stop, + .yield = subghz_protocol_encoder_feron_yield, +}; + +const SubGhzProtocol subghz_protocol_feron = { + .name = SUBGHZ_PROTOCOL_FERON_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_feron_decoder, + .encoder = &subghz_protocol_feron_encoder, +}; + +void* subghz_protocol_encoder_feron_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderFeron* instance = malloc(sizeof(SubGhzProtocolEncoderFeron)); + + instance->base.protocol = &subghz_protocol_feron; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 256; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + return instance; +} + +void subghz_protocol_encoder_feron_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderFeron* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderFeron instance + */ +static void subghz_protocol_encoder_feron_get_upload(SubGhzProtocolEncoderFeron* instance) { + furi_assert(instance); + size_t index = 0; + + // Send key and GAP + for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { + if(bit_read(instance->generic.data, i - 1)) { + // Send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_feron_const.te_long); + if(i == 1) { + //Send 500/500 and gap if bit was last + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_feron_const.te_short + 150); + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_feron_const.te_short + 150); + // Gap + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_feron_const.te_long * 6); + } else { + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_feron_const.te_short); + } + } else { + // Send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_feron_const.te_short); + if(i == 1) { + //Send 500/500 and gap if bit was last + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_feron_const.te_short + 150); + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_feron_const.te_short + 150); + // Gap + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_feron_const.te_long * 6); + } else { + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_feron_const.te_long); + } + } + } + + instance->encoder.size_upload = index; + return; +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_feron_check_remote_controller(SubGhzBlockGeneric* instance) { + instance->serial = instance->data >> 16; +} + +SubGhzProtocolStatus + subghz_protocol_encoder_feron_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderFeron* instance = context; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; + do { + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_feron_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_feron_check_remote_controller(&instance->generic); + subghz_protocol_encoder_feron_get_upload(instance); + instance->encoder.is_running = true; + } while(false); + + return ret; +} + +void subghz_protocol_encoder_feron_stop(void* context) { + SubGhzProtocolEncoderFeron* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_feron_yield(void* context) { + SubGhzProtocolEncoderFeron* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_feron_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderFeron* instance = malloc(sizeof(SubGhzProtocolDecoderFeron)); + instance->base.protocol = &subghz_protocol_feron; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_feron_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderFeron* instance = context; + free(instance); +} + +void subghz_protocol_decoder_feron_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderFeron* instance = context; + instance->decoder.parser_step = FeronDecoderStepReset; +} + +void subghz_protocol_decoder_feron_feed(void* context, bool level, volatile uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderFeron* instance = context; + + // Feron Decoder + // 2025.04 - @xMasterX (MMX) + + // Key samples + /* + 0110001100111000 1000010101111010 - ON + 0110001100111000 1000010001111011 - OFF + + 0110001100111000 1000011001111001 - brightness up + 0110001100111000 1000011101111000 - brightness down + + 0110001100111000 1000001001111101 - scroll mode command + + ------------------------------------------ + 0110001100111000 0111000010001111 - R + 0110001100111000 0001101011100101 - B + 0110001100111000 0100000010111111 - G + */ + + switch(instance->decoder.parser_step) { + case FeronDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_feron_const.te_long * 6) < + subghz_protocol_feron_const.te_delta * 4)) { + //Found GAP + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + instance->decoder.parser_step = FeronDecoderStepSaveDuration; + } + break; + case FeronDecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = FeronDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = FeronDecoderStepReset; + } + break; + case FeronDecoderStepCheckDuration: + if(!level) { + // Bit 0 is short and long timing = 350us HIGH (te_last) and 750us LOW + if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_feron_const.te_short) < + subghz_protocol_feron_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_feron_const.te_long) < + subghz_protocol_feron_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = FeronDecoderStepSaveDuration; + // Bit 1 is long and short timing = 750us HIGH (te_last) and 350us LOW + } else if( + (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_feron_const.te_long) < + subghz_protocol_feron_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_feron_const.te_short) < + subghz_protocol_feron_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = FeronDecoderStepSaveDuration; + } else if( + // End of the key 500Low(we are here)/500High us + DURATION_DIFF( + duration, (uint16_t)(subghz_protocol_feron_const.te_short + (uint16_t)150)) < + subghz_protocol_feron_const.te_delta) { + if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_feron_const.te_short) < + subghz_protocol_feron_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + } + if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_feron_const.te_long) < + subghz_protocol_feron_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + } + // If got 32 bits key reading is finished + if(instance->decoder.decode_count_bit == + subghz_protocol_feron_const.min_count_bit_for_found) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + instance->decoder.parser_step = FeronDecoderStepReset; + } else { + instance->decoder.parser_step = FeronDecoderStepReset; + } + } else { + instance->decoder.parser_step = FeronDecoderStepReset; + } + break; + } +} + +uint8_t subghz_protocol_decoder_feron_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderFeron* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +SubGhzProtocolStatus subghz_protocol_decoder_feron_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolDecoderFeron* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +SubGhzProtocolStatus + subghz_protocol_decoder_feron_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderFeron* instance = context; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, subghz_protocol_feron_const.min_count_bit_for_found); +} + +void subghz_protocol_decoder_feron_get_string(void* context, FuriString* output) { + furi_assert(context); + SubGhzProtocolDecoderFeron* instance = context; + + subghz_protocol_feron_check_remote_controller(&instance->generic); + + furi_string_cat_printf( + output, + "%s %db\r\n" + "Key: 0x%08lX\r\n" + "Serial: 0x%04lX\r\n" + "Command: 0x%04lX\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data & 0xFFFFFFFF), + instance->generic.serial, + (uint32_t)(instance->generic.data & 0xFFFF)); +} diff --git a/lib/subghz/protocols/feron.h b/lib/subghz/protocols/feron.h new file mode 100644 index 000000000..97f0eb6fe --- /dev/null +++ b/lib/subghz/protocols/feron.h @@ -0,0 +1,109 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_FERON_NAME "Feron" + +typedef struct SubGhzProtocolDecoderFeron SubGhzProtocolDecoderFeron; +typedef struct SubGhzProtocolEncoderFeron SubGhzProtocolEncoderFeron; + +extern const SubGhzProtocolDecoder subghz_protocol_feron_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_feron_encoder; +extern const SubGhzProtocol subghz_protocol_feron; + +/** + * Allocate SubGhzProtocolEncoderFeron. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderFeron* pointer to a SubGhzProtocolEncoderFeron instance + */ +void* subghz_protocol_encoder_feron_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderFeron. + * @param context Pointer to a SubGhzProtocolEncoderFeron instance + */ +void subghz_protocol_encoder_feron_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderFeron instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ +SubGhzProtocolStatus + subghz_protocol_encoder_feron_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderFeron instance + */ +void subghz_protocol_encoder_feron_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderFeron instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_feron_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderFeron. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderFeron* pointer to a SubGhzProtocolDecoderFeron instance + */ +void* subghz_protocol_decoder_feron_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderFeron. + * @param context Pointer to a SubGhzProtocolDecoderFeron instance + */ +void subghz_protocol_decoder_feron_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderFeron. + * @param context Pointer to a SubGhzProtocolDecoderFeron instance + */ +void subghz_protocol_decoder_feron_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderFeron instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_feron_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderFeron instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_feron_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderFeron. + * @param context Pointer to a SubGhzProtocolDecoderFeron instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return status + */ +SubGhzProtocolStatus subghz_protocol_decoder_feron_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data SubGhzProtocolDecoderFeron. + * @param context Pointer to a SubGhzProtocolDecoderFeron instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ +SubGhzProtocolStatus + subghz_protocol_decoder_feron_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderFeron instance + * @param output Resulting text + */ +void subghz_protocol_decoder_feron_get_string(void* context, FuriString* output); diff --git a/lib/subghz/protocols/protocol_items.c b/lib/subghz/protocols/protocol_items.c index ea3e88bf0..c73923c7a 100644 --- a/lib/subghz/protocols/protocol_items.c +++ b/lib/subghz/protocols/protocol_items.c @@ -52,6 +52,7 @@ const SubGhzProtocol* const subghz_protocol_registry_items[] = { &subghz_protocol_hollarm, &subghz_protocol_hay21, &subghz_protocol_revers_rb2, + &subghz_protocol_feron, }; const SubGhzProtocolRegistry subghz_protocol_registry = { diff --git a/lib/subghz/protocols/protocol_items.h b/lib/subghz/protocols/protocol_items.h index d06882466..6165d748a 100644 --- a/lib/subghz/protocols/protocol_items.h +++ b/lib/subghz/protocols/protocol_items.h @@ -53,3 +53,4 @@ #include "hollarm.h" #include "hay21.h" #include "revers_rb2.h" +#include "feron.h" From e4e8f18a9427ae29b001518301980be3d9bbaa84 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 21 Apr 2025 20:03:02 +0300 Subject: [PATCH 122/125] upd changelog --- CHANGELOG.md | 1 + ReadMe.md | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 128d64ca0..31c20e193 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Main changes - Current API: 86.0 **WARNING! After install of this version your Desktop (fav apps) and LCD & Notifications settings will be reset to default values, please configure them again after this update!** (this is required due to big updates on that parts and config struct changes) +* SubGHz: Add **Feron** protocol (static 32 bit) **full support** (by @xMasterX) * SubGHz: Add **Revers RB2 / RB2M Protocol** (static 64 bit) **full support** with add manually (by @xMasterX) * SubGHz: **Fix Hollarm protocol with more verification** * SubGHz: **Fix GangQi protocol** (by @DoberBit and @mishamyte (who spent 2 weeks on this)) diff --git a/ReadMe.md b/ReadMe.md index c40fb71c4..6ee86e881 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -165,6 +165,7 @@ Thanks to Official team (to their SubGHz Developer, Skorp) for implementing supp

Decoders/Encoders or emulation (+ programming mode) support made by @xMasterX
+- Feron (static 32 bit) - ReversRB2 / RB2M (static 64 bit) with add manually support - Marantec24 (static 24 bit) with add manually support - GangQi (static 34 bit) with button parsing and add manually support (thanks to @mishamyte for captures and testing, thanks @Skorpionm for help) From 9f2b202b7dd7b87e2b20111d6990f46b12ab4306 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 22 Apr 2025 01:22:02 +0300 Subject: [PATCH 123/125] fix nightshift settings lock bug --- .../settings/notification_settings/notification_settings_app.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index cb1d1048d..3713d7e26 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -559,7 +559,7 @@ static void night_shift_changed(VariableItem* item) { // force demo night_shift brightness ot rgb backlight and stock backlight notification_message(app->notification, &sequence_display_backlight_on); - int slide = 1; + int slide = 0; for(int i = 4 + slide; i < (6 + slide); i++) { VariableItem* t_item = variable_item_list_get(app->variable_item_list, i); From 925b95007aa62174f688a47c7e91d28ad3d5ed49 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Tue, 22 Apr 2025 10:23:05 +0700 Subject: [PATCH 124/125] Code cleanup --- .../notification_settings_app.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 3713d7e26..be7af4c42 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -393,9 +393,7 @@ static void rgb_backlight_installed_changed(VariableItem* item) { } // Lock/Unlock all rgb settings depent from rgb_backlight_installed switch - int slide = 1; - - for(int i = slide; i < (slide + 8); i++) { + for(int i = 1; i < 9; 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\nOFF!"); @@ -528,7 +526,7 @@ static void rgb_backlight_rainbow_wide_changed(VariableItem* item) { notification_message_save_settings(app->notification); } -// open settings.rgb_view if user press OK on first (index=0) menu string and (debug mode or rgb_backlight_installed is true) +// open settings.rgb_view if user press OK on last (index=10) menu string void variable_item_list_enter_callback(void* context, uint32_t index) { UNUSED(context); NotificationAppSettings* app = context; @@ -556,12 +554,10 @@ static void night_shift_changed(VariableItem* item) { app->notification->current_night_shift = night_shift_value[index]; app->notification->current_night_shift = night_shift_value[index]; - // force demo night_shift brightness ot rgb backlight and stock backlight + // force demo night_shift brightness to rgb backlight and stock backlight notification_message(app->notification, &sequence_display_backlight_on); - - int slide = 0; - - for(int i = 4 + slide; i < (6 + slide); i++) { + + for(int i = 4; i < 6; i++) { VariableItem* t_item = variable_item_list_get(app->variable_item_list, i); if(index == 0) { variable_item_set_locked(t_item, true, "Night Shift\nOFF!"); @@ -723,18 +719,15 @@ static NotificationAppSettings* alloc_settings(void) { variable_item_set_current_value_text(item, lcd_inversion_text[value_index]); //--- RGB BACKLIGHT --- - // Show RGB settings only when debug_mode or rgb_backlight_installed is active item = variable_item_list_add(app->variable_item_list, "RGB Mod Settings", 0, NULL, app); //--- RGB BACKLIGHT END --- 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 exit from settings.rgb_menu + // set callback for exit from rgb settings menu view_set_previous_callback(view_rgb, notification_app_rgb_settings_exit); - // Show rgb_backlight_installed swith only in Debug mode - item = variable_item_list_add( app->variable_item_list_rgb, "RGB backlight installed", From 384cd47b1be10a57e6ba9d6894470b987dc37a1b Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 23 Apr 2025 03:16:53 +0300 Subject: [PATCH 125/125] upd changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31c20e193..0dd43e977 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ * SubGHz: Add **Prastel (42bit static code)** support (OFW PR 4178 by @pmazzini) * Desktop: **Add support for Favorite App - Ok Long** (Warning! Old favourites apps list will be reset!) (PR #886 | by @DrEverr) * Display: **LCD Color Inversion** (Settings - LCD and Notifications - LCD Inversion) (PR #887 #893 | by @Dmitry422) -* Display: **Night Shift Feature** (dimming backlight in selected time interval) (PR #885 | by @Dmitry422) +* Display: **Night Shift Feature** (dimming backlight in selected time interval) (PR #885 #896 | by @Dmitry422) * Display: **Сombining RGB Backlight mod** (by @quen0n) and original backlight support **in one firmware** (+ Rainbow/Wave effect (based on @Willy-JL idea)) (PR #877 #881 #890 | by @Dmitry422) - (**To enable RGB Backlight support go into Notifications settings**) * NFC: Use default UL/UL-C pwd/key as default value for key input (PR #891 | by @mishamyte) * OFW: LFRFID - **EM4305 support**