From a9c2b4d6a0dc0f890351763ffd94f6a904833191 Mon Sep 17 00:00:00 2001 From: Kowalski Dragon Date: Tue, 20 Dec 2022 14:57:58 +0100 Subject: [PATCH 1/4] Desktop: dummy mode improvements. Fixes: correct scrolling text, correct AM/PM in Clock. (#2160) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Show passport instead of app if SD/app is missing * Desktop: cleanup dummy mode code and add more apps * Gui: fix incorrect trimming in scrollable text Signed-off-by: Kowalski Dragon (kowalski7cc) Co-authored-by: あく --- applications/plugins/clock/clock_app.c | 2 +- .../desktop/scenes/desktop_scene_main.c | 33 +++++++++++++++---- .../services/desktop/views/desktop_events.h | 4 ++- .../desktop/views/desktop_view_main.c | 6 ++-- applications/services/gui/elements.c | 7 ++-- 5 files changed, 38 insertions(+), 14 deletions(-) diff --git a/applications/plugins/clock/clock_app.c b/applications/plugins/clock/clock_app.c index e196f0d29..9d87ff950 100644 --- a/applications/plugins/clock/clock_app.c +++ b/applications/plugins/clock/clock_app.c @@ -56,7 +56,7 @@ static void clock_render_callback(Canvas* canvas, void* ctx) { 31, AlignLeft, AlignCenter, - (data->datetime.hour > 12) ? "AM" : "PM"); + (data->datetime.hour > 12) ? "PM" : "AM"); } canvas_set_font(canvas, FontSecondary); diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index 4f01ad5be..befcf399a 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -12,6 +12,10 @@ #define TAG "DesktopSrv" +#define MUSIC_PLAYER_APP EXT_PATH("/apps/Misc/music_player.fap") +#define SNAKE_GAME_APP EXT_PATH("/apps/Games/snake_game.fap") +#define CLOCK_APP EXT_PATH("/apps/Tools/clock.fap") + static void desktop_scene_main_new_idle_animation_callback(void* context) { furi_assert(context); Desktop* desktop = context; @@ -60,6 +64,19 @@ static void desktop_switch_to_app(Desktop* desktop, const FlipperApplication* fl } #endif +static void desktop_scene_main_open_app_or_profile(Desktop* desktop, const char* path) { + do { + LoaderStatus status = loader_start(desktop->loader, FAP_LOADER_APP_NAME, path); + if(status == LoaderStatusOk) break; + FURI_LOG_E(TAG, "loader_start failed: %d", status); + + status = loader_start(desktop->loader, "Passport", NULL); + if(status != LoaderStatusOk) { + FURI_LOG_E(TAG, "loader_start failed: %d", status); + } + } while(false); +} + void desktop_scene_main_callback(DesktopEvent event, void* context) { Desktop* desktop = (Desktop*)context; view_dispatcher_send_custom_event(desktop->view_dispatcher, event); @@ -181,12 +198,16 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { } break; } - case DesktopMainEventOpenGameMenu: { - LoaderStatus status = loader_start( - desktop->loader, FAP_LOADER_APP_NAME, EXT_PATH("/apps/Games/snake_game.fap")); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } + case DesktopMainEventOpenGame: { + desktop_scene_main_open_app_or_profile(desktop, SNAKE_GAME_APP); + break; + } + case DesktopMainEventOpenClock: { + desktop_scene_main_open_app_or_profile(desktop, CLOCK_APP); + break; + } + case DesktopMainEventOpenMusicPlayer: { + desktop_scene_main_open_app_or_profile(desktop, MUSIC_PLAYER_APP); break; } case DesktopLockedEventUpdate: diff --git a/applications/services/desktop/views/desktop_events.h b/applications/services/desktop/views/desktop_events.h index a7e610fff..666d179b8 100644 --- a/applications/services/desktop/views/desktop_events.h +++ b/applications/services/desktop/views/desktop_events.h @@ -10,7 +10,9 @@ typedef enum { DesktopMainEventOpenPassport, DesktopMainEventOpenPowerOff, - DesktopMainEventOpenGameMenu, + DesktopMainEventOpenGame, + DesktopMainEventOpenClock, + DesktopMainEventOpenMusicPlayer, DesktopLockedEventUnlocked, DesktopLockedEventUpdate, diff --git a/applications/services/desktop/views/desktop_view_main.c b/applications/services/desktop/views/desktop_view_main.c index 0edc0b703..cbf4a20ff 100644 --- a/applications/services/desktop/views/desktop_view_main.c +++ b/applications/services/desktop/views/desktop_view_main.c @@ -72,13 +72,13 @@ bool desktop_main_input_callback(InputEvent* event, void* context) { } else { if(event->type == InputTypeShort) { if(event->key == InputKeyOk) { - main_view->callback(DesktopMainEventOpenGameMenu, main_view->context); + main_view->callback(DesktopMainEventOpenGame, main_view->context); } else if(event->key == InputKeyUp) { main_view->callback(DesktopMainEventOpenLockMenu, main_view->context); } else if(event->key == InputKeyDown) { - main_view->callback(DesktopMainEventOpenPassport, main_view->context); + main_view->callback(DesktopMainEventOpenMusicPlayer, main_view->context); } else if(event->key == InputKeyLeft) { - main_view->callback(DesktopMainEventOpenPassport, main_view->context); + main_view->callback(DesktopMainEventOpenClock, main_view->context); } // Right key is handled by animation manager } diff --git a/applications/services/gui/elements.c b/applications/services/gui/elements.c index 955e1fbdd..6b796ed5b 100644 --- a/applications/services/gui/elements.c +++ b/applications/services/gui/elements.c @@ -564,7 +564,7 @@ void elements_scrollable_text_line( } // Calculate scroll size - size_t scroll_size = furi_string_size(string); + size_t scroll_size = furi_string_size(line); size_t right_width = 0; for(size_t i = scroll_size; i > 0; i--) { right_width += canvas_glyph_width(canvas, furi_string_get_char(line, i)); @@ -579,10 +579,11 @@ void elements_scrollable_text_line( furi_string_right(line, scroll); } - do { + len_px = canvas_string_width(canvas, furi_string_get_cstr(line)); + while(len_px > width) { furi_string_left(line, furi_string_size(line) - 1); len_px = canvas_string_width(canvas, furi_string_get_cstr(line)); - } while(len_px > width); + } if(ellipsis) { furi_string_cat(line, "..."); From e0d716647c4936024da2f85234013fc16fc52dc9 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Tue, 20 Dec 2022 17:46:05 +0300 Subject: [PATCH 2/4] [FL-3053] Archive browser delete fix (#2163) --- applications/main/archive/scenes/archive_scene_browser.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/applications/main/archive/scenes/archive_scene_browser.c b/applications/main/archive/scenes/archive_scene_browser.c index 04f4dcc3a..2f4693548 100644 --- a/applications/main/archive/scenes/archive_scene_browser.c +++ b/applications/main/archive/scenes/archive_scene_browser.c @@ -143,6 +143,8 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { break; case ArchiveBrowserEventFileMenuDelete: if(archive_get_tab(browser) != ArchiveTabFavorites) { + scene_manager_set_scene_state( + archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_NEED_REFRESH); scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneDelete); } consumed = true; From c34ae66b6e009d4cf1d7b5baadf09131c0417efa Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Tue, 20 Dec 2022 18:07:19 +0300 Subject: [PATCH 3/4] [FL-3041] IR format docs (#2162) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../file_formats/InfraredFileFormats.md | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 documentation/file_formats/InfraredFileFormats.md diff --git a/documentation/file_formats/InfraredFileFormats.md b/documentation/file_formats/InfraredFileFormats.md new file mode 100644 index 000000000..a6d6c276d --- /dev/null +++ b/documentation/file_formats/InfraredFileFormats.md @@ -0,0 +1,111 @@ +# Infrared Flipper File Formats + +## Infrared Remote File Format +### Example + + Filetype: IR signals file + Version: 1 + # + name: Button_1 + type: parsed + protocol: NECext + address: EE 87 00 00 + command: 5D A0 00 00 + # + name: Button_2 + type: raw + frequency: 38000 + duty_cycle: 0.330000 + data: 504 3432 502 483 500 484 510 502 502 482 501 485 509 1452 504 1458 509 1452 504 481 501 474 509 3420 503 + # + name: Button_3 + type: parsed + protocol: SIRC + address: 01 00 00 00 + command: 15 00 00 00 + +### Description +Filename extension: `.ir` + +This file format is used to store an infrared remote that consists of an arbitrary number of buttons. +Each button is separated from others by a comment character (`#`) for better readability. + +Known protocols are represented in the `parsed` form, whereas non-recognised signals may be saved and re-transmitted as `raw` data. + +#### Version history: +1. Initial version. + +#### Format fields +| Name | Use | Type | Description | +| ---------- | ------- | ------ |------------ | +| name | both | string | Name of the button. Only printable ASCII characters are allowed. | +| type | both | string | Type of the signal. Must be `parsed` or `raw`. | +| protocol | parsed | string | Name of the infrared protocol. Refer to `ir` console command for the complete list of supported protocols. | +| address | parsed | hex | Payload address. Must be 4 bytes long. | +| command | parsed | hex | Payload command. Must be 4 bytes long. | +| frequency | raw | uint32 | Carrier frequency, in Hertz, usually 38000 Hz. | +| duty_cycle | raw | float | Carrier duty cycle, usually 0.33. | +| data | raw | uint32 | Raw signal timings, in microseconds between logic level changes. Individual elements must be space-separated. Maximum timings amount is 1024. | + +## Infrared Library File Format +### Examples +- [TV Universal Library](/assets/resources/infrared/assets/tv.ir) +- [A/C Universal Library](/assets/resources/infrared/assets/ac.ir) +- [Audio Universal Library](/assets/resources/infrared/assets/audio.ir) + +### Description +Filename extension: `.ir` + +This file format is used to store universal remote libraries. It is identical to the previous format, differing only in the `Filetype` field.\ +It also has predefined button names for each universal library type, so that the universal remote application could understand them. +See [Universal Remotes](/documentation/UniversalRemotes.md) for more information. + +### Version history: +1. Initial version. + +## Infrared Test File Format +### Examples +See [Infrared Unit Tests](/assets/unit_tests/infrared/) for various examples. +### Description +Filename extension: `.irtest` + +This file format is used to store technical test data that is too large to keep directly in the firmware. +It is mostly similar to the two previous formats, with the main difference being the addition of the parsed signal arrays. + +Each infrared protocol must have corresponding unit tests complete with an `.irtest` file. + +Known protocols are represented in the `parsed_array` form, whereas raw data has the `raw` type.\ +Note: a single parsed signal must be represented as an array of size 1. + +### Version history: +1. Initial version. + +#### Format fields +| Name | Use | Type | Description | +| ---------- | ------------ | ------ |------------ | +| name | both | string | Name of the signal. Only printable ASCII characters are allowed. | +| type | both | string | Type of the signal. Must be `parsed_array` or `raw`. | +| count | parsed_array | uint32 | The number of parsed signals in an array. Must be at least 1. | +| protocol | parsed_array | string | Same as in previous formats. | +| address | parsed_array | hex | Ditto. | +| command | parsed_array | hex | Ditto. | +| repeat | parsed_array | bool | Indicates whether the signal is a repeated button press. | +| frequency | raw | uint32 | Same as in previous formats. | +| duty_cycle | raw | float | Ditto. | +| data | raw | uint32 | Ditto. | + +#### Signal names +The signal names in an `.irtest` file folow a convention ``, where the name is one of: +- decoder_input +- decoder_expected +- encoder_decoder_input, + +and the number is a sequential integer: 1, 2, 3...etc, which produces names like `decoder_input1`, `encoder_decoder_input3`, and so on. + +| Name | Type | Description | +| --------------------- | ------------ | ----------- | +| decoder_input | raw | A raw signal contaning the decoder input. Is also used as the expected encoder output. | +| decoder_expected | parsed_array | An array of parsed signals containing the expected decoder output. Is also used as the encoder input. | +| encoder_decoder_input | parsed_array | An array of parsed signals containing both the encoder-decoder input and expected output. | + +See [Unit Tests](/documentation/UnitTests.md#infrared) for more info. From 5856746fc9774157aa3f42608f5019efa829f76b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Wed, 21 Dec 2022 18:07:14 +0900 Subject: [PATCH 4/4] iButton: fixed notification on successful read (#2169) --- applications/main/ibutton/scenes/ibutton_scene_read.c | 1 - applications/main/ibutton/scenes/ibutton_scene_read_success.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/applications/main/ibutton/scenes/ibutton_scene_read.c b/applications/main/ibutton/scenes/ibutton_scene_read.c index 1fe75e45a..b5ee08e6f 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_read.c +++ b/applications/main/ibutton/scenes/ibutton_scene_read.c @@ -52,7 +52,6 @@ bool ibutton_scene_read_on_event(void* context, SceneManagerEvent event) { if(success) { ibutton_notification_message(ibutton, iButtonNotificationMessageSuccess); - ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOn); scene_manager_next_scene(scene_manager, iButtonSceneReadSuccess); DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess); } diff --git a/applications/main/ibutton/scenes/ibutton_scene_read_success.c b/applications/main/ibutton/scenes/ibutton_scene_read_success.c index 1c2bcdd29..749e7af37 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_read_success.c +++ b/applications/main/ibutton/scenes/ibutton_scene_read_success.c @@ -48,6 +48,8 @@ void ibutton_scene_read_success_on_enter(void* context) { dialog_ex_set_context(dialog_ex, ibutton); view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewDialogEx); + + ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOn); } bool ibutton_scene_read_success_on_event(void* context, SceneManagerEvent event) {