From e42aec68c533e6120f0e776e8bdc5d7d89e99c8b Mon Sep 17 00:00:00 2001 From: Max Andreev Date: Fri, 28 Apr 2023 17:25:20 +0300 Subject: [PATCH 01/30] Disable ci/cd on release* branches (#2624) --- .github/workflows/build.yml | 7 +++---- .github/workflows/lint_and_submodule_check.yml | 5 ++--- .github/workflows/merge_report.yml | 2 +- .github/workflows/pvs_studio.yml | 3 +-- .github/workflows/unit_tests.yml | 2 +- .github/workflows/updater_test.yml | 6 +++--- 6 files changed, 11 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dfeb8d83f2..0934eec76d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,6 @@ on: push: branches: - dev - - "release*" tags: - '*' pull_request: @@ -19,7 +18,7 @@ jobs: runs-on: [self-hosted,FlipperZeroShell] steps: - name: 'Wipe workspace' - run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' uses: actions/checkout@v3 @@ -167,7 +166,7 @@ jobs: target: [f7, f18] steps: - name: 'Wipe workspace' - run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' uses: actions/checkout@v3 @@ -207,7 +206,7 @@ jobs: cd testapp ufbt create APPID=testapp ufbt - + - name: Build example & external apps with uFBT run: | for appdir in 'applications/external' 'applications/examples'; do diff --git a/.github/workflows/lint_and_submodule_check.yml b/.github/workflows/lint_and_submodule_check.yml index 999111cc95..22ca7d893f 100644 --- a/.github/workflows/lint_and_submodule_check.yml +++ b/.github/workflows/lint_and_submodule_check.yml @@ -4,7 +4,6 @@ on: push: branches: - dev - - "release*" tags: - '*' pull_request: @@ -19,7 +18,7 @@ jobs: runs-on: [self-hosted,FlipperZeroShell] steps: - name: 'Wipe workspace' - run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' uses: actions/checkout@v3 @@ -64,7 +63,7 @@ jobs: else echo "Python Lint: all good ✨" >> $GITHUB_STEP_SUMMARY; fi - + - name: 'Check C++ code formatting' id: syntax_check_cpp if: always() diff --git a/.github/workflows/merge_report.yml b/.github/workflows/merge_report.yml index 5b7d5fcbf7..0201666665 100644 --- a/.github/workflows/merge_report.yml +++ b/.github/workflows/merge_report.yml @@ -13,7 +13,7 @@ jobs: runs-on: [self-hosted,FlipperZeroShell] steps: - name: 'Wipe workspace' - run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' uses: actions/checkout@v3 diff --git a/.github/workflows/pvs_studio.yml b/.github/workflows/pvs_studio.yml index b8c4d7a367..cb5b50278a 100644 --- a/.github/workflows/pvs_studio.yml +++ b/.github/workflows/pvs_studio.yml @@ -4,7 +4,6 @@ on: push: branches: - dev - - "release*" tags: - '*' pull_request: @@ -20,7 +19,7 @@ jobs: runs-on: [self-hosted, FlipperZeroShell] steps: - name: 'Wipe workspace' - run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' uses: actions/checkout@v3 diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 6a824fac31..81f0e0d050 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -13,7 +13,7 @@ jobs: runs-on: [self-hosted, FlipperZeroUnitTest] steps: - name: 'Wipe workspace' - run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: Checkout code uses: actions/checkout@v3 diff --git a/.github/workflows/updater_test.yml b/.github/workflows/updater_test.yml index 2861529d83..bd83729797 100644 --- a/.github/workflows/updater_test.yml +++ b/.github/workflows/updater_test.yml @@ -13,13 +13,13 @@ jobs: runs-on: [self-hosted, FlipperZeroUpdaterTest] steps: - name: 'Wipe workspace' - run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: Checkout code uses: actions/checkout@v3 with: fetch-depth: 1 - submodules: false + submodules: false ref: ${{ github.event.pull_request.head.sha }} - name: 'Get flipper from device manager (mock)' @@ -50,7 +50,7 @@ jobs: echo "tag=$(git tag -l --sort=-version:refname | grep -v "rc\|RC" | head -1)" >> $GITHUB_OUTPUT - name: 'Wipe workspace' - run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout latest release' uses: actions/checkout@v3 From 2e162c11311a7e6937e26901fe692fde56a6479c Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 2 May 2023 04:20:22 +0300 Subject: [PATCH 02/30] Replace QR code with good old link --- assets/slideshow/update_default/frame_01.png | Bin 933 -> 3213 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/slideshow/update_default/frame_01.png b/assets/slideshow/update_default/frame_01.png index 8a1b6585738886eee91d24c415ea17210706e004..ea37077ccd150cf1ac6149567f0cdb3a9ac6eb4b 100644 GIT binary patch literal 3213 zcmcIn32+nV6_$-LhJp#9q@0aLP!7|T{=E-uV_6chTMHW_8oOYcJ^qzdOIo3oPaMa% zKn*l7NiYfE1PUYsN((p{I^hbYfoTl}Cm}YZ7@8p&a|B4HE;mho*^=Wn4)J8Bnpy4c zzwiIv_ul*7(`rS|?5Bne89T&aFbvDgu;-$4H9FD~V$pZO+n1-J)8IfxzHTs>Cx(xh zve##pptU%UD=(Di%o1eHXBHJrg61+`09hLh$ur9WqFe++MhUt-{uI;A1MixQ9wo)} zH0=b=fDIOUGAe>_ZpCbuTu~(RifLx5F}X}Y06rKJjb%QsUl+8g^*RbLJRrS`Zo;Gr(j32qVjzafYHe?x#iq5WoUh3l1=X5C9|4q%ra_A#XuN z6>{yfBEHaFim5OZ3J4ZUX=$mslr(EWw*}{U-U0{(?V`LJ6~!i2)042H}vRhEC_BO?|!|Ydz#BL0%$! z`vlfq9Ezk>n$V^AX@E%uzLM^1}h1$2o z(et<`nt)&nLNTNTU7F^N7Ahx-Vk8JNFiw5i<5#p&eOj1NWCOH|A(&!9RU0pM0HE8{iFBZdA+eV+sxJ;)I3rL%AejF$))bFg-XBw^Q^@q|A<-|xOnZt6 zkurNciolSJDzcJ@K^1x76pFw^iBm9{APHU~c!J=hE?#KAU6YH$=?m}gmaU@62%{%M z0!5GtK?5FRNu0naoKi8Km5@4dk!4k!5mkwaqGbm?sB=VbZ`3d=1tE$wqQ$Wy24tj3 z2q_lh30%c!o}pEdBuR$kO-4l)R4wQekxo25(G4vDzuRQ|nvG5KYC)%_pq!Jv*E4Ol zoS>$9yy$_R`&7Cy(_v$9o?$S;jE7~9XrOR2JUXgzd8Co%!bOoQugBP>PC=BzO_5@f z!)kzvDYES8BhCE_s2jGl5F*e=sHEFW*VIs{7=%_gD#>@M(DH5Mb+P2p)OnTWc^WVn zOA$DxDwKk8G7m6bCKwi1SU^EF8v6f*dL*rKq3Cx*G+`~K?;lM6XDkJi|(H4ruN;KBqIVG@;t_n6lzC6k>OsKFXaS3q(X3$N$9uo#IZWr~5Qwb8VI3IgOHr(!D35(-oZ0?4qxSdz-p1j+Ci$lfC?QRjj-GmPhNP%d*!`IVy735_&%f zU-rD1pqrjo8|X*f7DO*DsfS{%2EzbLrrqi)tG~XX@x{Lw6Vl|37w&yE^W*v3$s3L5 zh7Pm?d{_R39UCP_jJ07}$HBO&^9M)Wxw$l^e((TpWPD)q(0^o&KC&KElcK?W)Nrcz zgOgYPSpEFk4{nXQwW#RySE(anPHoG7;J9>&JZ`mDlP`T%9oyM?Zbd>str?&8@X+O~ z><1e@{ncbs6wRDFuzCKE9B~|J9p$Rs7ywJ>jL4~9^aLAHym2Qtj?0#7WA;6}CZSLw z)6V6e+g-PC_wdA`(fOmQR|zwf#iq1d*Xs2VuN-|i_g+&?$F*IDYOQT&*DhbbPA!?-s>8_ ze%|t=>fm?IS5sT#E0|K^@| z_wdDI5{JW*=e+GXol`2Sell)o#qXPMWM4`keAj3%xN&jt*|>A7tA9CsLKP@JGT^T( zy<0p}bA^MmNbPpsCyryUmDlZmzm$uee!tasw>9rW{1@>{9_(9_+IGS_`^eR_i_KR$ z+HH$%)a*l^yA_9CJMDIk{@YtW|LFYvEcwcrqboPGzP|TV#iUmg+n2N)9*oavj&a<0 zSas3==hGc8=~c-;zJ0%7oqPNC*w}k}cdbfTR=r^2o_}uHP25h(BbR;p#D-_bwEf`f zbpEnu?)0@+(uxvVD=T*_ozWDN^WwbC1q11~R?^p7mi+eRY&tu6TaJI>in#Koro>t7 zu4Ut2D6F~u_tot;t6Se|U+kN=HUF`Ooj)5gbTaPoM?gwB>7 zUpnv9FI2zWI&Ac@=8Bj9?b1#6>Qj^5pZsp}Z?f74{p;|njZ<87L!xtU;+;TpvtjGF yQ4<#X?(KN^g}K2!*L?l~e?I=ejhIHR%5a!=JyZ0-)}7%$44IDE_CKXRQ}Z9Je{J0W delta 922 zcmV;L17-Y;8Kno18Gi-<007d~e}4b~00DDSM?wIu&K&6g00Uo1L_t(|ob8iBe`WTIE%GqFHinSeN1D{8gnErJ{z^)%wO&bBzMd8!d6raw;G_ZsClw$#sQ|%A z1qexbc^7;ek2sM5Y`9a z;FQavbV!(YUGfFAo`*100IxlkTglq0-|2fkr5EOTXMa6s32OnYj;MA#RRXILuTp+f zKfr9Egd5MzYwasQ~ffSQ&bHhIHumsl_D^fSAGFdoHP>m1ouJh(P86 zf@A6j(0cFMW(#Q?nwEW2zThd+0tBawo)P4|w`${it;I-Fkw~;yjb%gc-Jb1fxaPa}? z_}OY77Y#^qadIR)p?!c^W>)|1JCHa`nLuk_0Dm2au2i%ZVDV8b-oD3$-)Wsj|6^zi zpt+D9EB2|ai3@eFYwY;fCg!^~C-I1FiWE9|e!Jl?CXWQzQJ|hUdvqxJi zm^uDQ7oS7p*MzeG9v7`vzuVbMDZhWc Date: Tue, 2 May 2023 22:25:05 +0500 Subject: [PATCH 03/30] Added numpad keyboard --- applications/external/hid_app/hid.c | 15 + applications/external/hid_app/hid.h | 2 + applications/external/hid_app/views.h | 1 + .../external/hid_app/views/hid_numpad.c | 302 ++++++++++++++++++ .../external/hid_app/views/hid_numpad.h | 14 + 5 files changed, 334 insertions(+) create mode 100644 applications/external/hid_app/views/hid_numpad.c create mode 100644 applications/external/hid_app/views/hid_numpad.h diff --git a/applications/external/hid_app/hid.c b/applications/external/hid_app/hid.c index f29a3b22af..791f6b2e4c 100644 --- a/applications/external/hid_app/hid.c +++ b/applications/external/hid_app/hid.c @@ -9,6 +9,7 @@ enum HidDebugSubmenuIndex { HidSubmenuIndexKeynote, HidSubmenuIndexKeynoteVertical, HidSubmenuIndexKeyboard, + HidSubmenuIndexNumpad, HidSubmenuIndexMedia, HidSubmenuIndexTikTok, HidSubmenuIndexYTShorts, @@ -28,6 +29,9 @@ static void hid_submenu_callback(void* context, uint32_t index) { } else if(index == HidSubmenuIndexKeyboard) { app->view_id = HidViewKeyboard; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeyboard); + } else if(index == HidSubmenuIndexNumpad) { + app->view_id = HidViewNumpad; + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewNumpad); } else if(index == HidSubmenuIndexMedia) { app->view_id = HidViewMedia; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMedia); @@ -60,6 +64,7 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con hid_keynote_set_connected_status(hid->hid_keynote, connected); hid_keynote_vertical_set_connected_status(hid->hid_keynote_vertical, connected); hid_keyboard_set_connected_status(hid->hid_keyboard, connected); + hid_numpad_set_connected_status(hid->hid_numpad, connected); hid_media_set_connected_status(hid->hid_media, connected); hid_mouse_set_connected_status(hid->hid_mouse, connected); hid_mouse_jiggler_set_connected_status(hid->hid_mouse_jiggler, connected); @@ -118,6 +123,8 @@ Hid* hid_alloc(HidTransport transport) { app); submenu_add_item( app->device_type_submenu, "Keyboard", HidSubmenuIndexKeyboard, hid_submenu_callback, app); + submenu_add_item( + app->device_type_submenu, "Numpad keyboard", HidSubmenuIndexNumpad, hid_submenu_callback, app); submenu_add_item( app->device_type_submenu, "Media", HidSubmenuIndexMedia, hid_submenu_callback, app); submenu_add_item( @@ -185,6 +192,12 @@ Hid* hid_app_alloc_view(void* context) { view_dispatcher_add_view( app->view_dispatcher, HidViewKeyboard, hid_keyboard_get_view(app->hid_keyboard)); + //Numpad keyboard view + app->hid_numpad = hid_numpad_alloc(app); + view_set_previous_callback(hid_numpad_get_view(app->hid_numpad), hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, HidViewNumpad, hid_numpad_get_view(app->hid_numpad)); + // Media view app->hid_media = hid_media_alloc(app); view_set_previous_callback(hid_media_get_view(app->hid_media), hid_exit_confirm_view); @@ -240,6 +253,8 @@ void hid_free(Hid* app) { hid_keynote_vertical_free(app->hid_keynote_vertical); view_dispatcher_remove_view(app->view_dispatcher, HidViewKeyboard); hid_keyboard_free(app->hid_keyboard); + view_dispatcher_remove_view(app->view_dispatcher, HidViewNumpad); + hid_numpad_free(app->hid_numpad); view_dispatcher_remove_view(app->view_dispatcher, HidViewMedia); hid_media_free(app->hid_media); view_dispatcher_remove_view(app->view_dispatcher, HidViewMouse); diff --git a/applications/external/hid_app/hid.h b/applications/external/hid_app/hid.h index be9176a289..3478a51947 100644 --- a/applications/external/hid_app/hid.h +++ b/applications/external/hid_app/hid.h @@ -19,6 +19,7 @@ #include "views/hid_keynote.h" #include "views/hid_keynote_vertical.h" #include "views/hid_keyboard.h" +#include "views/hid_numpad.h" #include "views/hid_media.h" #include "views/hid_mouse.h" #include "views/hid_mouse_jiggler.h" @@ -44,6 +45,7 @@ struct Hid { HidKeynote* hid_keynote; HidKeynoteVertical* hid_keynote_vertical; HidKeyboard* hid_keyboard; + HidNumpad* hid_numpad; HidMedia* hid_media; HidMouse* hid_mouse; HidMouseJiggler* hid_mouse_jiggler; diff --git a/applications/external/hid_app/views.h b/applications/external/hid_app/views.h index 81e8d6dbea..ec4d23ad9f 100644 --- a/applications/external/hid_app/views.h +++ b/applications/external/hid_app/views.h @@ -3,6 +3,7 @@ typedef enum { HidViewKeynote, HidViewKeynoteVertical, HidViewKeyboard, + HidViewNumpad, HidViewMedia, HidViewMouse, HidViewMouseJiggler, diff --git a/applications/external/hid_app/views/hid_numpad.c b/applications/external/hid_app/views/hid_numpad.c new file mode 100644 index 0000000000..d3b488801c --- /dev/null +++ b/applications/external/hid_app/views/hid_numpad.c @@ -0,0 +1,302 @@ +#include "hid_numpad.h" +#include +#include +#include +#include "../hid.h" +#include "hid_icons.h" + +#define TAG "HidNumpad" + +struct HidNumpad { + View* view; + Hid* hid; +}; + +typedef struct { + uint8_t last_x; + uint8_t last_y; + uint8_t x; + uint8_t y; + uint8_t last_key_code; + uint16_t modifier_code; + bool ok_pressed; + bool back_pressed; + bool connected; + char key_string[5]; + HidTransport transport; +} HidNumpadModel; + +typedef struct { + uint8_t width; + char* key; + uint8_t height; + const Icon* icon; + uint8_t value; +} HidNumpadKey; + +typedef struct { + int8_t x; + int8_t y; +} HidNumpadPoint; + +#define MARGIN_TOP 0 +#define MARGIN_LEFT 24 +#define KEY_WIDTH 20 +#define KEY_HEIGHT 15 +#define KEY_PADDING 1 +#define ROW_COUNT 5 +#define COLUMN_COUNT 4 + +const HidNumpadKey hid_numpad_keyset[ROW_COUNT][COLUMN_COUNT] = { + { + {.width = 1, .height = 1, .icon = NULL, .key = "NL", .value = HID_KEYPAD_NUMLOCK}, + {.width = 1, .height = 1, .icon = NULL, .key = "/", .value = HID_KEYPAD_SLASH}, + {.width = 1, .height = 1, .icon = NULL, .key = "*", .value = HID_KEYPAD_ASTERISK}, + {.width = 1, .height = 1, .icon = NULL, .key = "-", .value = HID_KEYPAD_MINUS}, + }, + { + {.width = 1, .height = 1, .icon = NULL, .key = "7", .value = HID_KEYPAD_7}, + {.width = 1, .height = 1, .icon = NULL, .key = "8", .value = HID_KEYBOARD_8}, + {.width = 1, .height = 1, .icon = NULL, .key = "9", .value = HID_KEYBOARD_9}, + {.width = 1, .height = 2, .icon = NULL, .key = "+", .value = HID_KEYPAD_PLUS}, + }, + { + {.width = 1, .height = 1, .icon = NULL, .key = "4", .value = HID_KEYPAD_4}, + {.width = 1, .height = 1, .icon = NULL, .key = "5", .value = HID_KEYPAD_5}, + {.width = 1, .height = 1, .icon = NULL, .key = "6", .value = HID_KEYPAD_6}, + }, + { + {.width = 1, .height = 1, .icon = NULL, .key = "1", .value = HID_KEYPAD_1}, + {.width = 1, .height = 1, .icon = NULL, .key = "2", .value = HID_KEYPAD_2}, + {.width = 1, .height = 1, .icon = NULL, .key = "3", .value = HID_KEYPAD_3}, + {.width = 1, .height = 2, .icon = NULL, .key = "En", .value = HID_KEYPAD_ENTER}, + }, + { + {.width = 2, .height = 1, .icon = NULL, .key = "0", .value = HID_KEYBOARD_0}, + {.width = 0, .height = 0, .icon = NULL, .key = "0", .value = HID_KEYBOARD_0}, + {.width = 1, .height = 1, .icon = NULL, .key = ".", .value = HID_KEYPAD_DOT}, + }, +}; + +static void hid_numpad_draw_key( + Canvas* canvas, + HidNumpadModel* model, + uint8_t x, + uint8_t y, + HidNumpadKey key, + bool selected) { + if(!key.width || !key.height) return; + + canvas_set_color(canvas, ColorBlack); + uint8_t keyWidth = KEY_WIDTH * key.width + KEY_PADDING * (key.width - 1); + uint8_t keyHeight = KEY_HEIGHT * key.height + KEY_PADDING * (key.height - 1); + if(selected) { + elements_slightly_rounded_box( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING), + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING), + keyWidth, + keyHeight); + canvas_set_color(canvas, ColorWhite); + } else { + elements_slightly_rounded_frame( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING), + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING), + keyWidth, + keyHeight); + } + if(key.icon != NULL) { + canvas_draw_icon( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING) + keyWidth / 2 - key.icon->width / 2, + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING) + keyHeight / 2 - key.icon->height / 2, + key.icon); + } else { + strcpy(model->key_string, key.key); + canvas_draw_str_aligned( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING) + keyWidth / 2 + 1, + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING) + keyHeight / 2 + 1, + AlignCenter, + AlignCenter, + model->key_string); + } +} + +static void hid_numpad_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + HidNumpadModel* model = context; + + if((!model->connected) && (model->transport == HidTransportBle)) { + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Numpad"); + + canvas_draw_icon(canvas, 68, 3, &I_Pin_back_arrow_10x8); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned(canvas, 127, 4, AlignRight, AlignTop, "Hold to exit"); + + elements_multiline_text_aligned( + canvas, 4, 60, AlignLeft, AlignBottom, "Waiting for Connection..."); + return; + } + + canvas_set_font(canvas, FontKeyboard); + uint8_t initY = model->y == 0 ? 0 : 1; + + if(model->y > 5) { + initY = model->y - 4; + } + + for(uint8_t y = initY; y < ROW_COUNT; y++) { + const HidNumpadKey* numpadKeyRow = hid_numpad_keyset[y]; + uint8_t x = 0; + for(uint8_t i = 0; i < COLUMN_COUNT; i++) { + HidNumpadKey key = numpadKeyRow[i]; + bool keySelected = (x <= model->x && model->x < (x + key.width)) && y == model->y; + bool backSelected = model->back_pressed && key.value == HID_KEYBOARD_DELETE; + hid_numpad_draw_key( + canvas, + model, + x, + y - initY, + key, + (!model->ok_pressed && keySelected) || backSelected); + x += key.width; + } + } +} + +static uint8_t hid_numpad_get_selected_key(HidNumpadModel* model) { + HidNumpadKey key = hid_numpad_keyset[model->y][model->x]; + return key.value; +} + +static void hid_numpad_get_select_key(HidNumpadModel* model, HidNumpadPoint delta) { + do { + const int delta_sum = model->y + delta.y; + model->y = delta_sum < 0 ? ROW_COUNT - 1 : delta_sum % ROW_COUNT; + } while(delta.y != 0 && hid_numpad_keyset[model->y][model->x].value == 0); + + do { + const int delta_sum = model->x + delta.x; + model->x = delta_sum < 0 ? COLUMN_COUNT - 1 : delta_sum % COLUMN_COUNT; + } while(delta.x != 0 && hid_numpad_keyset[model->y][model->x].width == 0); +} + +static void hid_numpad_process(HidNumpad* hid_numpad, InputEvent* event) { + with_view_model( + hid_numpad->view, + HidNumpadModel * model, + { + if(event->key == InputKeyOk) { + if(event->type == InputTypePress) { + model->ok_pressed = true; + } else if(event->type == InputTypeLong || event->type == InputTypeShort) { + model->last_key_code = hid_numpad_get_selected_key(model); + hid_hal_keyboard_press( + hid_numpad->hid, model->modifier_code | model->last_key_code); + } else if(event->type == InputTypeRelease) { + hid_hal_keyboard_release( + hid_numpad->hid, model->modifier_code | model->last_key_code); + model->ok_pressed = false; + } + } else if(event->key == InputKeyBack) { + if(event->type == InputTypePress) { + model->back_pressed = true; + } else if(event->type == InputTypeShort) { + hid_hal_keyboard_press(hid_numpad->hid, HID_KEYBOARD_DELETE); + hid_hal_keyboard_release(hid_numpad->hid, HID_KEYBOARD_DELETE); + } else if(event->type == InputTypeRelease) { + model->back_pressed = false; + } + } else if(event->type == InputTypePress || event->type == InputTypeRepeat) { + if(event->key == InputKeyUp) { + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = 0, .y = -1}); + } else if(event->key == InputKeyDown) { + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = 0, .y = 1}); + } else if(event->key == InputKeyLeft) { + if(model->last_x == 2 && model->last_y == 2 && model->y == 1 && + model->x == 3) { + model->x = model->last_x; + model->y = model->last_y; + } else if( + model->last_x == 2 && model->last_y == 4 && model->y == 3 && + model->x == 3) { + model->x = model->last_x; + model->y = model->last_y; + } else + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = -1, .y = 0}); + model->last_x = 0; + model->last_y = 0; + } else if(event->key == InputKeyRight) { + if(model->x == 2 && model->y == 2) { + model->last_x = model->x; + model->last_y = model->y; + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = 1, .y = -1}); + } else if(model->x == 2 && model->y == 4) { + model->last_x = model->x; + model->last_y = model->y; + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = 1, .y = -1}); + } else { + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = 1, .y = 0}); + } + } + } + }, + true); +} + +static bool hid_numpad_input_callback(InputEvent* event, void* context) { + furi_assert(context); + HidNumpad* hid_numpad = context; + bool consumed = false; + + if(event->type == InputTypeLong && event->key == InputKeyBack) { + hid_hal_keyboard_release_all(hid_numpad->hid); + } else { + hid_numpad_process(hid_numpad, event); + consumed = true; + } + + return consumed; +} + +HidNumpad* hid_numpad_alloc(Hid* bt_hid) { + HidNumpad* hid_numpad = malloc(sizeof(HidNumpad)); + hid_numpad->view = view_alloc(); + hid_numpad->hid = bt_hid; + view_set_context(hid_numpad->view, hid_numpad); + view_allocate_model(hid_numpad->view, ViewModelTypeLocking, sizeof(HidNumpadModel)); + view_set_draw_callback(hid_numpad->view, hid_numpad_draw_callback); + view_set_input_callback(hid_numpad->view, hid_numpad_input_callback); + + with_view_model( + hid_numpad->view, + HidNumpadModel * model, + { + model->transport = bt_hid->transport; + model->y = 0; + }, + true); + + return hid_numpad; +} + +void hid_numpad_free(HidNumpad* hid_numpad) { + furi_assert(hid_numpad); + view_free(hid_numpad->view); + free(hid_numpad); +} + +View* hid_numpad_get_view(HidNumpad* hid_numpad) { + furi_assert(hid_numpad); + return hid_numpad->view; +} + +void hid_numpad_set_connected_status(HidNumpad* hid_numpad, bool connected) { + furi_assert(hid_numpad); + with_view_model( + hid_numpad->view, HidNumpadModel * model, { model->connected = connected; }, true); +} diff --git a/applications/external/hid_app/views/hid_numpad.h b/applications/external/hid_app/views/hid_numpad.h new file mode 100644 index 0000000000..d9bf54df9e --- /dev/null +++ b/applications/external/hid_app/views/hid_numpad.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +typedef struct Hid Hid; +typedef struct HidNumpad HidNumpad; + +HidNumpad* hid_numpad_alloc(Hid* bt_hid); + +void hid_numpad_free(HidNumpad* hid_numpad); + +View* hid_numpad_get_view(HidNumpad* hid_numpad); + +void hid_numpad_set_connected_status(HidNumpad* hid_numpad, bool connected); From 259855e7885ce9d7866fbe0b907313edba260cee Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Tue, 2 May 2023 20:52:41 +0100 Subject: [PATCH 04/30] Updated ac.ir New additions --- assets/resources/infrared/assets/ac.ir | 34 ++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index 49a4acd200..777d5399c4 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 14th Apr, 2023 -# Last Checked 25th Apr, 2023 +# Last Updated 2nd May, 2023 +# Last Checked 2nd May, 2023 # name: POWER type: raw @@ -1740,3 +1740,33 @@ type: parsed protocol: NEC address: 04 00 00 00 command: 00 00 00 00 +# +name: TEMP+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 443 457 418 451 424 445 420 449 416 453 422 25403 3487 1758 421 1325 416 445 420 452 423 446 419 1319 422 447 418 450 415 456 419 449 416 1323 418 454 421 1316 414 1326 415 462 424 1307 423 1315 415 1323 418 1322 419 1321 420 449 416 452 423 1316 414 455 420 448 417 453 422 447 418 452 423 448 417 451 424 443 422 450 415 452 423 445 420 450 415 456 419 450 415 452 423 447 418 450 415 456 419 1318 423 447 418 454 421 445 420 450 415 453 422 446 419 451 424 1315 415 1324 417 454 421 446 419 1321 420 1319 422 448 417 452 423 445 420 449 416 453 422 448 417 452 423 445 420 449 416 455 420 1319 422 1314 416 1325 416 1322 419 1322 419 1318 423 1317 424 447 418 1320 421 1317 424 1317 424 1315 415 455 420 449 416 452 423 447 418 451 414 454 421 448 417 453 422 448 417 452 423 444 421 449 416 452 423 447 418 453 422 445 420 450 415 456 419 448 417 453 422 446 419 450 415 455 420 450 415 453 422 448 417 452 423 444 421 448 417 454 421 446 419 452 423 445 420 450 415 453 422 447 418 451 424 446 419 449 416 454 421 447 418 452 423 446 419 452 423 1315 415 451 424 1316 414 456 419 451 414 453 422 1317 424 1316 425 444 421 447 418 452 423 448 417 450 415 455 420 456 419 449 416 446 419 451 414 455 420 1320 421 447 418 452 423 453 422 439 415 1324 417 459 416 446 419 451 424 446 419 1320 421 446 419 1319 422 +# +name: TEMP- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 444 455 420 449 416 454 421 448 417 451 424 25402 3487 1758 421 1317 424 445 420 452 423 443 422 1317 424 447 418 451 424 447 418 449 416 1324 417 452 423 1315 415 1324 417 452 423 1316 425 1315 415 1325 416 1323 418 1319 422 449 416 452 423 1318 423 445 420 448 417 453 422 447 418 452 423 446 419 449 416 455 420 447 418 453 422 446 419 452 423 446 419 451 424 444 421 447 418 451 424 445 420 1320 421 448 417 454 421 445 420 452 423 445 420 450 415 454 421 1316 414 1324 417 454 421 448 417 1321 420 1320 421 448 417 453 422 446 419 452 423 446 419 449 416 455 420 448 417 451 424 445 420 1321 420 1319 422 1316 414 1324 417 1324 417 1321 420 1320 421 449 416 1323 418 1323 418 1319 422 1317 424 446 419 453 422 445 420 450 415 453 422 448 417 452 423 447 418 450 415 455 420 448 417 454 421 445 420 451 414 455 420 449 416 454 421 448 417 452 423 446 419 449 416 454 421 447 418 452 423 445 420 450 415 454 421 450 415 454 421 447 418 452 423 444 421 451 424 442 423 449 416 451 424 445 420 450 415 455 420 448 417 454 421 447 418 450 415 457 418 1317 424 448 417 1320 421 448 417 453 422 449 416 1321 420 1320 421 448 417 452 423 449 416 451 424 446 419 448 417 454 421 449 416 452 423 447 418 452 423 1315 415 452 423 447 418 451 424 446 419 1319 422 448 417 451 424 446 419 449 416 1324 417 453 422 1316 414 +# SWING_HORIZONTAL +name: SWING +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 446 455 420 449 416 461 393 467 419 454 421 25402 3484 1759 419 1319 422 449 416 454 421 447 418 1322 419 449 416 454 421 449 416 452 423 1317 424 444 421 1321 420 1316 425 446 419 1329 422 1308 422 1318 422 1317 424 1314 416 453 422 447 418 1323 418 451 424 444 421 448 417 454 421 449 416 458 417 444 421 449 416 454 421 447 418 453 422 446 419 456 419 445 420 448 417 452 423 446 419 451 424 1316 414 453 422 447 418 453 422 446 419 451 414 455 420 449 416 1324 417 1321 420 452 423 444 421 1318 423 1317 423 445 420 450 415 455 420 447 418 455 420 447 418 451 424 445 420 456 419 444 421 1317 424 1316 424 1315 415 1323 417 452 423 1316 414 456 419 1318 423 448 417 452 423 444 421 450 415 456 419 448 417 453 422 447 418 450 415 454 421 448 417 454 421 446 419 452 423 446 419 449 416 455 420 448 417 452 423 448 417 451 424 451 424 445 420 444 421 447 418 460 415 446 419 451 424 446 419 450 415 454 421 449 416 1321 420 451 424 444 421 449 416 453 422 447 418 454 421 445 420 449 416 456 419 449 416 452 423 447 418 451 424 444 421 451 424 1314 416 453 422 1324 417 445 420 449 416 453 422 1319 422 1315 415 455 420 448 417 452 423 453 422 442 423 451 424 439 415 454 421 447 418 451 424 447 418 1322 418 451 424 442 423 448 417 451 424 1317 423 1315 415 454 421 449 416 460 415 446 419 1320 421 1319 422 +# OFF +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 445 455 421 449 416 453 422 447 418 451 424 25400 3494 1753 416 1322 419 450 415 456 420 449 416 1325 416 451 425 444 421 448 417 453 423 1318 423 444 421 1320 421 1316 414 457 419 1320 421 1318 423 1314 417 1322 419 1320 421 449 416 453 422 1317 424 445 420 450 415 456 419 447 418 451 414 456 420 449 416 452 424 448 417 453 422 445 420 450 415 456 419 448 417 452 423 447 418 449 416 453 423 448 417 453 423 446 419 449 416 453 423 447 418 1321 420 451 414 454 422 449 416 1322 419 1319 422 449 416 1322 419 451 424 445 420 449 416 455 421 445 420 449 416 455 420 448 417 452 424 446 419 1321 420 1317 424 1315 416 1324 417 1322 419 1320 421 1320 421 446 419 1319 422 1319 422 1318 423 1313 417 453 423 445 420 450 415 454 421 449 416 454 422 446 419 449 416 456 420 448 417 453 423 444 421 450 415 454 422 447 418 451 424 445 420 450 415 455 420 447 418 452 424 447 418 451 424 445 420 448 417 453 423 446 419 451 424 444 421 448 417 452 423 446 419 451 424 445 420 448 417 451 414 456 420 452 424 443 422 449 416 451 424 448 417 449 416 455 420 1318 423 446 419 1319 422 448 417 451 424 447 418 1320 421 1316 415 455 421 451 414 455 421 449 416 451 424 446 419 1319 422 448 417 454 422 446 419 451 414 1325 416 452 423 447 418 451 424 447 418 1318 423 446 419 449 416 1327 424 1312 419 449 416 455 421 449 416 +# OFF +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 645 17766 3059 8884 533 461 557 1427 560 435 584 433 534 458 534 458 534 458 588 404 587 405 586 1399 586 407 584 408 558 1429 555 1457 502 491 525 1460 528 1458 554 1431 554 1431 555 1431 554 438 555 438 554 439 553 440 553 464 528 464 528 464 529 465 528 465 526 467 526 467 527 465 553 439 554 439 554 438 554 439 554 439 553 439 554 439 553 439 553 439 554 440 552 464 528 464 528 465 528 466 527 466 501 492 525 468 526 466 527 466 553 439 554 439 553 440 552 1433 553 1433 553 2936 3024 8893 552 1458 527 465 528 465 527 467 526 467 500 493 524 468 526 467 526 467 552 1434 552 441 552 441 552 1435 550 465 528 1458 527 1458 528 1459 527 1485 501 1485 500 1486 501 491 527 466 528 465 528 465 527 465 528 465 527 465 528 465 528 465 527 465 528 465 527 466 527 466 527 492 500 492 501 492 500 493 500 493 500 492 526 466 527 465 527 465 527 465 527 466 527 466 527 466 527 465 527 466 526 466 527 466 526 467 526 493 499 493 474 518 499 494 500 493 526 2936 3025 8918 526 1459 527 466 527 466 527 466 526 466 527 466 526 467 526 467 525 467 526 1460 525 493 499 493 498 495 498 495 499 493 500 493 525 1460 527 1460 525 1460 526 1460 525 1460 526 1460 526 468 525 1487 499 1487 497 495 498 495 499 493 500 1486 525 1460 525 1460 525 467 525 467 526 467 525 467 526 468 524 1462 524 468 524 494 498 1488 497 1488 499 494 499 493 525 468 525 1461 524 468 525 468 524 468 525 468 525 468 524 468 525 469 524 494 498 494 499 1488 473 1514 524 From bf0e8534132794962a21e54b734567704166d175 Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Tue, 2 May 2023 20:53:25 +0100 Subject: [PATCH 05/30] Updated audio.ir Updated last checked, no new additions --- assets/resources/infrared/assets/audio.ir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index f6183ed861..ce6d0a7aa7 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 # Last Updated 14th Apr, 2023 -# Last Checked 25th Apr, 2023 +# Last Checked 2nd May, 2023 # name: POWER type: parsed From 7ba96ad653197f9f98c367f829b67f0471657d0e Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Tue, 2 May 2023 20:53:48 +0100 Subject: [PATCH 06/30] Updated fans.ir New additions --- assets/resources/infrared/assets/fans.ir | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/assets/resources/infrared/assets/fans.ir b/assets/resources/infrared/assets/fans.ir index 6bef11b347..e422bdce4b 100644 --- a/assets/resources/infrared/assets/fans.ir +++ b/assets/resources/infrared/assets/fans.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 14th Apr, 2023 -# Last Checked 25th Apr, 2023 +# Last Updated 2nd May, 2023 +# Last Checked 2nd May, 2023 # name: POWER type: raw @@ -1497,3 +1497,9 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 3534 3439 954 2505 985 2535 955 798 954 2535 899 2591 899 2599 899 853 925 2566 924 2567 922 2596 894 2596 894 867 894 859 894 860 893 2597 894 859 894 859 894 867 894 2597 893 859 894 859 894 860 893 859 894 2605 894 40336 3531 3469 894 2597 893 2597 893 859 894 2597 893 2597 893 2605 893 860 893 2597 893 2597 893 2597 894 2597 893 868 893 860 893 860 893 2597 893 860 893 860 893 868 893 2597 893 860 893 860 893 860 893 860 893 2605 893 +# +name: POWER +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 1A 00 00 00 From 79566b7fa31a1cef5465b4f5ffc1369cb40dd36b Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Tue, 2 May 2023 20:54:15 +0100 Subject: [PATCH 07/30] Updated projectors.ir New additions --- .../resources/infrared/assets/projectors.ir | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/assets/resources/infrared/assets/projectors.ir b/assets/resources/infrared/assets/projectors.ir index 00e331bd49..8e81a25bd0 100644 --- a/assets/resources/infrared/assets/projectors.ir +++ b/assets/resources/infrared/assets/projectors.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 14th Apr, 2023 -# Last Checked 25th Apr, 2023 +# Last Updated 2nd May, 2023 +# Last Checked 2nd May, 2023 # # ON name: POWER @@ -886,3 +886,27 @@ type: parsed protocol: NECext address: 84 F4 00 00 command: 2F D0 00 00 +# +name: MUTE +type: parsed +protocol: NECext +address: 4F 50 00 00 +command: 0F F0 00 00 +# +name: POWER +type: parsed +protocol: NEC +address: 02 00 00 00 +command: 12 00 00 00 +# +name: VOL- +type: parsed +protocol: NEC +address: 02 00 00 00 +command: 06 00 00 00 +# +name: VOL+ +type: parsed +protocol: NEC +address: 02 00 00 00 +command: 00 00 00 00 From dd6c031a3186dda25f92c5ea27a8053bb5a36451 Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Tue, 2 May 2023 21:00:24 +0100 Subject: [PATCH 08/30] Updated tv.ir New additions, Added full sharp tv support. Reverted Vizio raw data change, will add this if needed --- assets/resources/infrared/assets/tv.ir | 64 ++++++++++++++++++++------ 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index bd246f3d6f..8c781eea9f 100755 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 2, May, 2023 -# Last Checked 2, May, 2023 +# Last Updated 2nd May, 2023 +# Last Checked 2nd May, 2023 # name: POWER type: parsed @@ -1899,39 +1899,77 @@ type: parsed protocol: SIRC20 address: 10 01 00 00 command: 33 00 00 00 +# +# Sharp TV +# +name: POWER +type: parsed +protocol: NECext +address: 00 BD 00 00 +command: 01 FE 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: 00 BD 00 00 +command: 0C F3 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 00 BD 00 00 +command: 10 EF 00 00 +# +name: CH+ +type: parsed +protocol: NECext +address: 00 BD 00 00 +command: 18 E7 00 00 +# +name: CH- +type: parsed +protocol: NECext +address: 00 BD 00 00 +command: 1C E3 00 00 # +name: MUTE +type: parsed +protocol: NECext +address: 00 BD 00 00 +command: 04 FB 00 00 +# name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 -data: 195 1833 300 766 280 760 275 790 276 737 309 731 304 1801 301 1804 309 731 304 1801 270 795 282 758 277 762 273 1832 270 769 246 45851 326 1780 302 739 307 785 282 732 303 736 310 1795 307 732 303 763 303 1775 307 733 334 1798 273 1832 270 1810 251 814 273 1780 281 43762 302 1804 309 758 277 737 330 762 284 730 305 734 301 1803 310 1796 306 733 302 1829 273 767 279 734 301 791 275 1804 278 762 253 45870 307 1798 304 763 272 767 279 787 279 760 275 1829 284 730 305 734 301 1804 309 757 278 1827 275 1804 278 1828 274 765 270 1835 278 43740 303 1776 306 787 279 760 275 765 281 759 307 758 277 1775 307 1799 303 736 299 1832 281 759 276 763 304 736 299 1832 281 733 302 45820 306 1800 302 764 282 758 277 788 278 762 284 1821 281 732 303 736 310 1796 307 733 302 1829 273 1806 276 1830 272 767 268 1837 245 43772 302 1778 304 789 277 762 284 756 279 786 249 765 301 1777 336 1770 301 764 282 1824 278 761 274 765 301 738 308 1824 278 761 274 +data: 278 1811 277 788 246 794 250 764 280 786 248 792 252 1813 275 1815 273 791 253 1812 276 789 255 785 249 791 253 1812 276 789 255 45322 280 1809 279 786 248 766 278 788 246 794 250 1815 273 792 252 788 246 1819 280 785 249 1817 271 1819 280 1810 278 787 247 1818 281 43217 274 1818 270 794 250 764 280 786 248 792 252 788 256 1809 279 1811 277 788 246 1819 280 785 249 766 278 762 272 1819 280 785 248 # name: MUTE type: raw frequency: 38000 duty_cycle: 0.330000 -data: 254 1721 360 681 354 738 308 706 329 711 355 1774 307 1772 361 1744 327 687 359 1772 299 742 335 705 330 736 279 1825 298 742 283 44773 384 1721 360 707 308 707 359 733 302 711 335 705 361 704 331 708 338 1766 336 704 331 1773 329 1776 306 1773 360 681 323 1782 331 44726 411 1722 328 686 360 733 302 711 335 705 361 1742 329 1803 330 1749 332 708 327 1777 335 705 330 710 325 741 274 1830 303 737 278 44778 359 1747 355 712 303 711 355 711 335 705 330 709 337 703 363 703 332 1770 332 709 337 1767 335 1771 300 1752 360 733 302 1776 326 44731 355 1751 330 711 355 737 309 705 330 710 336 1793 309 1771 331 1774 307 706 360 1771 300 740 326 714 332 735 280 1798 325 741 274 +data: 278 1812 276 762 282 758 276 765 279 761 273 1818 281 1809 279 1811 277 762 282 1809 279 760 274 766 278 762 282 1809 279 760 274 44279 276 1813 275 763 281 759 275 766 278 762 272 768 276 764 280 760 274 1817 271 768 276 1815 273 1817 271 1819 280 759 275 1816 272 44276 279 1812 276 763 281 758 276 765 279 761 273 1818 281 1810 278 1811 277 762 272 1819 279 760 274 766 278 762 282 1809 279 760 274 # -name: POWER +name: VOL+ type: raw frequency: 38000 duty_cycle: 0.330000 -data: 9219 4484 662 469 661 469 661 1627 660 471 658 474 656 499 631 499 631 499 631 1657 630 1657 631 500 630 1657 631 1657 631 1657 630 1657 631 1657 631 500 630 500 630 500 630 1657 630 500 631 500 630 500 631 500 630 1657 630 1658 630 1657 631 500 630 1657 631 1658 630 1658 630 1658 630 40107 9106 2202 631 +data: 272 1817 271 794 250 790 254 786 248 792 252 762 272 794 250 1815 273 792 252 1813 275 790 254 785 249 766 278 1813 275 789 255 46372 273 1817 271 794 250 763 281 785 248 792 252 1813 275 1814 274 791 253 1812 276 789 255 1810 278 1812 276 1813 275 790 254 1811 277 42170 277 1814 274 791 253 787 247 793 251 763 281 759 275 791 253 1812 276 789 255 1810 278 787 247 793 251 789 255 1810 278 787 247 # -name: VOL+ +name: VOL- type: raw frequency: 38000 duty_cycle: 0.330000 -data: 9218 4484 636 495 660 469 661 1627 660 471 658 472 658 474 656 475 655 474 656 1632 655 1632 656 474 657 1632 656 1631 657 1632 656 1631 656 1632 656 474 656 1632 655 475 656 474 657 474 656 474 656 474 656 474 656 1632 655 474 656 1632 656 1632 656 1632 656 1632 656 1632 656 1632 656 40103 9107 2177 655 -# -name: VOL- +data: 275 1814 274 791 253 787 247 793 251 789 255 1810 278 787 247 1818 281 785 249 1816 272 793 251 789 255 785 249 1816 272 766 278 45325 274 1815 273 792 252 762 272 794 250 790 254 786 247 1818 270 794 250 1815 273 792 252 1813 275 1815 273 1816 272 793 251 1814 274 43224 277 1814 274 764 280 786 248 792 252 788 246 1820 279 786 247 1817 271 768 276 1815 273 792 252 761 273 794 250 1815 273 791 253 +# +name: CH+ type: raw frequency: 38000 duty_cycle: 0.330000 -data: 9245 4429 689 467 662 468 661 1626 660 471 658 473 657 474 656 474 656 474 656 1631 657 1631 657 474 656 1631 656 1632 656 1631 657 1631 657 1631 656 1632 656 1631 657 474 656 474 656 474 657 474 656 474 656 474 657 474 656 474 656 1631 656 1632 656 1632 656 1632 656 1632 656 1631 656 40082 9109 2175 656 +data: 272 1817 271 794 250 790 254 786 248 792 252 1813 275 790 254 759 275 792 252 1813 275 789 255 785 248 792 252 1813 275 789 255 46372 273 1817 271 793 251 763 281 759 275 791 253 787 247 1818 281 1810 278 1812 276 789 255 1809 279 1811 277 1813 275 790 254 1811 277 42169 277 1815 273 792 252 787 247 794 250 789 255 1810 278 787 247 794 250 789 255 1810 278 761 273 793 251 789 255 1810 278 787 247 # -name: MUTE +name: CH- type: raw frequency: 38000 duty_cycle: 0.330000 -data: 9219 4485 636 495 660 469 661 1626 661 471 658 473 657 474 656 499 631 500 630 1657 630 1657 631 500 630 1657 630 1657 631 1657 631 1657 630 1657 631 1657 631 500 630 500 630 1657 631 500 630 500 630 500 630 500 631 500 630 1657 631 1657 631 500 630 1657 631 1658 630 1657 631 1658 630 39868 9106 2178 655 +data: 273 1816 272 767 277 789 255 785 249 791 253 787 246 1818 281 785 248 765 279 1812 276 789 255 759 275 791 253 1812 276 789 255 46372 281 1808 280 785 249 791 253 787 247 793 251 1814 274 791 253 1812 276 1814 274 791 253 1812 276 1814 274 1815 273 792 252 1813 275 42172 272 1819 280 785 249 765 279 761 273 768 276 764 280 1811 277 788 246 768 276 1815 273 792 252 788 246 794 250 1815 273 791 253 From 238005890ec6a619157ac75eb60bd02dfe6c736e Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Wed, 3 May 2023 00:56:25 +0300 Subject: [PATCH 09/30] [FL-3294] Fix TERMINFO on Linux systems (#2630) * Fix TERMINFO on Linux systems * Set TERMINFO_DIRS only on Linux * Unset TERMINFO_DIRS if it was not set before --- scripts/toolchain/fbtenv.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index 57a50281ed..143dce74b9 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -56,6 +56,16 @@ fbtenv_restore_env() unset SSL_CERT_FILE; unset REQUESTS_CA_BUNDLE; fi + + if [ "$SYS_TYPE" = "Linux" ]; then + if [ -n "$SAVED_TERMINFO_DIRS" ]; then + export TERMINFO_DIRS="$SAVED_TERMINFO_DIRS"; + else + unset TERMINFO_DIRS; + fi + unset SAVED_TERMINFO_DIRS; + fi + export PYTHONNOUSERSITE="$SAVED_PYTHONNOUSERSITE"; export PYTHONPATH="$SAVED_PYTHONPATH"; export PYTHONHOME="$SAVED_PYTHONHOME"; @@ -325,6 +335,11 @@ fbtenv_main() export PYTHONNOUSERSITE=1; export PYTHONPATH=; export PYTHONHOME=; + + if [ "$SYS_TYPE" = "Linux" ]; then + export SAVED_TERMINFO_DIRS="${TERMINFO_DIRS:-""}"; + export TERMINFO_DIRS="$TOOLCHAIN_ARCH_DIR/ncurses/share/terminfo"; + fi } fbtenv_main "${1:-""}"; From 23c946ef50e07950199637776d2f520351ee7ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Wed, 3 May 2023 11:08:41 +0900 Subject: [PATCH 10/30] Move gauge calibration to separate header, add f18 calibration (#2622) --- firmware/targets/f18/api_symbols.csv | 1 + .../f18/furi_hal/furi_hal_power_calibration.h | 37 ++++++++++++++++++ firmware/targets/f7/api_symbols.csv | 1 + firmware/targets/f7/furi_hal/furi_hal_power.c | 38 +------------------ .../f7/furi_hal/furi_hal_power_calibration.h | 37 ++++++++++++++++++ 5 files changed, 77 insertions(+), 37 deletions(-) create mode 100644 firmware/targets/f18/furi_hal/furi_hal_power_calibration.h create mode 100644 firmware/targets/f7/furi_hal/furi_hal_power_calibration.h diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index eb2d6f43fa..25f36ca025 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -36,6 +36,7 @@ Header,+,applications/services/notification/notification_messages.h,, Header,+,applications/services/power/power_service/power.h,, Header,+,applications/services/rpc/rpc_app.h,, Header,+,applications/services/storage/storage.h,, +Header,-,firmware/targets/f18/furi_hal/furi_hal_power_calibration.h,, Header,+,firmware/targets/f18/furi_hal/furi_hal_resources.h,, Header,+,firmware/targets/f18/furi_hal/furi_hal_spi_config.h,, Header,+,firmware/targets/f18/furi_hal/furi_hal_target_hw.h,, diff --git a/firmware/targets/f18/furi_hal/furi_hal_power_calibration.h b/firmware/targets/f18/furi_hal/furi_hal_power_calibration.h new file mode 100644 index 0000000000..e97e1657db --- /dev/null +++ b/firmware/targets/f18/furi_hal/furi_hal_power_calibration.h @@ -0,0 +1,37 @@ +const ParamCEDV cedv = { + .cedv_conf.gauge_conf = + { + .CCT = 1, + .CSYNC = 0, + .EDV_CMP = 0, + .SC = 1, + .FIXED_EDV0 = 1, + .FCC_LIM = 1, + .FC_FOR_VDQ = 1, + .IGNORE_SD = 1, + .SME0 = 0, + }, + .full_charge_cap = 1300, + .design_cap = 1300, + .EDV0 = 3300, + .EDV1 = 3321, + .EDV2 = 3355, + .EMF = 3679, + .C0 = 430, + .C1 = 0, + .R1 = 408, + .R0 = 334, + .T0 = 4626, + .TC = 11, + .DOD0 = 4044, + .DOD10 = 3905, + .DOD20 = 3807, + .DOD30 = 3718, + .DOD40 = 3642, + .DOD50 = 3585, + .DOD60 = 3546, + .DOD70 = 3514, + .DOD80 = 3477, + .DOD90 = 3411, + .DOD100 = 3299, +}; diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index d0c6b36ad5..951e92aae1 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -47,6 +47,7 @@ Header,+,firmware/targets/f7/furi_hal/furi_hal_idle_timer.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_interrupt.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_nfc.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_os.h,, +Header,-,firmware/targets/f7/furi_hal/furi_hal_power_calibration.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_pwm.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_resources.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_rfid.h,, diff --git a/firmware/targets/f7/furi_hal/furi_hal_power.c b/firmware/targets/f7/furi_hal/furi_hal_power.c index e380de7fa5..ec405f1080 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_power.c +++ b/firmware/targets/f7/furi_hal/furi_hal_power.c @@ -46,43 +46,7 @@ static volatile FuriHalPower furi_hal_power = { .suppress_charge = 0, }; -const ParamCEDV cedv = { - .cedv_conf.gauge_conf = - { - .CCT = 1, - .CSYNC = 0, - .EDV_CMP = 0, - .SC = 1, - .FIXED_EDV0 = 1, - .FCC_LIM = 1, - .FC_FOR_VDQ = 1, - .IGNORE_SD = 1, - .SME0 = 0, - }, - .full_charge_cap = 2101, - .design_cap = 2101, - .EDV0 = 3300, - .EDV1 = 3321, - .EDV2 = 3355, - .EMF = 3679, - .C0 = 430, - .C1 = 0, - .R1 = 408, - .R0 = 334, - .T0 = 4626, - .TC = 11, - .DOD0 = 4044, - .DOD10 = 3905, - .DOD20 = 3807, - .DOD30 = 3718, - .DOD40 = 3642, - .DOD50 = 3585, - .DOD60 = 3546, - .DOD70 = 3514, - .DOD80 = 3477, - .DOD90 = 3411, - .DOD100 = 3299, -}; +#include void furi_hal_power_init() { #ifdef FURI_HAL_POWER_DEBUG diff --git a/firmware/targets/f7/furi_hal/furi_hal_power_calibration.h b/firmware/targets/f7/furi_hal/furi_hal_power_calibration.h new file mode 100644 index 0000000000..5eb0f938b2 --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_power_calibration.h @@ -0,0 +1,37 @@ +const ParamCEDV cedv = { + .cedv_conf.gauge_conf = + { + .CCT = 1, + .CSYNC = 0, + .EDV_CMP = 0, + .SC = 1, + .FIXED_EDV0 = 1, + .FCC_LIM = 1, + .FC_FOR_VDQ = 1, + .IGNORE_SD = 1, + .SME0 = 0, + }, + .full_charge_cap = 2101, + .design_cap = 2101, + .EDV0 = 3300, + .EDV1 = 3321, + .EDV2 = 3355, + .EMF = 3679, + .C0 = 430, + .C1 = 0, + .R1 = 408, + .R0 = 334, + .T0 = 4626, + .TC = 11, + .DOD0 = 4044, + .DOD10 = 3905, + .DOD20 = 3807, + .DOD30 = 3718, + .DOD40 = 3642, + .DOD50 = 3585, + .DOD60 = 3546, + .DOD70 = 3514, + .DOD80 = 3477, + .DOD90 = 3411, + .DOD100 = 3299, +}; From 5c09bc5b2d25da5fa6fc71e82eb316ed9db87c1f Mon Sep 17 00:00:00 2001 From: Lewis Westbury Date: Wed, 3 May 2023 04:33:30 +0100 Subject: [PATCH 11/30] Gui: relax some asserts in view (#2623) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove assertion preventing replacement of view input callback * Gui: relax some asserts in view Co-authored-by: あく --- applications/services/gui/view.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/applications/services/gui/view.c b/applications/services/gui/view.c index 4d84cac507..07ae072a17 100644 --- a/applications/services/gui/view.c +++ b/applications/services/gui/view.c @@ -19,19 +19,16 @@ void view_tie_icon_animation(View* view, IconAnimation* icon_animation) { void view_set_draw_callback(View* view, ViewDrawCallback callback) { furi_assert(view); - furi_assert(view->draw_callback == NULL); view->draw_callback = callback; } void view_set_input_callback(View* view, ViewInputCallback callback) { furi_assert(view); - furi_assert(view->input_callback == NULL); view->input_callback = callback; } void view_set_custom_callback(View* view, ViewCustomCallback callback) { furi_assert(view); - furi_assert(callback); view->custom_callback = callback; } @@ -62,7 +59,6 @@ void view_set_update_callback_context(View* view, void* context) { void view_set_context(View* view, void* context) { furi_assert(view); - furi_assert(context); view->context = context; } From c5b460b416e24fa887ec93672e56b71109c91a79 Mon Sep 17 00:00:00 2001 From: hedger Date: Wed, 3 May 2023 06:58:59 +0300 Subject: [PATCH 12/30] [FL-3260] Added API version to device info (#2611) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * hal: device_info: added API version to "firmware.api.major" & "firmware.api.minor" * FuriHal: bump device info version Co-authored-by: あく --- .../loader/firmware_api/firmware_api.cpp | 7 +++++++ firmware/targets/f18/api_symbols.csv | 3 ++- firmware/targets/f7/api_symbols.csv | 3 ++- firmware/targets/f7/furi_hal/furi_hal_info.c | 16 ++++++++++++++-- .../targets/furi_hal_include/furi_hal_info.h | 2 ++ furi/core/common_defines.h | 4 ++++ 6 files changed, 31 insertions(+), 4 deletions(-) diff --git a/applications/services/loader/firmware_api/firmware_api.cpp b/applications/services/loader/firmware_api/firmware_api.cpp index 52e86efc26..6651bf1124 100644 --- a/applications/services/loader/firmware_api/firmware_api.cpp +++ b/applications/services/loader/firmware_api/firmware_api.cpp @@ -6,6 +6,8 @@ /* Generated table */ #include +#include + static_assert(!has_hash_collisions(elf_api_table), "Detected API method hash collision!"); constexpr HashtableApiInterface elf_api_interface{ @@ -19,3 +21,8 @@ constexpr HashtableApiInterface elf_api_interface{ }; const ElfApiInterface* const firmware_api_interface = &elf_api_interface; + +extern "C" void furi_hal_info_get_api_version(uint16_t* major, uint16_t* minor) { + *major = elf_api_interface.api_version_major; + *minor = elf_api_interface.api_version_minor; +} \ No newline at end of file diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index 25f36ca025..bdd5d6b61f 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.0,, +Version,+,23.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -960,6 +960,7 @@ Function,+,furi_hal_i2c_write_mem,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, Function,+,furi_hal_i2c_write_reg_16,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint16_t, uint32_t" Function,+,furi_hal_i2c_write_reg_8,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t, uint32_t" Function,+,furi_hal_info_get,void,"PropertyValueCallback, char, void*" +Function,+,furi_hal_info_get_api_version,void,"uint16_t*, uint16_t*" Function,-,furi_hal_init,void, Function,-,furi_hal_init_early,void, Function,-,furi_hal_interrupt_init,void, diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 951e92aae1..9f4ec4261c 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.0,, +Version,+,23.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1148,6 +1148,7 @@ Function,+,furi_hal_ibutton_pin_configure,void, Function,+,furi_hal_ibutton_pin_reset,void, Function,+,furi_hal_ibutton_pin_write,void,const _Bool Function,+,furi_hal_info_get,void,"PropertyValueCallback, char, void*" +Function,+,furi_hal_info_get_api_version,void,"uint16_t*, uint16_t*" Function,+,furi_hal_infrared_async_rx_set_capture_isr_callback,void,"FuriHalInfraredRxCaptureCallback, void*" Function,+,furi_hal_infrared_async_rx_set_timeout,void,uint32_t Function,+,furi_hal_infrared_async_rx_set_timeout_isr_callback,void,"FuriHalInfraredRxTimeoutCallback, void*" diff --git a/firmware/targets/f7/furi_hal/furi_hal_info.c b/firmware/targets/f7/furi_hal/furi_hal_info.c index c984ef4d56..4c034ff352 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_info.c +++ b/firmware/targets/f7/furi_hal/furi_hal_info.c @@ -8,6 +8,11 @@ #include #include +FURI_WEAK void furi_hal_info_get_api_version(uint16_t* major, uint16_t* minor) { + *major = 0; + *minor = 0; +} + void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) { FuriString* key = furi_string_alloc(); FuriString* value = furi_string_alloc(); @@ -18,10 +23,10 @@ void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) { // Device Info version if(sep == '.') { property_value_out(&property_context, NULL, 2, "format", "major", "3"); - property_value_out(&property_context, NULL, 2, "format", "minor", "0"); + property_value_out(&property_context, NULL, 2, "format", "minor", "1"); } else { property_value_out(&property_context, NULL, 3, "device", "info", "major", "2"); - property_value_out(&property_context, NULL, 3, "device", "info", "minor", "0"); + property_value_out(&property_context, NULL, 3, "device", "info", "minor", "1"); } // Model name @@ -161,6 +166,13 @@ void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) { version_get_builddate(firmware_version)); property_value_out( &property_context, "%d", 2, "firmware", "target", version_get_target(firmware_version)); + + uint16_t api_version_major, api_version_minor; + furi_hal_info_get_api_version(&api_version_major, &api_version_minor); + property_value_out( + &property_context, "%d", 3, "firmware", "api", "major", api_version_major); + property_value_out( + &property_context, "%d", 3, "firmware", "api", "minor", api_version_minor); } if(furi_hal_bt_is_alive()) { diff --git a/firmware/targets/furi_hal_include/furi_hal_info.h b/firmware/targets/furi_hal_include/furi_hal_info.h index fa3267f5d4..7e8b0e1fb1 100644 --- a/firmware/targets/furi_hal_include/furi_hal_info.h +++ b/firmware/targets/furi_hal_include/furi_hal_info.h @@ -14,6 +14,8 @@ extern "C" { #endif +void furi_hal_info_get_api_version(uint16_t* major, uint16_t* minor); + /** Get device information * * @param[in] callback callback to provide with new data diff --git a/furi/core/common_defines.h b/furi/core/common_defines.h index 1ec847d459..d7bfaf2076 100644 --- a/furi/core/common_defines.h +++ b/furi/core/common_defines.h @@ -15,6 +15,10 @@ extern "C" { #define FURI_WARN_UNUSED __attribute__((warn_unused_result)) #endif +#ifndef FURI_WEAK +#define FURI_WEAK __attribute__((weak)) +#endif + #ifndef FURI_IS_IRQ_MASKED #define FURI_IS_IRQ_MASKED() (__get_PRIMASK() != 0U) #endif From dfbacd1a4753d64d76b1ac85da8f5bc9a46ecbd5 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Tue, 2 May 2023 21:05:24 -0700 Subject: [PATCH 13/30] [#2612] Remove spaces in CSN(#2616) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../external/picopass/scenes/picopass_scene_read_card_success.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/external/picopass/scenes/picopass_scene_read_card_success.c b/applications/external/picopass/scenes/picopass_scene_read_card_success.c index 198b21d986..cc18ac066a 100644 --- a/applications/external/picopass/scenes/picopass_scene_read_card_success.c +++ b/applications/external/picopass/scenes/picopass_scene_read_card_success.c @@ -34,7 +34,7 @@ void picopass_scene_read_card_success_on_enter(void* context) { uint8_t csn[PICOPASS_BLOCK_LEN] = {0}; memcpy(csn, AA1[PICOPASS_CSN_BLOCK_INDEX].data, PICOPASS_BLOCK_LEN); for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) { - furi_string_cat_printf(csn_str, "%02X ", csn[i]); + furi_string_cat_printf(csn_str, "%02X", csn[i]); } bool no_key = picopass_is_memset(pacs->key, 0x00, PICOPASS_BLOCK_LEN); From 59386f9fa9e8b3f9b03823c99405484dddaec071 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Wed, 3 May 2023 08:15:47 +0400 Subject: [PATCH 14/30] WS: add protocol "Wendox W6726" (#2604) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * WS: add protocol "Wendox" * WS: add bat status * WS: add CRC, refactoring * WS: description added * WS: fix name file * WeatherStation: cleanup alien symbols Co-authored-by: あく --- .../protocols/protocol_items.c | 1 + .../protocols/protocol_items.h | 1 + .../weather_station/protocols/wendox_w6726.c | 299 ++++++++++++++++++ .../weather_station/protocols/wendox_w6726.h | 80 +++++ 4 files changed, 381 insertions(+) create mode 100644 applications/external/weather_station/protocols/wendox_w6726.c create mode 100644 applications/external/weather_station/protocols/wendox_w6726.h diff --git a/applications/external/weather_station/protocols/protocol_items.c b/applications/external/weather_station/protocols/protocol_items.c index 2c9d751c7e..cd4bae76dc 100644 --- a/applications/external/weather_station/protocols/protocol_items.c +++ b/applications/external/weather_station/protocols/protocol_items.c @@ -16,6 +16,7 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = { &ws_protocol_auriol_th, &ws_protocol_oregon_v1, &ws_protocol_tx_8300, + &ws_protocol_wendox_w6726, }; const SubGhzProtocolRegistry weather_station_protocol_registry = { diff --git a/applications/external/weather_station/protocols/protocol_items.h b/applications/external/weather_station/protocols/protocol_items.h index f9e443abcf..0398c11f25 100644 --- a/applications/external/weather_station/protocols/protocol_items.h +++ b/applications/external/weather_station/protocols/protocol_items.h @@ -16,5 +16,6 @@ #include "auriol_hg0601a.h" #include "oregon_v1.h" #include "tx_8300.h" +#include "wendox_w6726.h" extern const SubGhzProtocolRegistry weather_station_protocol_registry; diff --git a/applications/external/weather_station/protocols/wendox_w6726.c b/applications/external/weather_station/protocols/wendox_w6726.c new file mode 100644 index 0000000000..2fbe961f72 --- /dev/null +++ b/applications/external/weather_station/protocols/wendox_w6726.c @@ -0,0 +1,299 @@ +#include "wendox_w6726.h" + +#define TAG "WSProtocolWendoxW6726" + +/* + * Wendox W6726 + * + * Temperature -50C to +70C + * _ _ _ __ _ + * _| |___| |___| |___ ... | |_| |__...._______________ + * preamble data guard time + * + * 3 reps every 3 minutes + * in the first message 11 bytes of the preamble in the rest by 7 + * + * bit 0: 1955-hi, 5865-lo + * bit 1: 5865-hi, 1955-lo + * guard time: 12*1955+(lo last bit) + * data: 29 bit + * + * IIIII | ZTTTTTTTTT | uuuuuuuBuu | CCCC + * + * I: identification; + * Z: temperature sign; + * T: temperature sign dependent +12C; + * B: battery low; flag to indicate low battery voltage; + * C: CRC4 (polynomial = 0x9, start_data = 0xD); + * u: unknown; + */ + +static const SubGhzBlockConst ws_protocol_wendox_w6726_const = { + .te_short = 1955, + .te_long = 5865, + .te_delta = 300, + .min_count_bit_for_found = 29, +}; + +struct WSProtocolDecoderWendoxW6726 { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + WSBlockGeneric generic; + + uint16_t header_count; +}; + +struct WSProtocolEncoderWendoxW6726 { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + WSBlockGeneric generic; +}; + +typedef enum { + WendoxW6726DecoderStepReset = 0, + WendoxW6726DecoderStepCheckPreambule, + WendoxW6726DecoderStepSaveDuration, + WendoxW6726DecoderStepCheckDuration, +} WendoxW6726DecoderStep; + +const SubGhzProtocolDecoder ws_protocol_wendox_w6726_decoder = { + .alloc = ws_protocol_decoder_wendox_w6726_alloc, + .free = ws_protocol_decoder_wendox_w6726_free, + + .feed = ws_protocol_decoder_wendox_w6726_feed, + .reset = ws_protocol_decoder_wendox_w6726_reset, + + .get_hash_data = ws_protocol_decoder_wendox_w6726_get_hash_data, + .serialize = ws_protocol_decoder_wendox_w6726_serialize, + .deserialize = ws_protocol_decoder_wendox_w6726_deserialize, + .get_string = ws_protocol_decoder_wendox_w6726_get_string, +}; + +const SubGhzProtocolEncoder ws_protocol_wendox_w6726_encoder = { + .alloc = NULL, + .free = NULL, + + .deserialize = NULL, + .stop = NULL, + .yield = NULL, +}; + +const SubGhzProtocol ws_protocol_wendox_w6726 = { + .name = WS_PROTOCOL_WENDOX_W6726_NAME, + .type = SubGhzProtocolWeatherStation, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 | + SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable, + + .decoder = &ws_protocol_wendox_w6726_decoder, + .encoder = &ws_protocol_wendox_w6726_encoder, +}; + +void* ws_protocol_decoder_wendox_w6726_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + WSProtocolDecoderWendoxW6726* instance = malloc(sizeof(WSProtocolDecoderWendoxW6726)); + instance->base.protocol = &ws_protocol_wendox_w6726; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void ws_protocol_decoder_wendox_w6726_free(void* context) { + furi_assert(context); + WSProtocolDecoderWendoxW6726* instance = context; + free(instance); +} + +void ws_protocol_decoder_wendox_w6726_reset(void* context) { + furi_assert(context); + WSProtocolDecoderWendoxW6726* instance = context; + instance->decoder.parser_step = WendoxW6726DecoderStepReset; +} + +static bool ws_protocol_wendox_w6726_check(WSProtocolDecoderWendoxW6726* instance) { + if(!instance->decoder.decode_data) return false; + uint8_t msg[] = { + instance->decoder.decode_data >> 28, + instance->decoder.decode_data >> 20, + instance->decoder.decode_data >> 12, + instance->decoder.decode_data >> 4}; + + uint8_t crc = subghz_protocol_blocks_crc4(msg, 4, 0x9, 0xD); + return (crc == (instance->decoder.decode_data & 0x0F)); +} + +/** + * Analysis of received data + * @param instance Pointer to a WSBlockGeneric* instance + */ +static void ws_protocol_wendox_w6726_remote_controller(WSBlockGeneric* instance) { + instance->id = (instance->data >> 24) & 0xFF; + instance->battery_low = (instance->data >> 6) & 1; + instance->channel = WS_NO_CHANNEL; + + if(((instance->data >> 23) & 1)) { + instance->temp = (float)(((instance->data >> 14) & 0x1FF) + 12) / 10.0f; + } else { + instance->temp = (float)((~(instance->data >> 14) & 0x1FF) + 1 - 12) / -10.0f; + } + + if(instance->temp < -50.0f) { + instance->temp = -50.0f; + } else if(instance->temp > 70.0f) { + instance->temp = 70.0f; + } + + instance->btn = WS_NO_BTN; + instance->humidity = WS_NO_HUMIDITY; +} + +void ws_protocol_decoder_wendox_w6726_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + WSProtocolDecoderWendoxW6726* instance = context; + + switch(instance->decoder.parser_step) { + case WendoxW6726DecoderStepReset: + if((level) && (DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_short) < + ws_protocol_wendox_w6726_const.te_delta)) { + instance->decoder.parser_step = WendoxW6726DecoderStepCheckPreambule; + instance->decoder.te_last = duration; + instance->header_count = 0; + } + break; + + case WendoxW6726DecoderStepCheckPreambule: + if(level) { + instance->decoder.te_last = duration; + } else { + if((DURATION_DIFF(instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_short) < + ws_protocol_wendox_w6726_const.te_delta * 1) && + (DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_long) < + ws_protocol_wendox_w6726_const.te_delta * 2)) { + instance->header_count++; + } else if((instance->header_count > 4) && (instance->header_count < 12)) { + if((DURATION_DIFF( + instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_long) < + ws_protocol_wendox_w6726_const.te_delta * 2) && + (DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_short) < + ws_protocol_wendox_w6726_const.te_delta)) { + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration; + } else { + instance->decoder.parser_step = WendoxW6726DecoderStepReset; + } + + } else { + instance->decoder.parser_step = WendoxW6726DecoderStepReset; + } + } + break; + + case WendoxW6726DecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = WendoxW6726DecoderStepCheckDuration; + } else { + instance->decoder.parser_step = WendoxW6726DecoderStepReset; + } + break; + + case WendoxW6726DecoderStepCheckDuration: + if(!level) { + if(duration > + ws_protocol_wendox_w6726_const.te_short + ws_protocol_wendox_w6726_const.te_long) { + if(DURATION_DIFF( + instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_short) < + ws_protocol_wendox_w6726_const.te_delta) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration; + } else if( + DURATION_DIFF( + instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_long) < + ws_protocol_wendox_w6726_const.te_delta * 2) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration; + } else { + instance->decoder.parser_step = WendoxW6726DecoderStepReset; + } + if((instance->decoder.decode_count_bit == + ws_protocol_wendox_w6726_const.min_count_bit_for_found) && + ws_protocol_wendox_w6726_check(instance)) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + ws_protocol_wendox_w6726_remote_controller(&instance->generic); + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + + instance->decoder.parser_step = WendoxW6726DecoderStepReset; + } else if( + (DURATION_DIFF(instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_short) < + ws_protocol_wendox_w6726_const.te_delta) && + (DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_long) < + ws_protocol_wendox_w6726_const.te_delta * 3)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration; + } else if( + (DURATION_DIFF(instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_long) < + ws_protocol_wendox_w6726_const.te_delta * 2) && + (DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_short) < + ws_protocol_wendox_w6726_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration; + } else { + instance->decoder.parser_step = WendoxW6726DecoderStepReset; + } + } else { + instance->decoder.parser_step = WendoxW6726DecoderStepReset; + } + break; + } +} + +uint8_t ws_protocol_decoder_wendox_w6726_get_hash_data(void* context) { + furi_assert(context); + WSProtocolDecoderWendoxW6726* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +SubGhzProtocolStatus ws_protocol_decoder_wendox_w6726_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + WSProtocolDecoderWendoxW6726* instance = context; + return ws_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +SubGhzProtocolStatus + ws_protocol_decoder_wendox_w6726_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + WSProtocolDecoderWendoxW6726* instance = context; + return ws_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + ws_protocol_wendox_w6726_const.min_count_bit_for_found); +} + +void ws_protocol_decoder_wendox_w6726_get_string(void* context, FuriString* output) { + furi_assert(context); + WSProtocolDecoderWendoxW6726* instance = context; + furi_string_printf( + output, + "%s %dbit\r\n" + "Key:0x%lX%08lX\r\n" + "Sn:0x%lX Ch:%d Bat:%d\r\n" + "Temp:%3.1f C Hum:%d%%", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data >> 32), + (uint32_t)(instance->generic.data), + instance->generic.id, + instance->generic.channel, + instance->generic.battery_low, + (double)instance->generic.temp, + instance->generic.humidity); +} diff --git a/applications/external/weather_station/protocols/wendox_w6726.h b/applications/external/weather_station/protocols/wendox_w6726.h new file mode 100644 index 0000000000..236777a1c8 --- /dev/null +++ b/applications/external/weather_station/protocols/wendox_w6726.h @@ -0,0 +1,80 @@ +#pragma once + +#include + +#include +#include +#include +#include "ws_generic.h" +#include + +#define WS_PROTOCOL_WENDOX_W6726_NAME "Wendox W6726" + +typedef struct WSProtocolDecoderWendoxW6726 WSProtocolDecoderWendoxW6726; +typedef struct WSProtocolEncoderWendoxW6726 WSProtocolEncoderWendoxW6726; + +extern const SubGhzProtocolDecoder ws_protocol_wendox_w6726_decoder; +extern const SubGhzProtocolEncoder ws_protocol_wendox_w6726_encoder; +extern const SubGhzProtocol ws_protocol_wendox_w6726; + +/** + * Allocate WSProtocolDecoderWendoxW6726. + * @param environment Pointer to a SubGhzEnvironment instance + * @return WSProtocolDecoderWendoxW6726* pointer to a WSProtocolDecoderWendoxW6726 instance + */ +void* ws_protocol_decoder_wendox_w6726_alloc(SubGhzEnvironment* environment); + +/** + * Free WSProtocolDecoderWendoxW6726. + * @param context Pointer to a WSProtocolDecoderWendoxW6726 instance + */ +void ws_protocol_decoder_wendox_w6726_free(void* context); + +/** + * Reset decoder WSProtocolDecoderWendoxW6726. + * @param context Pointer to a WSProtocolDecoderWendoxW6726 instance + */ +void ws_protocol_decoder_wendox_w6726_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a WSProtocolDecoderWendoxW6726 instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void ws_protocol_decoder_wendox_w6726_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a WSProtocolDecoderWendoxW6726 instance + * @return hash Hash sum + */ +uint8_t ws_protocol_decoder_wendox_w6726_get_hash_data(void* context); + +/** + * Serialize data WSProtocolDecoderWendoxW6726. + * @param context Pointer to a WSProtocolDecoderWendoxW6726 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return status + */ +SubGhzProtocolStatus ws_protocol_decoder_wendox_w6726_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data WSProtocolDecoderWendoxW6726. + * @param context Pointer to a WSProtocolDecoderWendoxW6726 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ +SubGhzProtocolStatus + ws_protocol_decoder_wendox_w6726_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a WSProtocolDecoderWendoxW6726 instance + * @param output Resulting text + */ +void ws_protocol_decoder_wendox_w6726_get_string(void* context, FuriString* output); From 015ab4a0242c9c9c7ff182afd42b81cbecee758c Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Wed, 3 May 2023 07:39:14 +0300 Subject: [PATCH 15/30] [#2591] BadUSB: command parser fix (#2607) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../bad_usb/helpers/ducky_script_commands.c | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/applications/main/bad_usb/helpers/ducky_script_commands.c b/applications/main/bad_usb/helpers/ducky_script_commands.c index 1498c9a73f..d073b4c8d6 100644 --- a/applications/main/bad_usb/helpers/ducky_script_commands.c +++ b/applications/main/bad_usb/helpers/ducky_script_commands.c @@ -152,22 +152,22 @@ static int32_t ducky_fnc_waitforbutton(BadUsbScript* bad_usb, const char* line, } static const DuckyCmd ducky_commands[] = { - {"REM ", NULL, -1}, - {"ID ", NULL, -1}, - {"DELAY ", ducky_fnc_delay, -1}, - {"STRING ", ducky_fnc_string, 0}, - {"STRINGLN ", ducky_fnc_string, 1}, - {"DEFAULT_DELAY ", ducky_fnc_defdelay, -1}, - {"DEFAULTDELAY ", ducky_fnc_defdelay, -1}, - {"STRINGDELAY ", ducky_fnc_strdelay, -1}, - {"STRING_DELAY ", ducky_fnc_strdelay, -1}, - {"REPEAT ", ducky_fnc_repeat, -1}, - {"SYSRQ ", ducky_fnc_sysrq, -1}, - {"ALTCHAR ", ducky_fnc_altchar, -1}, - {"ALTSTRING ", ducky_fnc_altstring, -1}, - {"ALTCODE ", ducky_fnc_altstring, -1}, - {"HOLD ", ducky_fnc_hold, -1}, - {"RELEASE ", ducky_fnc_release, -1}, + {"REM", NULL, -1}, + {"ID", NULL, -1}, + {"DELAY", ducky_fnc_delay, -1}, + {"STRING", ducky_fnc_string, 0}, + {"STRINGLN", ducky_fnc_string, 1}, + {"DEFAULT_DELAY", ducky_fnc_defdelay, -1}, + {"DEFAULTDELAY", ducky_fnc_defdelay, -1}, + {"STRINGDELAY", ducky_fnc_strdelay, -1}, + {"STRING_DELAY", ducky_fnc_strdelay, -1}, + {"REPEAT", ducky_fnc_repeat, -1}, + {"SYSRQ", ducky_fnc_sysrq, -1}, + {"ALTCHAR", ducky_fnc_altchar, -1}, + {"ALTSTRING", ducky_fnc_altstring, -1}, + {"ALTCODE", ducky_fnc_altstring, -1}, + {"HOLD", ducky_fnc_hold, -1}, + {"RELEASE", ducky_fnc_release, -1}, {"WAIT_FOR_BUTTON_PRESS", ducky_fnc_waitforbutton, -1}, }; @@ -175,8 +175,15 @@ static const DuckyCmd ducky_commands[] = { #define WORKER_TAG TAG "Worker" int32_t ducky_execute_cmd(BadUsbScript* bad_usb, const char* line) { + size_t cmd_word_len = strcspn(line, " "); for(size_t i = 0; i < COUNT_OF(ducky_commands); i++) { - if(strncmp(line, ducky_commands[i].name, strlen(ducky_commands[i].name)) == 0) { + size_t cmd_compare_len = strlen(ducky_commands[i].name); + + if(cmd_compare_len != cmd_word_len) { + continue; + } + + if(strncmp(line, ducky_commands[i].name, cmd_compare_len) == 0) { if(ducky_commands[i].callback == NULL) { return 0; } else { From c3ececcf969576f2099fd45be80d5e4f213dc9b5 Mon Sep 17 00:00:00 2001 From: hedger Date: Wed, 3 May 2023 08:48:49 +0300 Subject: [PATCH 16/30] [FL-3174] Dolphin builder in ufbt; minor ufbt/fbt improvements (#2601) * ufbt: added "dolphin_ext" target (expects "external" subfolder in cwd with dolphin assets); cleaned up unused code * ufbt: codestyle fixes * scripts: fixed style according to ruff linter * scripts: additional cleanup & codestyle fixes * github: pass target hw code when installing local SDK with ufbt * ufbt: added error message for missing folder in dolphin builder * scripts: more linter fixes * sdk: added flipper_format_stream; ufbt: support for --extra-define * fbt: reduced amount of global defines * scripts, fbt: rearranged imports Co-authored-by: Aleksandr Kutuzov --- .github/workflows/build.yml | 2 + assets/SConscript | 4 +- firmware.scons | 4 +- firmware/targets/f18/api_symbols.csv | 8 +++- firmware/targets/f7/api_symbols.csv | 8 +++- lib/flipper_format/SConscript | 1 + lib/freertos.scons | 3 -- lib/libusb_stm32.scons | 8 ++-- lib/littlefs.scons | 8 ++-- lib/misc.scons | 4 +- lib/toolbox/SConscript | 4 +- scripts/assets.py | 32 ++++++------- scripts/distfap.py | 6 +-- scripts/fbt/appmanifest.py | 10 ++--- scripts/fbt/elfmanifest.py | 4 +- scripts/fbt/fapassets.py | 2 +- scripts/fbt/sdk/cache.py | 17 +++---- scripts/fbt/util.py | 9 ++-- scripts/fbt/version.py | 2 +- scripts/fbt_tools/ccache.py | 2 +- scripts/fbt_tools/crosscc.py | 14 +++--- scripts/fbt_tools/fbt_apps.py | 13 +++--- scripts/fbt_tools/fbt_assets.py | 14 +++--- scripts/fbt_tools/fbt_debugopts.py | 2 - scripts/fbt_tools/fbt_dist.py | 3 +- scripts/fbt_tools/fbt_extapps.py | 18 +++----- scripts/fbt_tools/fbt_hwtarget.py | 2 - scripts/fbt_tools/fbt_sdk.py | 19 ++++---- scripts/fbt_tools/fbt_tweaks.py | 12 +++-- scripts/fbt_tools/fbt_version.py | 2 +- scripts/fbt_tools/fwbin.py | 4 +- scripts/fbt_tools/gdb.py | 4 -- scripts/fbt_tools/objdump.py | 2 +- scripts/fbt_tools/openocd.py | 4 +- scripts/fbt_tools/pvsstudio.py | 13 +++--- scripts/fbt_tools/sconsmodular.py | 3 +- scripts/fbt_tools/sconsrecursiveglob.py | 2 +- scripts/fbt_tools/strip.py | 2 +- scripts/flash.py | 50 ++++++++++----------- scripts/flipper/app.py | 2 +- scripts/flipper/assets/copro.py | 8 ++-- scripts/flipper/assets/coprobin.py | 3 +- scripts/flipper/assets/dolphin.py | 12 +++-- scripts/flipper/assets/icon.py | 12 ++--- scripts/flipper/assets/manifest.py | 5 +-- scripts/flipper/assets/obdata.py | 4 +- scripts/flipper/cube.py | 8 ++-- scripts/flipper/storage.py | 4 +- scripts/flipper/utils/__init__.py | 1 - scripts/flipper/utils/programmer_openocd.py | 10 ++--- scripts/flipper/utils/stm32wb55.py | 6 +-- scripts/flipper/utils/templite.py | 4 +- scripts/fwsize.py | 7 +-- scripts/get_env.py | 10 ++--- scripts/lint.py | 11 +++-- scripts/merge_report_qa.py | 3 +- scripts/meta.py | 3 +- scripts/ob.py | 4 +- scripts/otp.py | 37 +++++++-------- scripts/program.py | 14 +++--- scripts/runfap.py | 12 +++-- scripts/sconsdist.py | 2 +- scripts/selfupdate.py | 12 +++-- scripts/serial_cli.py | 5 ++- scripts/storage.py | 12 ++--- scripts/ufbt/SConstruct | 37 ++++++++++----- scripts/ufbt/commandline.scons | 32 ++++--------- scripts/ufbt/site_init.py | 6 +-- scripts/ufbt/site_tools/ufbt_state.py | 7 ++- scripts/ufbt/update.scons | 37 --------------- scripts/update.py | 20 ++++----- scripts/version.py | 8 ++-- site_scons/extapps.scons | 4 +- 73 files changed, 306 insertions(+), 377 deletions(-) delete mode 100644 scripts/ufbt/update.scons diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0934eec76d..d69318530b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -193,12 +193,14 @@ jobs: TARGET="$(echo '${{ matrix.target }}' | sed 's/f//')"; \ ./fbt TARGET_HW=$TARGET DEBUG=0 COMPACT=1 fap_dist updater_package echo "sdk-file=$(ls dist/${{ matrix.target }}-*/flipper-z-${{ matrix.target }}-sdk-*.zip)" >> $GITHUB_OUTPUT + echo "hw-target-code=$TARGET" >> $GITHUB_OUTPUT - name: Deploy uFBT with SDK uses: flipperdevices/flipperzero-ufbt-action@v0.1.0 with: task: setup sdk-file: ${{ steps.build-fw.outputs.sdk-file }} + sdk-hw-target: ${{ steps.build-fw.outputs.hw-target-code }} - name: Build test app with SDK run: | diff --git a/assets/SConscript b/assets/SConscript index 21437aa301..9bd273626d 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -1,7 +1,7 @@ -Import("env") - from fbt.version import get_git_commit_unix_timestamp +Import("env") + assetsenv = env.Clone( tools=["fbt_assets"], FW_LIB_NAME="assets", diff --git a/firmware.scons b/firmware.scons index c7fdc63925..c469968991 100644 --- a/firmware.scons +++ b/firmware.scons @@ -1,5 +1,3 @@ -Import("ENV", "fw_build_meta") - from SCons.Errors import UserError from SCons.Node import FS @@ -10,6 +8,8 @@ from fbt_extra.util import ( link_elf_dir_as_latest, ) +Import("ENV", "fw_build_meta") + # Building initial C environment for libs env = ENV.Clone( tools=[ diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index bdd5d6b61f..f84bf074e1 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.1,, +Version,+,23.3,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -112,6 +112,7 @@ Header,+,lib/flipper_application/plugins/composite_resolver.h,, Header,+,lib/flipper_application/plugins/plugin_manager.h,, Header,+,lib/flipper_format/flipper_format.h,, Header,+,lib/flipper_format/flipper_format_i.h,, +Header,+,lib/flipper_format/flipper_format_stream.h,, Header,+,lib/libusb_stm32/inc/hid_usage_button.h,, Header,+,lib/libusb_stm32/inc/hid_usage_consumer.h,, Header,+,lib/libusb_stm32/inc/hid_usage_desktop.h,, @@ -755,6 +756,11 @@ Function,+,flipper_format_read_uint32,_Bool,"FlipperFormat*, const char*, uint32 Function,+,flipper_format_rewind,_Bool,FlipperFormat* Function,+,flipper_format_seek_to_end,_Bool,FlipperFormat* Function,+,flipper_format_set_strict_mode,void,"FlipperFormat*, _Bool" +Function,+,flipper_format_stream_delete_key_and_write,_Bool,"Stream*, FlipperStreamWriteData*, _Bool" +Function,+,flipper_format_stream_get_value_count,_Bool,"Stream*, const char*, uint32_t*, _Bool" +Function,+,flipper_format_stream_read_value_line,_Bool,"Stream*, const char*, FlipperStreamValue, void*, size_t, _Bool" +Function,+,flipper_format_stream_write_comment_cstr,_Bool,"Stream*, const char*" +Function,+,flipper_format_stream_write_value_line,_Bool,"Stream*, FlipperStreamWriteData*" Function,+,flipper_format_string_alloc,FlipperFormat*, Function,+,flipper_format_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t" Function,+,flipper_format_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t" diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 9f4ec4261c..c176b2d7e1 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.1,, +Version,+,23.3,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -118,6 +118,7 @@ Header,+,lib/flipper_application/plugins/composite_resolver.h,, Header,+,lib/flipper_application/plugins/plugin_manager.h,, Header,+,lib/flipper_format/flipper_format.h,, Header,+,lib/flipper_format/flipper_format_i.h,, +Header,+,lib/flipper_format/flipper_format_stream.h,, Header,+,lib/ibutton/ibutton_key.h,, Header,+,lib/ibutton/ibutton_protocols.h,, Header,+,lib/ibutton/ibutton_worker.h,, @@ -918,6 +919,11 @@ Function,+,flipper_format_read_uint32,_Bool,"FlipperFormat*, const char*, uint32 Function,+,flipper_format_rewind,_Bool,FlipperFormat* Function,+,flipper_format_seek_to_end,_Bool,FlipperFormat* Function,+,flipper_format_set_strict_mode,void,"FlipperFormat*, _Bool" +Function,+,flipper_format_stream_delete_key_and_write,_Bool,"Stream*, FlipperStreamWriteData*, _Bool" +Function,+,flipper_format_stream_get_value_count,_Bool,"Stream*, const char*, uint32_t*, _Bool" +Function,+,flipper_format_stream_read_value_line,_Bool,"Stream*, const char*, FlipperStreamValue, void*, size_t, _Bool" +Function,+,flipper_format_stream_write_comment_cstr,_Bool,"Stream*, const char*" +Function,+,flipper_format_stream_write_value_line,_Bool,"Stream*, FlipperStreamWriteData*" Function,+,flipper_format_string_alloc,FlipperFormat*, Function,+,flipper_format_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t" Function,+,flipper_format_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t" diff --git a/lib/flipper_format/SConscript b/lib/flipper_format/SConscript index 353da80357..9c9e8b6f33 100644 --- a/lib/flipper_format/SConscript +++ b/lib/flipper_format/SConscript @@ -7,6 +7,7 @@ env.Append( SDK_HEADERS=[ File("flipper_format.h"), File("flipper_format_i.h"), + File("flipper_format_stream.h"), ], ) diff --git a/lib/freertos.scons b/lib/freertos.scons index 1c5a5bf54f..cb0006e560 100644 --- a/lib/freertos.scons +++ b/lib/freertos.scons @@ -7,9 +7,6 @@ env.Append( "#/lib/FreeRTOS-Kernel/portable/GCC/ARM_CM4F", "#/lib/FreeRTOS-glue", ], - CPPDEFINES=[ - "HAVE_FREERTOS", - ], ) diff --git a/lib/libusb_stm32.scons b/lib/libusb_stm32.scons index 4838b7c509..ccc5de24f0 100644 --- a/lib/libusb_stm32.scons +++ b/lib/libusb_stm32.scons @@ -4,9 +4,6 @@ env.Append( CPPPATH=[ "#/lib/libusb_stm32/inc", ], - CPPDEFINES=[ - ("USB_PMASIZE", "0x400"), - ], SDK_HEADERS=env.GlobRecursive( "*.h", Dir("libusb_stm32/inc"), @@ -16,6 +13,11 @@ env.Append( libenv = env.Clone(FW_LIB_NAME="usb_stm32") libenv.ApplyLibFlags() +libenv.Append( + CPPDEFINES=[ + ("USB_PMASIZE", "0x400"), + ], +) sources = [ diff --git a/lib/littlefs.scons b/lib/littlefs.scons index 792142c32f..3d68e07bae 100644 --- a/lib/littlefs.scons +++ b/lib/littlefs.scons @@ -4,14 +4,16 @@ env.Append( CPPPATH=[ "#/lib/littlefs", ], - CPPDEFINES=[ - ("LFS_CONFIG", "lfs_config.h"), - ], ) libenv = env.Clone(FW_LIB_NAME="littlefs") libenv.ApplyLibFlags() +libenv.Append( + CPPDEFINES=[ + ("LFS_CONFIG", "lfs_config.h"), + ], +) sources = Glob("littlefs/*.c", source=True) diff --git a/lib/misc.scons b/lib/misc.scons index b479851b12..1ff6e2fb0c 100644 --- a/lib/misc.scons +++ b/lib/misc.scons @@ -1,7 +1,7 @@ -Import("env") - from fbt.util import GLOB_FILE_EXCLUSION +Import("env") + env.Append( CPPPATH=[ "#/lib/digital_signal", diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index bb06c2db4b..4e158e30ea 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -1,8 +1,8 @@ -Import("env") - from fbt.version import get_fast_git_version_id +Import("env") + env.Append( CPPPATH=[ "#/lib/toolbox", diff --git a/scripts/assets.py b/scripts/assets.py index 75bebcfb45..c0fa9100b7 100755 --- a/scripts/assets.py +++ b/scripts/assets.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 +import os + from flipper.app import App from flipper.assets.icon import file2image -import os - ICONS_SUPPORTED_FORMATS = ["png"] ICONS_TEMPLATE_H_HEADER = """#pragma once @@ -127,7 +127,7 @@ def icons(self): if not filenames: continue if "frame_rate" in filenames: - self.logger.debug(f"Folder contains animation") + self.logger.debug("Folder contains animation") icon_name = "A_" + os.path.split(dirpath)[1].replace("-", "_") width = height = None frame_count = 0 @@ -186,7 +186,7 @@ def icons(self): icons_c.write("\n") icons.append((icon_name, width, height, 0, 1)) # Create array of images: - self.logger.debug(f"Finalizing source file") + self.logger.debug("Finalizing source file") for name, width, height, frame_rate, frame_count in icons: icons_c.write( ICONS_TEMPLATE_C_ICONS.format( @@ -201,7 +201,7 @@ def icons(self): icons_c.close() # Create Public Header - self.logger.debug(f"Creating header") + self.logger.debug("Creating header") icons_h = open( os.path.join(self.args.output_directory, f"{self.args.filename}.h"), "w", @@ -211,7 +211,7 @@ def icons(self): for name, width, height, frame_rate, frame_count in icons: icons_h.write(ICONS_TEMPLATE_H_ICON_NAME.format(name=name)) icons_h.close() - self.logger.debug(f"Done") + self.logger.debug("Done") return 0 def manifest(self): @@ -232,7 +232,7 @@ def manifest(self): new_manifest = Manifest(self.args.timestamp) new_manifest.create(directory_path) - self.logger.info(f"Comparing new manifest with existing") + self.logger.info("Comparing new manifest with existing") only_in_old, changed, only_in_new = Manifest.compare(old_manifest, new_manifest) for record in only_in_old: self.logger.info(f"Only in old: {record}") @@ -246,38 +246,38 @@ def manifest(self): else: self.logger.info("Manifest is up-to-date!") - self.logger.info(f"Complete") + self.logger.info("Complete") return 0 def copro(self): from flipper.assets.copro import Copro - self.logger.info(f"Bundling coprocessor binaries") + self.logger.info("Bundling coprocessor binaries") copro = Copro(self.args.mcu) - self.logger.info(f"Loading CUBE info") + self.logger.info("Loading CUBE info") copro.loadCubeInfo(self.args.cube_dir, self.args.cube_ver) - self.logger.info(f"Bundling") + self.logger.info("Bundling") copro.bundle( self.args.output_dir, self.args.stack_file, self.args.stack_type, self.args.stack_addr, ) - self.logger.info(f"Complete") + self.logger.info("Complete") return 0 def dolphin(self): from flipper.assets.dolphin import Dolphin - self.logger.info(f"Processing Dolphin sources") + self.logger.info("Processing Dolphin sources") dolphin = Dolphin() - self.logger.info(f"Loading data") + self.logger.info("Loading data") dolphin.load(self.args.input_directory) - self.logger.info(f"Packing") + self.logger.info("Packing") dolphin.pack(self.args.output_directory, self.args.symbol_name) - self.logger.info(f"Complete") + self.logger.info("Complete") return 0 diff --git a/scripts/distfap.py b/scripts/distfap.py index 060fe26fff..d330988b51 100644 --- a/scripts/distfap.py +++ b/scripts/distfap.py @@ -1,12 +1,12 @@ #!/usr/bin/env python3 +import os +import posixpath + from flipper.app import App from flipper.storage import FlipperStorage, FlipperStorageOperations from flipper.utils.cdc import resolve_port -import os -import posixpath - class Main(App): def init(self): diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index 37ddc43486..5e41f4c0e3 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -1,7 +1,7 @@ +import os from dataclasses import dataclass, field -from typing import List, Optional, Tuple, Callable from enum import Enum -import os +from typing import Callable, List, Optional, Tuple class FlipperManifestException(Exception): @@ -93,7 +93,7 @@ def __init__(self): def get(self, appname: str): try: return self.known_apps[appname] - except KeyError as _: + except KeyError: raise FlipperManifestException( f"Missing application manifest for '{appname}'" ) @@ -223,6 +223,7 @@ def _check_if_app_target_supported(self, app_name: str): return self.appmgr.get(app_name).supports_hardware_target(self.hw_target) def _get_app_depends(self, app_name: str) -> List[str]: + app_def = self.appmgr.get(app_name) # Skip app if its target is not supported by the target we are building for if not self._check_if_app_target_supported(app_name): self._writer( @@ -230,7 +231,6 @@ def _get_app_depends(self, app_name: str) -> List[str]: ) return [] - app_def = self.appmgr.get(app_name) return list( filter( self._check_if_app_target_supported, @@ -296,7 +296,7 @@ def _group_plugins(self): try: parent_app = self.appmgr.get(parent_app_id) parent_app._plugins.append(extension_app) - except FlipperManifestException as e: + except FlipperManifestException: self._writer( f"Module {extension_app.appid} has unknown parent {parent_app_id}" ) diff --git a/scripts/fbt/elfmanifest.py b/scripts/fbt/elfmanifest.py index 17bceddf4e..333888e140 100644 --- a/scripts/fbt/elfmanifest.py +++ b/scripts/fbt/elfmanifest.py @@ -1,12 +1,10 @@ -from dataclasses import dataclass import os - import struct from dataclasses import dataclass, field -from .appmanifest import FlipperApplication from flipper.assets.icon import file2image +from .appmanifest import FlipperApplication _MANIFEST_MAGIC = 0x52474448 diff --git a/scripts/fbt/fapassets.py b/scripts/fbt/fapassets.py index 0649f03efe..9902fd79a1 100644 --- a/scripts/fbt/fapassets.py +++ b/scripts/fbt/fapassets.py @@ -1,5 +1,5 @@ -import os import hashlib +import os import struct from typing import TypedDict diff --git a/scripts/fbt/sdk/cache.py b/scripts/fbt/sdk/cache.py index 756c378275..b6f6edbe51 100644 --- a/scripts/fbt/sdk/cache.py +++ b/scripts/fbt/sdk/cache.py @@ -1,20 +1,13 @@ -import operator -import os import csv import operator - -from enum import Enum, auto -from typing import Set, ClassVar, Any +import os from dataclasses import dataclass +from enum import Enum, auto +from typing import Any, ClassVar, Set from ansi.color import fg -from . import ( - ApiEntries, - ApiEntryFunction, - ApiEntryVariable, - ApiHeader, -) +from . import ApiEntries, ApiEntryFunction, ApiEntryVariable, ApiHeader @dataclass(frozen=True) @@ -137,7 +130,7 @@ def save(self) -> None: f"API version is still WIP: {self.version}. Review the changes and re-run command." ) ) - print(f"CSV file entries to mark up:") + print("CSV file entries to mark up:") print( fg.yellow( "\n".join( diff --git a/scripts/fbt/util.py b/scripts/fbt/util.py index 7bdaea031f..ae850a8c3c 100644 --- a/scripts/fbt/util.py +++ b/scripts/fbt/util.py @@ -1,10 +1,9 @@ -import SCons -from SCons.Subst import quote_spaces -from SCons.Errors import StopError - -import re import os +import re +import SCons +from SCons.Errors import StopError +from SCons.Subst import quote_spaces WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") diff --git a/scripts/fbt/version.py b/scripts/fbt/version.py index e7fe2edaf6..09f48c8eb8 100644 --- a/scripts/fbt/version.py +++ b/scripts/fbt/version.py @@ -1,5 +1,5 @@ -import subprocess import datetime +import subprocess from functools import cache diff --git a/scripts/fbt_tools/ccache.py b/scripts/fbt_tools/ccache.py index e88886ade3..63577ab781 100644 --- a/scripts/fbt_tools/ccache.py +++ b/scripts/fbt_tools/ccache.py @@ -3,7 +3,7 @@ def exists(): def generate(env): - if ccache := env.WhereIs("ccache"): + if env.WhereIs("ccache"): env["CCACHE"] = "ccache" env["CC_NOCACHE"] = env["CC"] env["CC"] = "$CCACHE $CC_NOCACHE" diff --git a/scripts/fbt_tools/crosscc.py b/scripts/fbt_tools/crosscc.py index dd5cd53196..d0631ca33a 100644 --- a/scripts/fbt_tools/crosscc.py +++ b/scripts/fbt_tools/crosscc.py @@ -1,15 +1,11 @@ -from SCons.Errors import StopError -from SCons.Tool import asm -from SCons.Tool import gcc -from SCons.Tool import gxx -from SCons.Tool import ar -from SCons.Tool import gnulink -import strip +import subprocess + import gdb import objdump - +import strip from SCons.Action import _subproc -import subprocess +from SCons.Errors import StopError +from SCons.Tool import ar, asm, gcc, gnulink, gxx def prefix_commands(env, command_prefix, cmd_list): diff --git a/scripts/fbt_tools/fbt_apps.py b/scripts/fbt_tools/fbt_apps.py index 9dbe307203..053a695037 100644 --- a/scripts/fbt_tools/fbt_apps.py +++ b/scripts/fbt_tools/fbt_apps.py @@ -1,15 +1,14 @@ -from SCons.Builder import Builder -from SCons.Action import Action -from SCons.Errors import StopError -from SCons.Warnings import warn, WarningOnByDefault from ansi.color import fg - from fbt.appmanifest import ( - FlipperAppType, - AppManager, ApplicationsCGenerator, + AppManager, + FlipperAppType, FlipperManifestException, ) +from SCons.Action import Action +from SCons.Builder import Builder +from SCons.Errors import StopError +from SCons.Warnings import WarningOnByDefault, warn # Adding objects for application management to env # AppManager env["APPMGR"] - loads all manifests; manages list of known apps diff --git a/scripts/fbt_tools/fbt_assets.py b/scripts/fbt_tools/fbt_assets.py index e4c567993e..68617c2549 100644 --- a/scripts/fbt_tools/fbt_assets.py +++ b/scripts/fbt_tools/fbt_assets.py @@ -1,10 +1,10 @@ -from SCons.Builder import Builder -from SCons.Action import Action -from SCons.Errors import StopError - import os import subprocess + from ansi.color import fg +from SCons.Action import Action +from SCons.Builder import Builder +from SCons.Errors import StopError def icons_emitter(target, source, env): @@ -76,11 +76,11 @@ def proto_ver_generator(target, source, env): target_file = target[0] src_dir = source[0].dir.abspath try: - git_fetch = _invoke_git( + _invoke_git( ["fetch", "--tags"], source_dir=src_dir, ) - except (subprocess.CalledProcessError, EnvironmentError) as e: + except (subprocess.CalledProcessError, EnvironmentError): # Not great, not terrible print(fg.boldred("Git: fetch failed")) @@ -89,7 +89,7 @@ def proto_ver_generator(target, source, env): ["describe", "--tags", "--abbrev=0"], source_dir=src_dir, ) - except (subprocess.CalledProcessError, EnvironmentError) as e: + except (subprocess.CalledProcessError, EnvironmentError): raise StopError("Git: describe failed") git_major, git_minor = git_describe.split(".") diff --git a/scripts/fbt_tools/fbt_debugopts.py b/scripts/fbt_tools/fbt_debugopts.py index 9abe59893e..33cc0c0763 100644 --- a/scripts/fbt_tools/fbt_debugopts.py +++ b/scripts/fbt_tools/fbt_debugopts.py @@ -1,5 +1,3 @@ -from re import search - from SCons.Errors import UserError diff --git a/scripts/fbt_tools/fbt_dist.py b/scripts/fbt_tools/fbt_dist.py index d2808419c7..a43d62e9dc 100644 --- a/scripts/fbt_tools/fbt_dist.py +++ b/scripts/fbt_tools/fbt_dist.py @@ -1,6 +1,5 @@ -from SCons.Builder import Builder from SCons.Action import Action -from SCons.Script import Mkdir +from SCons.Builder import Builder from SCons.Defaults import Touch diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index 4ac1c68737..1a1bad29e7 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -3,23 +3,19 @@ import pathlib import shutil from dataclasses import dataclass, field -from typing import Optional, TypedDict - -from ansi.color import fg +from typing import Optional import SCons.Warnings -from SCons.Action import Action -from SCons.Builder import Builder -from SCons.Errors import UserError -from SCons.Node import NodeList -from SCons.Node.FS import File, Entry - +from ansi.color import fg from fbt.appmanifest import FlipperApplication, FlipperAppType, FlipperManifestException from fbt.elfmanifest import assemble_manifest_data from fbt.fapassets import FileBundler from fbt.sdk.cache import SdkCache from fbt.util import extract_abs_dir_path - +from SCons.Action import Action +from SCons.Builder import Builder +from SCons.Errors import UserError +from SCons.Node.FS import Entry, File _FAP_META_SECTION = ".fapmeta" _FAP_FILEASSETS_SECTION = ".fapassets" @@ -289,7 +285,7 @@ def GetExtAppByIdOrPath(env, app_dir): try: # Maybe user passed an appid? app = appmgr.get(app_dir) - except FlipperManifestException as _: + except FlipperManifestException: # Look up path components in known app dirs for dir_part in reversed(pathlib.Path(app_dir).parts): if app := appmgr.find_by_appdir(dir_part): diff --git a/scripts/fbt_tools/fbt_hwtarget.py b/scripts/fbt_tools/fbt_hwtarget.py index b4e1e58ac1..1831a6984d 100644 --- a/scripts/fbt_tools/fbt_hwtarget.py +++ b/scripts/fbt_tools/fbt_hwtarget.py @@ -1,5 +1,3 @@ -from SCons.Builder import Builder -from SCons.Action import Action import json diff --git a/scripts/fbt_tools/fbt_sdk.py b/scripts/fbt_tools/fbt_sdk.py index 90d0831eb4..2f7d62388d 100644 --- a/scripts/fbt_tools/fbt_sdk.py +++ b/scripts/fbt_tools/fbt_sdk.py @@ -1,21 +1,20 @@ +import json +import os.path +import pathlib +import posixpath import shutil -from SCons.Builder import Builder + +from fbt.sdk.cache import SdkCache +from fbt.sdk.collector import SdkCollector +from fbt.util import path_as_posix from SCons.Action import Action +from SCons.Builder import Builder from SCons.Errors import UserError # from SCons.Scanner import C from SCons.Script import Entry from SCons.Util import LogicalLines -import os.path -import posixpath -import pathlib -import json - -from fbt.sdk.collector import SdkCollector -from fbt.sdk.cache import SdkCache -from fbt.util import path_as_posix - def ProcessSdkDepends(env, filename): try: diff --git a/scripts/fbt_tools/fbt_tweaks.py b/scripts/fbt_tools/fbt_tweaks.py index 700f66d238..68ac9d7d17 100644 --- a/scripts/fbt_tools/fbt_tweaks.py +++ b/scripts/fbt_tools/fbt_tweaks.py @@ -1,15 +1,13 @@ +import os +import sys +import traceback + import SCons.Warnings as Warnings +from ansi.color import fg from SCons.Errors import UserError - # from SCons.Script.Main import find_deepest_user_frame -from ansi.color import fg, bg, fx - -import traceback -import sys -import os - def find_deepest_user_frame(tb): tb.reverse() diff --git a/scripts/fbt_tools/fbt_version.py b/scripts/fbt_tools/fbt_version.py index 87497ca5f7..8469e181a3 100644 --- a/scripts/fbt_tools/fbt_version.py +++ b/scripts/fbt_tools/fbt_version.py @@ -1,5 +1,5 @@ -from SCons.Builder import Builder from SCons.Action import Action +from SCons.Builder import Builder def version_emitter(target, source, env): diff --git a/scripts/fbt_tools/fwbin.py b/scripts/fbt_tools/fwbin.py index f510c2a60c..06a435b6db 100644 --- a/scripts/fbt_tools/fwbin.py +++ b/scripts/fbt_tools/fwbin.py @@ -1,6 +1,6 @@ -from SCons.Builder import Builder -from SCons.Action import Action import SCons +from SCons.Action import Action +from SCons.Builder import Builder __OBJCOPY_ARM_BIN = "arm-none-eabi-objcopy" __NM_ARM_BIN = "arm-none-eabi-nm" diff --git a/scripts/fbt_tools/gdb.py b/scripts/fbt_tools/gdb.py index 38256a0f81..ea29e9c92e 100644 --- a/scripts/fbt_tools/gdb.py +++ b/scripts/fbt_tools/gdb.py @@ -1,7 +1,3 @@ -from SCons.Builder import Builder -from SCons.Action import Action - - def generate(env): env.SetDefault( GDB="gdb", diff --git a/scripts/fbt_tools/objdump.py b/scripts/fbt_tools/objdump.py index f5fa938a7b..31f8176484 100644 --- a/scripts/fbt_tools/objdump.py +++ b/scripts/fbt_tools/objdump.py @@ -1,5 +1,5 @@ -from SCons.Builder import Builder from SCons.Action import Action +from SCons.Builder import Builder def generate(env): diff --git a/scripts/fbt_tools/openocd.py b/scripts/fbt_tools/openocd.py index dcf0bf925a..157d798f40 100644 --- a/scripts/fbt_tools/openocd.py +++ b/scripts/fbt_tools/openocd.py @@ -1,7 +1,7 @@ -from SCons.Builder import Builder +import SCons from SCons.Action import Action +from SCons.Builder import Builder from SCons.Defaults import Touch -import SCons __OPENOCD_BIN = "openocd" diff --git a/scripts/fbt_tools/pvsstudio.py b/scripts/fbt_tools/pvsstudio.py index 593559a33f..211f46aee8 100644 --- a/scripts/fbt_tools/pvsstudio.py +++ b/scripts/fbt_tools/pvsstudio.py @@ -1,11 +1,12 @@ -from SCons.Builder import Builder -from SCons.Action import Action -from SCons.Script import Delete, Mkdir, GetBuildFailures, Flatten -import multiprocessing -import webbrowser import atexit -import sys +import multiprocessing import subprocess +import sys +import webbrowser + +from SCons.Action import Action +from SCons.Builder import Builder +from SCons.Script import Delete, Flatten, GetBuildFailures, Mkdir __no_browser = False diff --git a/scripts/fbt_tools/sconsmodular.py b/scripts/fbt_tools/sconsmodular.py index 57ae8f055c..4dc2079a6e 100644 --- a/scripts/fbt_tools/sconsmodular.py +++ b/scripts/fbt_tools/sconsmodular.py @@ -1,5 +1,6 @@ -import posixpath import os +import posixpath + from SCons.Errors import UserError diff --git a/scripts/fbt_tools/sconsrecursiveglob.py b/scripts/fbt_tools/sconsrecursiveglob.py index fbcee965b1..7dbde531b3 100644 --- a/scripts/fbt_tools/sconsrecursiveglob.py +++ b/scripts/fbt_tools/sconsrecursiveglob.py @@ -1,6 +1,6 @@ import SCons -from SCons.Script import Flatten from fbt.util import GLOB_FILE_EXCLUSION +from SCons.Script import Flatten def GlobRecursive(env, pattern, node=".", exclude=[]): diff --git a/scripts/fbt_tools/strip.py b/scripts/fbt_tools/strip.py index 053956f22e..ee14fc185a 100644 --- a/scripts/fbt_tools/strip.py +++ b/scripts/fbt_tools/strip.py @@ -1,5 +1,5 @@ -from SCons.Builder import Builder from SCons.Action import Action +from SCons.Builder import Builder def generate(env): diff --git a/scripts/flash.py b/scripts/flash.py index fb05b8b0b8..6189dc1a28 100755 --- a/scripts/flash.py +++ b/scripts/flash.py @@ -1,13 +1,9 @@ #!/usr/bin/env python3 -import logging -import argparse -import sys -import os from flipper.app import App -from flipper.cube import CubeProgrammer from flipper.assets.coprobin import CoproBinary +from flipper.cube import CubeProgrammer STATEMENT = "AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE" @@ -94,59 +90,59 @@ def _getCubeParams(self): } def wipe(self): - self.logger.info(f"Wiping flash") + self.logger.info("Wiping flash") cp = CubeProgrammer(self._getCubeParams()) - self.logger.info(f"Setting RDP to 0xBB") + self.logger.info("Setting RDP to 0xBB") cp.setOptionBytes({"RDP": ("0xBB", "rw")}) - self.logger.info(f"Verifying RDP") + self.logger.info("Verifying RDP") r = cp.checkOptionBytes({"RDP": ("0xBB", "rw")}) - assert r == True + assert r is True self.logger.info(f"Result: {r}") - self.logger.info(f"Setting RDP to 0xAA") + self.logger.info("Setting RDP to 0xAA") cp.setOptionBytes({"RDP": ("0xAA", "rw")}) - self.logger.info(f"Verifying RDP") + self.logger.info("Verifying RDP") r = cp.checkOptionBytes({"RDP": ("0xAA", "rw")}) - assert r == True + assert r is True self.logger.info(f"Result: {r}") - self.logger.info(f"Complete") + self.logger.info("Complete") return 0 def core1bootloader(self): - self.logger.info(f"Flashing bootloader") + self.logger.info("Flashing bootloader") cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x08000000", self.args.bootloader) - self.logger.info(f"Complete") + self.logger.info("Complete") cp.resetTarget() return 0 def core1firmware(self): - self.logger.info(f"Flashing firmware") + self.logger.info("Flashing firmware") cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x08008000", self.args.firmware) - self.logger.info(f"Complete") + self.logger.info("Complete") cp.resetTarget() return 0 def core1(self): - self.logger.info(f"Flashing bootloader") + self.logger.info("Flashing bootloader") cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x08000000", self.args.bootloader) - self.logger.info(f"Flashing firmware") + self.logger.info("Flashing firmware") cp.flashBin("0x08008000", self.args.firmware) cp.resetTarget() - self.logger.info(f"Complete") + self.logger.info("Complete") return 0 def core2fus(self): if self.args.statement != STATEMENT: self.logger.error( - f"PLEASE DON'T. THIS FEATURE INTENDED ONLY FOR FACTORY FLASHING" + "PLEASE DON'T. THIS FEATURE INTENDED ONLY FOR FACTORY FLASHING" ) return 1 - self.logger.info(f"Flashing Firmware Update Service") + self.logger.info("Flashing Firmware Update Service") cp = CubeProgrammer(self._getCubeParams()) cp.flashCore2(self.args.fus_address, self.args.fus) - self.logger.info(f"Complete") + self.logger.info("Complete") return 0 def core2radio(self): @@ -163,15 +159,15 @@ def core2radio(self): f"Radio address not provided, guessed as 0x{radio_address:X}" ) if radio_address > 0x080E0000: - self.logger.error(f"I KNOW WHAT YOU DID LAST SUMMER") + self.logger.error("I KNOW WHAT YOU DID LAST SUMMER") return 1 cp = CubeProgrammer(self._getCubeParams()) - self.logger.info(f"Removing Current Radio Stack") + self.logger.info("Removing Current Radio Stack") cp.deleteCore2RadioStack() - self.logger.info(f"Flashing Radio Stack") + self.logger.info("Flashing Radio Stack") cp.flashCore2(radio_address, self.args.radio) - self.logger.info(f"Complete") + self.logger.info("Complete") return 0 diff --git a/scripts/flipper/app.py b/scripts/flipper/app.py index 30630a5f9f..405c4c3990 100644 --- a/scripts/flipper/app.py +++ b/scripts/flipper/app.py @@ -44,7 +44,7 @@ def __call__(self, args=None, skip_logger_init=False): if isinstance(return_code, int): return self._exit(return_code) else: - self.logger.error(f"Missing return code") + self.logger.error("Missing return code") return self._exit(255) def _exit(self, code): diff --git a/scripts/flipper/assets/copro.py b/scripts/flipper/assets/copro.py index e0375b51f1..ee13a9b5ea 100644 --- a/scripts/flipper/assets/copro.py +++ b/scripts/flipper/assets/copro.py @@ -6,7 +6,7 @@ import posixpath import os -from flipper.utils import * +from flipper.utils import file_sha256, timestamp from flipper.assets.coprobin import CoproBinary, get_stack_type @@ -45,13 +45,13 @@ def loadCubeInfo(self, cube_dir, reference_cube_version): cube_manifest = ET.parse(cube_manifest_file) cube_package = cube_manifest.find("PackDescription") if not cube_package: - raise Exception(f"Unknown Cube manifest format") + raise Exception("Unknown Cube manifest format") cube_version = cube_package.get("Patch") or cube_package.get("Release") if not cube_version or not cube_version.startswith("FW.WB"): - raise Exception(f"Incorrect Cube package or version info") + raise Exception("Incorrect Cube package or version info") cube_version = cube_version.replace("FW.WB.", "", 1) if cube_version != reference_cube_version: - raise Exception(f"Unsupported cube version") + raise Exception("Unsupported cube version") self.version = cube_version def _getFileName(self, name): diff --git a/scripts/flipper/assets/coprobin.py b/scripts/flipper/assets/coprobin.py index 64f0b8c871..7c5bdb3dc4 100644 --- a/scripts/flipper/assets/coprobin.py +++ b/scripts/flipper/assets/coprobin.py @@ -1,6 +1,7 @@ import struct import math -import os, os.path +import os +import os.path import sys diff --git a/scripts/flipper/assets/dolphin.py b/scripts/flipper/assets/dolphin.py index cbd1320b65..ebe9fd8898 100644 --- a/scripts/flipper/assets/dolphin.py +++ b/scripts/flipper/assets/dolphin.py @@ -1,13 +1,11 @@ import multiprocessing import logging import os -import sys -import shutil from collections import Counter -from flipper.utils.fff import * -from flipper.utils.templite import * -from .icon import * +from flipper.utils.fff import FlipperFormatFile +from flipper.utils.templite import Templite +from .icon import ImageTools, file2image def _convert_image_to_bm(pair: set): @@ -121,7 +119,7 @@ def load(self, animation_directory: str): self.meta["Passive frames"] + self.meta["Active frames"] == ordered_frames_count ) - except EOFError as e: + except EOFError: raise Exception("Invalid meta file: too short") except AssertionError as e: self.logger.exception(e) @@ -158,7 +156,7 @@ def load(self, animation_directory: str): except AssertionError as e: self.logger.exception(e) self.logger.error( - f"Animation {self.name} bubble slot {bubble_slot} got incorrect data: {bubble}" + f"Animation {self.name} bubble slot {bubble['Slot']} got incorrect data: {bubble}" ) raise Exception("Meta file is invalid: incorrect bubble data") except EOFError: diff --git a/scripts/flipper/assets/icon.py b/scripts/flipper/assets/icon.py index f0dae25bea..d5d2a585ee 100644 --- a/scripts/flipper/assets/icon.py +++ b/scripts/flipper/assets/icon.py @@ -1,9 +1,6 @@ import logging -import argparse import subprocess import io -import os -import sys ICONS_SUPPORTED_FORMATS = ["png"] @@ -36,11 +33,8 @@ class ImageTools: @staticmethod def is_processing_slow(): try: - from PIL import Image, ImageOps - import heatshrink2 - return False - except ImportError as e: + except ImportError: return True def __init__(self): @@ -52,7 +46,7 @@ def png2xbm(self, file): try: from PIL import Image, ImageOps - except ImportError as e: + except ImportError: self.__pil_unavailable = True self.logger.info("pillow module is missing, using convert cli util") return self.png2xbm(file) @@ -72,7 +66,7 @@ def xbm2hs(self, data): try: import heatshrink2 - except ImportError as e: + except ImportError: self.__hs2_unavailable = True self.logger.info("heatshrink2 module is missing, using heatshrink cli util") return self.xbm2hs(data) diff --git a/scripts/flipper/assets/manifest.py b/scripts/flipper/assets/manifest.py index a8f6855a47..a9bbb8dacd 100644 --- a/scripts/flipper/assets/manifest.py +++ b/scripts/flipper/assets/manifest.py @@ -1,11 +1,10 @@ -import datetime import logging import os import posixpath from pathlib import Path -from flipper.utils import * -from flipper.utils.fstree import * +from flipper.utils import timestamp, file_md5 +from flipper.utils.fstree import FsNode, compare_fs_trees MANIFEST_VERSION = 0 diff --git a/scripts/flipper/assets/obdata.py b/scripts/flipper/assets/obdata.py index 0f7f5c1928..eb35d0e174 100644 --- a/scripts/flipper/assets/obdata.py +++ b/scripts/flipper/assets/obdata.py @@ -1,7 +1,5 @@ #!/usr/bin/env python3 -import logging -import struct from enum import Enum from dataclasses import dataclass @@ -181,7 +179,7 @@ def __init__(self, obfname): def gen_values(self): obref = ObReferenceValuesGenerator() - converted_refs = list(obref.apply(ob) for ob in self.obs) + list(obref.apply(ob) for ob in self.obs) return obref diff --git a/scripts/flipper/cube.py b/scripts/flipper/cube.py index 38aa54a854..e4f9876df1 100644 --- a/scripts/flipper/cube.py +++ b/scripts/flipper/cube.py @@ -14,7 +14,7 @@ def __init__(self, config={}): if "port" in config and config["port"]: connect.append(f"port={config['port']}") else: - connect.append(f"port=swd") + connect.append("port=swd") if "serial" in config and config["serial"]: connect.append(f"sn={config['serial']}") self.params.append("-c " + " ".join(connect)) @@ -43,20 +43,20 @@ def _execute(self, args): return output.decode() def getVersion(self): - output = self._execute(["--version"]) + self._execute(["--version"]) def checkOptionBytes(self, option_bytes): output = self._execute(["-ob displ"]) ob_correct = True for line in output.split("\n"): line = line.strip() - if not ":" in line: + if ":" not in line: self.logger.debug(f"Skipping line: {line}") continue key, data = line.split(":", 1) key = key.strip() data = data.strip() - if not key in option_bytes.keys(): + if key not in option_bytes.keys(): self.logger.debug(f"Skipping key: {key}") continue self.logger.debug(f"Processing key: {key} {data}") diff --git a/scripts/flipper/storage.py b/scripts/flipper/storage.py index cff32ceb1d..9f6f52156f 100644 --- a/scripts/flipper/storage.py +++ b/scripts/flipper/storage.py @@ -151,7 +151,7 @@ def list_tree(self, path: str = "/", level: int = 0): try: # TODO: better decoding, considering non-ascii characters line = line.decode("ascii") - except: + except Exception: continue line = line.strip() @@ -194,7 +194,7 @@ def walk(self, path: str = "/"): try: # TODO: better decoding, considering non-ascii characters line = line.decode("ascii") - except: + except Exception: continue line = line.strip() diff --git a/scripts/flipper/utils/__init__.py b/scripts/flipper/utils/__init__.py index 62bf98a25e..6b4ebbd52b 100644 --- a/scripts/flipper/utils/__init__.py +++ b/scripts/flipper/utils/__init__.py @@ -1,6 +1,5 @@ import datetime import hashlib -import os def timestamp(): diff --git a/scripts/flipper/utils/programmer_openocd.py b/scripts/flipper/utils/programmer_openocd.py index 3d21718547..5a8029f379 100644 --- a/scripts/flipper/utils/programmer_openocd.py +++ b/scripts/flipper/utils/programmer_openocd.py @@ -31,13 +31,13 @@ def __init__( config["interface"] = interface config["target"] = "target/stm32wbx.cfg" - if not serial is None: + if serial is not None: if interface == "interface/cmsis-dap.cfg": config["serial"] = f"cmsis_dap_serial {serial}" elif "stlink" in interface: config["serial"] = f"stlink_serial {serial}" - if not port_base is None: + if port_base is not None: config["port_base"] = port_base self.openocd = OpenOCD(config) @@ -59,7 +59,7 @@ def flash(self, address: int, file_path: str, verify: bool = True) -> bool: raise Exception(f"File {file_path} not found") self.openocd.start() - self.openocd.send_tcl(f"init") + self.openocd.send_tcl("init") self.openocd.send_tcl( f"program {file_path} 0x{address:08x}{' verify' if verify else ''} reset exit" ) @@ -196,7 +196,7 @@ def option_bytes_set(self, file_path: str) -> bool: if ob_need_to_apply: stm32.option_bytes_apply(self.openocd) else: - self.logger.info(f"Option Bytes are already correct") + self.logger.info("Option Bytes are already correct") # Load Option Bytes # That will reset and also lock the Option Bytes and the Flash @@ -256,7 +256,7 @@ def otp_write(self, address: int, file_path: str) -> OpenOCDProgrammerResult: already_written = False if already_written: - self.logger.info(f"OTP memory is already written with the given data") + self.logger.info("OTP memory is already written with the given data") return OpenOCDProgrammerResult.Success self.reset(self.RunMode.Stop) diff --git a/scripts/flipper/utils/stm32wb55.py b/scripts/flipper/utils/stm32wb55.py index 910b0d7d69..52a5ec4e3e 100644 --- a/scripts/flipper/utils/stm32wb55.py +++ b/scripts/flipper/utils/stm32wb55.py @@ -123,7 +123,7 @@ def reset(self, oocd: OpenOCD, mode: RunMode): def clear_flash_errors(self, oocd: OpenOCD): # Errata 2.2.9: Flash OPTVERR flag is always set after system reset # And also clear all other flash error flags - self.logger.debug(f"Resetting flash errors") + self.logger.debug("Resetting flash errors") self.FLASH_SR.load(oocd) self.FLASH_SR.OP_ERR = 1 self.FLASH_SR.PROG_ERR = 1 @@ -218,7 +218,7 @@ def flash_lock(self, oocd: OpenOCD): raise Exception("Flash lock failed") def option_bytes_apply(self, oocd: OpenOCD): - self.logger.debug(f"Applying Option Bytes") + self.logger.debug("Applying Option Bytes") self.FLASH_CR.load(oocd) self.FLASH_CR.OPT_STRT = 1 @@ -228,7 +228,7 @@ def option_bytes_apply(self, oocd: OpenOCD): self.flash_wait_for_operation(oocd) def option_bytes_load(self, oocd: OpenOCD): - self.logger.debug(f"Loading Option Bytes") + self.logger.debug("Loading Option Bytes") self.FLASH_CR.load(oocd) self.FLASH_CR.OBL_LAUNCH = 1 self.FLASH_CR.store(oocd) diff --git a/scripts/flipper/utils/templite.py b/scripts/flipper/utils/templite.py index 2d958bd77a..1d19585cd8 100644 --- a/scripts/flipper/utils/templite.py +++ b/scripts/flipper/utils/templite.py @@ -77,8 +77,8 @@ def processControl(self): return lines = self.block.splitlines() - margin = min(len(l) - len(l.lstrip()) for l in lines if l.strip()) - self.block = "\n".join("\t" * self.offset + l[margin:] for l in lines) + margin = min(len(line) - len(line.lstrip()) for line in lines if line.strip()) + self.block = "\n".join("\t" * self.offset + line[margin:] for line in lines) self.blocks.append(self.block) if self.block.endswith(":"): self.offset += 1 diff --git a/scripts/fwsize.py b/scripts/fwsize.py index 445c290498..75a8256922 100644 --- a/scripts/fwsize.py +++ b/scripts/fwsize.py @@ -1,10 +1,11 @@ #!/usr/bin/env python3 -from flipper.app import App -import subprocess -import os import math +import os +import subprocess + from ansi.color import fg +from flipper.app import App class Main(App): diff --git a/scripts/get_env.py b/scripts/get_env.py index 92f9243c2d..5403bafeb2 100644 --- a/scripts/get_env.py +++ b/scripts/get_env.py @@ -1,14 +1,14 @@ #!/usr/bin/env python3 -import ssl +import argparse +import datetime import json import os -import shlex +import random import re +import shlex +import ssl import string -import random -import argparse -import datetime import urllib.request diff --git a/scripts/lint.py b/scripts/lint.py index 58f2d69f55..8530209bec 100755 --- a/scripts/lint.py +++ b/scripts/lint.py @@ -1,14 +1,13 @@ #!/usr/bin/env python3 +import multiprocessing import os import re import shutil import subprocess -import multiprocessing from flipper.app import App - SOURCE_CODE_FILE_EXTENSIONS = [".h", ".c", ".cpp", ".cxx", ".hpp"] SOURCE_CODE_FILE_PATTERN = r"^[0-9A-Za-z_]+\.[a-z]+$" SOURCE_CODE_DIR_PATTERN = r"^[0-9A-Za-z_]+$" @@ -59,7 +58,7 @@ def _check_folders(self, folders: list): show_message = True if show_message: self.logger.warning( - f"Folders are not renamed automatically, please fix it by yourself" + "Folders are not renamed automatically, please fix it by yourself" ) def _find_sources(self, folders: list): @@ -70,7 +69,7 @@ def _find_sources(self, folders: list): for filename in filenames: ext = os.path.splitext(filename.lower())[1] - if not ext in SOURCE_CODE_FILE_EXTENSIONS: + if ext not in SOURCE_CODE_FILE_EXTENSIONS: continue output.append(os.path.join(dirpath, filename)) return output @@ -80,7 +79,7 @@ def _format_source(task): try: subprocess.check_call(task) return True - except subprocess.CalledProcessError as e: + except subprocess.CalledProcessError: return False def _format_sources(self, sources: list, dry_run: bool = False): @@ -144,7 +143,7 @@ def _apply_file_naming_convention(self, sources: list, dry_run: bool = False): def _apply_file_permissions(self, sources: list, dry_run: bool = False): execute_permissions = 0o111 - pattern = re.compile(SOURCE_CODE_FILE_PATTERN) + re.compile(SOURCE_CODE_FILE_PATTERN) good = [] bad = [] # Check sources for unexpected execute permissions diff --git a/scripts/merge_report_qa.py b/scripts/merge_report_qa.py index caa7424085..a33327e6b7 100755 --- a/scripts/merge_report_qa.py +++ b/scripts/merge_report_qa.py @@ -1,9 +1,10 @@ #!/usr/bin/env python3 +import argparse import os import re import sys -import argparse + from slack_sdk import WebClient from slack_sdk.errors import SlackApiError diff --git a/scripts/meta.py b/scripts/meta.py index ae2f213b76..f47ef65fb0 100755 --- a/scripts/meta.py +++ b/scripts/meta.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -from flipper.app import App import json +from flipper.app import App + class Main(App): def init(self): diff --git a/scripts/ob.py b/scripts/ob.py index 178fe16a77..7010bdec58 100755 --- a/scripts/ob.py +++ b/scripts/ob.py @@ -44,7 +44,7 @@ def _add_args(self, parser): ) def check(self): - self.logger.info(f"Checking Option Bytes") + self.logger.info("Checking Option Bytes") # OpenOCD openocd = OpenOCDProgrammer( @@ -60,7 +60,7 @@ def check(self): return return_code def set(self): - self.logger.info(f"Setting Option Bytes") + self.logger.info("Setting Option Bytes") # OpenOCD openocd = OpenOCDProgrammer( diff --git a/scripts/otp.py b/scripts/otp.py index cb76bdc861..19b8c4df42 100755 --- a/scripts/otp.py +++ b/scripts/otp.py @@ -1,13 +1,13 @@ #!/usr/bin/env python3 +import datetime import logging -import argparse -import subprocess import os -import sys import re import struct -import datetime + +from flipper.app import App +from flipper.utils.programmer_openocd import OpenOCDProgrammer, OpenOCDProgrammerResult OTP_MAGIC = 0xBABE OTP_VERSION = 0x02 @@ -33,9 +33,6 @@ "mgg": 0x02, } -from flipper.app import App -from flipper.utils.programmer_openocd import OpenOCDProgrammer, OpenOCDProgrammerResult - class OTPException(Exception): def __init__(self, message: str, result: OpenOCDProgrammerResult): @@ -158,7 +155,7 @@ def _packSecond(self): ) def generate_all(self): - self.logger.info(f"Generating OTP") + self.logger.info("Generating OTP") self._processFirstArgs() self._processSecondArgs() with open(f"{self.args.file}_first.bin", "wb") as file: @@ -172,18 +169,18 @@ def generate_all(self): return 0 def flash_first(self): - self.logger.info(f"Flashing first block of OTP") + self.logger.info("Flashing first block of OTP") self._processFirstArgs() filename = f"otp_unknown_first_{self.timestamp}.bin" try: - self.logger.info(f"Packing binary data") + self.logger.info("Packing binary data") with open(filename, "wb") as file: file.write(self._packFirst()) - self.logger.info(f"Flashing OTP") + self.logger.info("Flashing OTP") openocd = OpenOCDProgrammer( self.args.interface, @@ -195,7 +192,7 @@ def flash_first(self): if programmer_result != OpenOCDProgrammerResult.Success: raise OTPException("Failed to flash OTP", programmer_result) - self.logger.info(f"Flashed Successfully") + self.logger.info("Flashed Successfully") except OTPException as e: self.logger.exception(e) return e.get_exit_code() @@ -205,18 +202,18 @@ def flash_first(self): return 0 def flash_second(self): - self.logger.info(f"Flashing second block of OTP") + self.logger.info("Flashing second block of OTP") self._processSecondArgs() filename = f"otp_{self.args.name}_second_{self.timestamp}.bin" try: - self.logger.info(f"Packing binary data") + self.logger.info("Packing binary data") with open(filename, "wb") as file: file.write(self._packSecond()) - self.logger.info(f"Flashing OTP") + self.logger.info("Flashing OTP") openocd = OpenOCDProgrammer( self.args.interface, @@ -228,7 +225,7 @@ def flash_second(self): if programmer_result != OpenOCDProgrammerResult.Success: raise OTPException("Failed to flash OTP", programmer_result) - self.logger.info(f"Flashed Successfully") + self.logger.info("Flashed Successfully") except OTPException as e: self.logger.exception(e) return e.get_exit_code() @@ -238,7 +235,7 @@ def flash_second(self): return 0 def flash_all(self): - self.logger.info(f"Flashing OTP") + self.logger.info("Flashing OTP") self._processFirstArgs() self._processSecondArgs() @@ -246,12 +243,12 @@ def flash_all(self): filename = f"otp_{self.args.name}_whole_{self.timestamp}.bin" try: - self.logger.info(f"Packing binary data") + self.logger.info("Packing binary data") with open(filename, "wb") as file: file.write(self._packFirst()) file.write(self._packSecond()) - self.logger.info(f"Flashing OTP") + self.logger.info("Flashing OTP") openocd = OpenOCDProgrammer( self.args.interface, @@ -263,7 +260,7 @@ def flash_all(self): if programmer_result != OpenOCDProgrammerResult.Success: raise OTPException("Failed to flash OTP", programmer_result) - self.logger.info(f"Flashed Successfully") + self.logger.info("Flashed Successfully") except OTPException as e: self.logger.exception(e) return e.get_exit_code() diff --git a/scripts/program.py b/scripts/program.py index c140a9024e..f3e7e3e2d1 100755 --- a/scripts/program.py +++ b/scripts/program.py @@ -1,13 +1,13 @@ #!/usr/bin/env python3 -import typing -import subprocess import logging -import time import os import socket - +import subprocess +import time +import typing from abc import ABC, abstractmethod from dataclasses import dataclass + from flipper.app import App @@ -223,7 +223,7 @@ def _valid_ip(self, address): try: socket.inet_aton(address) return True - except: + except Exception: return False def set_serial(self, serial: str): @@ -415,12 +415,12 @@ def flash(self): if len(interfaces) == 0: interfaces = [p for p in network_programmers if p.get_name() == i_name] else: - self.logger.info(f"Probing for interfaces...") + self.logger.info("Probing for interfaces...") interfaces = self._search_interface(self.args.serial) if len(interfaces) == 0: # Probe network blackmagic - self.logger.info(f"Probing for network interfaces...") + self.logger.info("Probing for network interfaces...") interfaces = self._search_network_interface(self.args.serial) if len(interfaces) == 0: diff --git a/scripts/runfap.py b/scripts/runfap.py index f8ff607c1c..a240acf121 100644 --- a/scripts/runfap.py +++ b/scripts/runfap.py @@ -1,14 +1,12 @@ #!/usr/bin/env python3 +import operator +from functools import reduce + from flipper.app import App from flipper.storage import FlipperStorage, FlipperStorageOperations from flipper.utils.cdc import resolve_port -import os -import posixpath -from functools import reduce -import operator - class Main(App): def init(self): @@ -38,8 +36,8 @@ def init(self): self.parser.set_defaults(func=self.install) @staticmethod - def flatten(l): - return reduce(operator.concat, l, []) + def flatten(item_list): + return reduce(operator.concat, item_list, []) def install(self): self.args.sources = self.flatten(self.args.sources) diff --git a/scripts/sconsdist.py b/scripts/sconsdist.py index af2554d0ad..1657feab93 100644 --- a/scripts/sconsdist.py +++ b/scripts/sconsdist.py @@ -5,7 +5,7 @@ import tarfile import zipfile from os import makedirs, walk -from os.path import exists, join, relpath, basename, split +from os.path import basename, exists, join, relpath from ansi.color import fg from flipper.app import App diff --git a/scripts/selfupdate.py b/scripts/selfupdate.py index 9bfbfefa37..1ce0b83763 100644 --- a/scripts/selfupdate.py +++ b/scripts/selfupdate.py @@ -1,14 +1,12 @@ #!/usr/bin/env python3 -from typing import final -from flipper.app import App -from flipper.storage import FlipperStorage, FlipperStorageOperations -from flipper.utils.cdc import resolve_port - import logging import os import pathlib -import serial.tools.list_ports as list_ports + +from flipper.app import App +from flipper.storage import FlipperStorage, FlipperStorageOperations +from flipper.utils.cdc import resolve_port class Main(App): @@ -54,7 +52,7 @@ def install(self): f"update install {flipper_update_path}/{manifest_name}\r" ) result = storage.read.until(storage.CLI_EOL) - if not b"Verifying" in result: + if b"Verifying" not in result: self.logger.error(f"Unexpected response: {result.decode('ascii')}") return 3 result = storage.read.until(storage.CLI_EOL) diff --git a/scripts/serial_cli.py b/scripts/serial_cli.py index 390b1f2638..2fa37d7512 100644 --- a/scripts/serial_cli.py +++ b/scripts/serial_cli.py @@ -1,9 +1,10 @@ import logging -import subprocess -from flipper.utils.cdc import resolve_port import os +import subprocess import sys +from flipper.utils.cdc import resolve_port + def main(): logger = logging.getLogger() diff --git a/scripts/storage.py b/scripts/storage.py index 84c01021a4..e04eaa7e1f 100755 --- a/scripts/storage.py +++ b/scripts/storage.py @@ -1,14 +1,14 @@ #!/usr/bin/env python3 -from flipper.app import App -from flipper.storage import FlipperStorage, FlipperStorageOperations -from flipper.utils.cdc import resolve_port - -import os import binascii import filecmp +import os import tempfile +from flipper.app import App +from flipper.storage import FlipperStorage, FlipperStorageOperations +from flipper.utils.cdc import resolve_port + def WrapStorageOp(func): def wrapper(*args, **kwargs): @@ -122,7 +122,7 @@ def read(self): try: print("Text data:") print(data.decode()) - except: + except Exception: print("Binary hexadecimal data:") print(binascii.hexlify(data).decode()) diff --git a/scripts/ufbt/SConstruct b/scripts/ufbt/SConstruct index ce7c8b9780..fdb51981be 100644 --- a/scripts/ufbt/SConstruct +++ b/scripts/ufbt/SConstruct @@ -1,7 +1,6 @@ from SCons.Platform import TempFileMunge from SCons.Node import FS from SCons.Errors import UserError -from SCons.Warnings import warn, WarningOnByDefault import os @@ -14,6 +13,7 @@ SetOption("max_drift", 1) ufbt_state_dir = Dir(os.environ.get("UFBT_STATE_DIR", "#.ufbt")) ufbt_script_dir = Dir(os.environ.get("UFBT_SCRIPT_DIR")) +ufbt_build_dir = ufbt_state_dir.Dir("build") ufbt_current_sdk_dir = ufbt_state_dir.Dir("current") @@ -63,16 +63,7 @@ core_env = Environment( ], ) -if "update" in BUILD_TARGETS: - SConscript( - "update.scons", - exports={"core_env": core_env}, - ) - -if "purge" in BUILD_TARGETS: - core_env.Execute(Delete(ufbt_state_dir)) - print("uFBT state purged") - Exit(0) +core_env.Append(CPPDEFINES=GetOption("extra_defines")) # Now we can import stuff bundled with SDK - it was added to sys.path by ufbt_state @@ -109,7 +100,7 @@ env = core_env.Clone( "fbt_assets", ("compilation_db", {"COMPILATIONDB_COMSTR": "\tCDB\t${TARGET}"}), ], - FBT_FAP_DEBUG_ELF_ROOT=ufbt_state_dir.Dir("build"), + FBT_FAP_DEBUG_ELF_ROOT=ufbt_build_dir, TEMPFILE=TempFileMunge, MAXLINELENGTH=2048, PROGSUFFIX=".elf", @@ -427,3 +418,25 @@ dist_env.PhonyTarget( "get_apiversion", "@echo $( ${UFBT_API_VERSION} $)", ) + +# Dolphin animation builder. Expects "external" directory in current dir +# with animation sources & manifests. Builds & uploads them to connected Flipper +dolphin_src_dir = original_app_dir.Dir("external") +if dolphin_src_dir.exists(): + dolphin_dir = ufbt_build_dir.Dir("dolphin") + dolphin_external = dist_env.DolphinExtBuilder( + ufbt_build_dir.Dir("dolphin"), + original_app_dir, + DOLPHIN_RES_TYPE="external", + ) + dist_env.PhonyTarget( + "dolphin_ext", + '${PYTHON3} ${FBT_SCRIPT_DIR}/storage.py send "${SOURCE}" /ext/dolphin', + source=ufbt_build_dir.Dir("dolphin"), + ) +else: + + def missing_dolphin_folder(**kw): + raise UserError(f"Dolphin folder not found: {dolphin_src_dir}") + + dist_env.PhonyTarget("dolphin_ext", Action(missing_dolphin_folder, None)) diff --git a/scripts/ufbt/commandline.scons b/scripts/ufbt/commandline.scons index 9af5e9bce9..a9b91bbca9 100644 --- a/scripts/ufbt/commandline.scons +++ b/scripts/ufbt/commandline.scons @@ -1,32 +1,18 @@ AddOption( - "--proxy-env", - action="store", - dest="proxy_env", - default="", - help="Comma-separated list of additional environment variables to pass to child SCons processes", + "--extra-define", + action="append", + dest="extra_defines", + default=[], + help="Extra global define that will be passed to C/C++ compiler, can be specified multiple times", ) AddOption( - "--channel", + "--proxy-env", action="store", - dest="sdk_channel", - choices=["dev", "rc", "release"], + dest="proxy_env", default="", - help="Release channel to use for SDK", -) - -AddOption( - "--branch", - action="store", - dest="sdk_branch", - help="Custom main repo branch to use for SDK", -) - -AddOption( - "--hw-target", - action="store", - dest="sdk_target", - help="SDK Hardware target", + help="Comma-separated list of additional environment variables to pass to " + "child SCons processes", ) vars = Variables("ufbt_options.py", ARGUMENTS) diff --git a/scripts/ufbt/site_init.py b/scripts/ufbt/site_init.py index 557085ede8..8e38a36e96 100644 --- a/scripts/ufbt/site_init.py +++ b/scripts/ufbt/site_init.py @@ -1,8 +1,8 @@ -from SCons.Script import GetBuildFailures -import SCons.Errors - import atexit + +import SCons.Errors from ansi.color import fg, fx +from SCons.Script import GetBuildFailures def bf_to_str(bf): diff --git a/scripts/ufbt/site_tools/ufbt_state.py b/scripts/ufbt/site_tools/ufbt_state.py index 76c6e9acfa..47f4afec4e 100644 --- a/scripts/ufbt/site_tools/ufbt_state.py +++ b/scripts/ufbt/site_tools/ufbt_state.py @@ -1,12 +1,11 @@ -from SCons.Errors import StopError -from SCons.Warnings import warn, WarningOnByDefault - import json import os -import sys import pathlib +import sys from functools import reduce +from SCons.Errors import StopError + def _load_sdk_data(sdk_root): split_vars = { diff --git a/scripts/ufbt/update.scons b/scripts/ufbt/update.scons deleted file mode 100644 index 9658e0bb20..0000000000 --- a/scripts/ufbt/update.scons +++ /dev/null @@ -1,37 +0,0 @@ -from SCons.Errors import StopError - -Import("core_env") - -update_env = core_env.Clone( - toolpath=[core_env["FBT_SCRIPT_DIR"].Dir("fbt_tools")], - tools=["python3"], -) -print("Updating SDK...") -ufbt_state = update_env["UFBT_STATE"] - -update_args = [ - "--ufbt-dir", - f'"{update_env["UFBT_STATE_DIR"]}"', -] - -if branch_name := GetOption("sdk_branch"): - update_args.extend(["--branch", branch_name]) -elif channel_name := GetOption("sdk_channel"): - update_args.extend(["--channel", channel_name]) -elif branch_name := ufbt_state.get("branch", None): - update_args.extend(["--branch", branch_name]) -elif channel_name := ufbt_state.get("channel", None): - update_args.extend(["--channel", channel_name]) -else: - raise StopError("No branch or channel specified for SDK update") - -if hw_target := GetOption("sdk_target"): - update_args.extend(["--hw-target", hw_target]) -else: - update_args.extend(["--hw-target", ufbt_state["hw_target"]]) - -update_env.Replace(UPDATE_ARGS=update_args) -result = update_env.Execute( - update_env.subst('$PYTHON3 "$UFBT_BOOTSTRAP_SCRIPT" $UPDATE_ARGS'), -) -Exit(result) diff --git a/scripts/update.py b/scripts/update.py index 2b01572605..0f3ee6ea8b 100755 --- a/scripts/update.py +++ b/scripts/update.py @@ -1,16 +1,16 @@ #!/usr/bin/env python3 -from flipper.app import App -from flipper.utils.fff import FlipperFormatFile -from flipper.assets.coprobin import CoproBinary, get_stack_type -from flipper.assets.obdata import OptionBytesData, ObReferenceValues -from os.path import basename, join, exists +import math import os import shutil -import zlib import tarfile -import math +import zlib +from os.path import exists, join +from flipper.app import App +from flipper.assets.coprobin import CoproBinary, get_stack_type +from flipper.assets.obdata import ObReferenceValues, OptionBytesData +from flipper.utils.fff import FlipperFormatFile from slideshow import Main as SlideshowMain @@ -267,9 +267,9 @@ def crc(fileName): @staticmethod def batch(iterable, n=1): - l = len(iterable) - for ndx in range(0, l, n): - yield iterable[ndx : min(ndx + n, l)] + iterable_len = len(iterable) + for ndx in range(0, iterable_len, n): + yield iterable[ndx : min(ndx + n, iterable_len)] if __name__ == "__main__": diff --git a/scripts/version.py b/scripts/version.py index 880a972813..71d201abb6 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -1,12 +1,12 @@ #!/usb/bin/env python3 -from flipper.app import App - -import subprocess -import os import json +import os +import subprocess from datetime import date, datetime +from flipper.app import App + class GitVersion: REVISION_SUFFIX_LENGTH = 8 diff --git a/site_scons/extapps.scons b/site_scons/extapps.scons index 89ee492429..6db0e538df 100644 --- a/site_scons/extapps.scons +++ b/site_scons/extapps.scons @@ -1,12 +1,12 @@ from dataclasses import dataclass, field +from fbt.appmanifest import FlipperAppType from SCons.Node import NodeList from SCons.Warnings import warn, WarningOnByDefault -from SCons.Errors import UserError + Import("ENV") -from fbt.appmanifest import FlipperAppType appenv = ENV["APPENV"] = ENV.Clone( tools=[ From 71e85ac36723663f1d153d46f682245d8ed4a58d Mon Sep 17 00:00:00 2001 From: Raymond Lucke Date: Wed, 3 May 2023 02:38:09 -0400 Subject: [PATCH 17/30] Add HID mouse auto-clicker. (#2627) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add HID mouse auto-clicker. * Add click rate adjustment to HID auto-clicker. * Fix formatting. * HidRemote: modify jiggler/clicker event filter and allow repeat to change click rate --------- Co-authored-by: あく --- applications/external/hid_app/hid.c | 22 ++ applications/external/hid_app/hid.h | 2 + applications/external/hid_app/views.h | 1 + .../hid_app/views/hid_mouse_clicker.c | 214 ++++++++++++++++++ .../hid_app/views/hid_mouse_clicker.h | 14 ++ .../hid_app/views/hid_mouse_jiggler.c | 2 +- 6 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 applications/external/hid_app/views/hid_mouse_clicker.c create mode 100644 applications/external/hid_app/views/hid_mouse_clicker.h diff --git a/applications/external/hid_app/hid.c b/applications/external/hid_app/hid.c index 949ff63b3e..a4f64589d7 100644 --- a/applications/external/hid_app/hid.c +++ b/applications/external/hid_app/hid.c @@ -11,6 +11,7 @@ enum HidDebugSubmenuIndex { HidSubmenuIndexMedia, HidSubmenuIndexTikTok, HidSubmenuIndexMouse, + HidSubmenuIndexMouseClicker, HidSubmenuIndexMouseJiggler, }; @@ -32,6 +33,9 @@ static void hid_submenu_callback(void* context, uint32_t index) { } else if(index == HidSubmenuIndexTikTok) { app->view_id = BtHidViewTikTok; view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewTikTok); + } else if(index == HidSubmenuIndexMouseClicker) { + app->view_id = HidViewMouseClicker; + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseClicker); } else if(index == HidSubmenuIndexMouseJiggler) { app->view_id = HidViewMouseJiggler; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseJiggler); @@ -53,6 +57,7 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con hid_keyboard_set_connected_status(hid->hid_keyboard, connected); hid_media_set_connected_status(hid->hid_media, connected); hid_mouse_set_connected_status(hid->hid_mouse, connected); + hid_mouse_clicker_set_connected_status(hid->hid_mouse_clicker, connected); hid_mouse_jiggler_set_connected_status(hid->hid_mouse_jiggler, connected); hid_tiktok_set_connected_status(hid->hid_tiktok, connected); } @@ -114,6 +119,12 @@ Hid* hid_alloc(HidTransport transport) { hid_submenu_callback, app); } + submenu_add_item( + app->device_type_submenu, + "Mouse Clicker", + HidSubmenuIndexMouseClicker, + hid_submenu_callback, + app); submenu_add_item( app->device_type_submenu, "Mouse Jiggler", @@ -172,6 +183,15 @@ Hid* hid_app_alloc_view(void* context) { view_dispatcher_add_view( app->view_dispatcher, HidViewMouse, hid_mouse_get_view(app->hid_mouse)); + // Mouse clicker view + app->hid_mouse_clicker = hid_mouse_clicker_alloc(app); + view_set_previous_callback( + hid_mouse_clicker_get_view(app->hid_mouse_clicker), hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, + HidViewMouseClicker, + hid_mouse_clicker_get_view(app->hid_mouse_clicker)); + // Mouse jiggler view app->hid_mouse_jiggler = hid_mouse_jiggler_alloc(app); view_set_previous_callback( @@ -205,6 +225,8 @@ void hid_free(Hid* app) { hid_media_free(app->hid_media); view_dispatcher_remove_view(app->view_dispatcher, HidViewMouse); hid_mouse_free(app->hid_mouse); + view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseClicker); + hid_mouse_clicker_free(app->hid_mouse_clicker); view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseJiggler); hid_mouse_jiggler_free(app->hid_mouse_jiggler); view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok); diff --git a/applications/external/hid_app/hid.h b/applications/external/hid_app/hid.h index 8ed1664a34..49d8b4e045 100644 --- a/applications/external/hid_app/hid.h +++ b/applications/external/hid_app/hid.h @@ -20,6 +20,7 @@ #include "views/hid_keyboard.h" #include "views/hid_media.h" #include "views/hid_mouse.h" +#include "views/hid_mouse_clicker.h" #include "views/hid_mouse_jiggler.h" #include "views/hid_tiktok.h" @@ -43,6 +44,7 @@ struct Hid { HidKeyboard* hid_keyboard; HidMedia* hid_media; HidMouse* hid_mouse; + HidMouseClicker* hid_mouse_clicker; HidMouseJiggler* hid_mouse_jiggler; HidTikTok* hid_tiktok; diff --git a/applications/external/hid_app/views.h b/applications/external/hid_app/views.h index 2a44832e12..1bea3355e0 100644 --- a/applications/external/hid_app/views.h +++ b/applications/external/hid_app/views.h @@ -4,6 +4,7 @@ typedef enum { HidViewKeyboard, HidViewMedia, HidViewMouse, + HidViewMouseClicker, HidViewMouseJiggler, BtHidViewTikTok, HidViewExitConfirm, diff --git a/applications/external/hid_app/views/hid_mouse_clicker.c b/applications/external/hid_app/views/hid_mouse_clicker.c new file mode 100644 index 0000000000..d85affc433 --- /dev/null +++ b/applications/external/hid_app/views/hid_mouse_clicker.c @@ -0,0 +1,214 @@ +#include "hid_mouse_clicker.h" +#include +#include "../hid.h" + +#include "hid_icons.h" + +#define TAG "HidMouseClicker" +#define DEFAULT_CLICK_RATE 1 +#define MAXIMUM_CLICK_RATE 60 + +struct HidMouseClicker { + View* view; + Hid* hid; + FuriTimer* timer; +}; + +typedef struct { + bool connected; + bool running; + int rate; + HidTransport transport; +} HidMouseClickerModel; + +static void hid_mouse_clicker_start_or_restart_timer(void* context) { + furi_assert(context); + HidMouseClicker* hid_mouse_clicker = context; + + if(furi_timer_is_running(hid_mouse_clicker->timer)) { + furi_timer_stop(hid_mouse_clicker->timer); + } + + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { + furi_timer_start( + hid_mouse_clicker->timer, furi_kernel_get_tick_frequency() / model->rate); + }, + true); +} + +static void hid_mouse_clicker_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + HidMouseClickerModel* model = context; + + // Header + if(model->transport == HidTransportBle) { + if(model->connected) { + canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); + } else { + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); + } + } + + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse Clicker"); + + // Ok + canvas_draw_icon(canvas, 63, 25, &I_Space_65x18); + if(model->running) { + canvas_set_font(canvas, FontPrimary); + + FuriString* rate_label = furi_string_alloc(); + furi_string_printf(rate_label, "%d clicks/s\n\nUp / Down", model->rate); + elements_multiline_text(canvas, AlignLeft, 35, furi_string_get_cstr(rate_label)); + canvas_set_font(canvas, FontSecondary); + furi_string_free(rate_label); + + elements_slightly_rounded_box(canvas, 66, 27, 60, 13); + canvas_set_color(canvas, ColorWhite); + } else { + canvas_set_font(canvas, FontPrimary); + elements_multiline_text(canvas, AlignLeft, 35, "Press Start\nto start\nclicking"); + canvas_set_font(canvas, FontSecondary); + } + canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9); + if(model->running) { + elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Stop"); + } else { + elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Start"); + } + canvas_set_color(canvas, ColorBlack); + + // Back + canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8); + elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Quit"); +} + +static void hid_mouse_clicker_timer_callback(void* context) { + furi_assert(context); + HidMouseClicker* hid_mouse_clicker = context; + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { + if(model->running) { + hid_hal_mouse_press(hid_mouse_clicker->hid, HID_MOUSE_BTN_LEFT); + hid_hal_mouse_release(hid_mouse_clicker->hid, HID_MOUSE_BTN_LEFT); + } + }, + false); +} + +static void hid_mouse_clicker_enter_callback(void* context) { + hid_mouse_clicker_start_or_restart_timer(context); +} + +static void hid_mouse_clicker_exit_callback(void* context) { + furi_assert(context); + HidMouseClicker* hid_mouse_clicker = context; + furi_timer_stop(hid_mouse_clicker->timer); +} + +static bool hid_mouse_clicker_input_callback(InputEvent* event, void* context) { + furi_assert(context); + HidMouseClicker* hid_mouse_clicker = context; + + bool consumed = false; + bool rate_changed = false; + + if(event->type != InputTypeShort && event->type != InputTypeRepeat) { + return false; + } + + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { + switch(event->key) { + case InputKeyOk: + model->running = !model->running; + consumed = true; + break; + case InputKeyUp: + if(model->rate < MAXIMUM_CLICK_RATE) { + model->rate++; + } + rate_changed = true; + consumed = true; + break; + case InputKeyDown: + if(model->rate > 1) { + model->rate--; + } + rate_changed = true; + consumed = true; + break; + default: + consumed = true; + break; + } + }, + true); + + if(rate_changed) { + hid_mouse_clicker_start_or_restart_timer(context); + } + + return consumed; +} + +HidMouseClicker* hid_mouse_clicker_alloc(Hid* hid) { + HidMouseClicker* hid_mouse_clicker = malloc(sizeof(HidMouseClicker)); + + hid_mouse_clicker->view = view_alloc(); + view_set_context(hid_mouse_clicker->view, hid_mouse_clicker); + view_allocate_model( + hid_mouse_clicker->view, ViewModelTypeLocking, sizeof(HidMouseClickerModel)); + view_set_draw_callback(hid_mouse_clicker->view, hid_mouse_clicker_draw_callback); + view_set_input_callback(hid_mouse_clicker->view, hid_mouse_clicker_input_callback); + view_set_enter_callback(hid_mouse_clicker->view, hid_mouse_clicker_enter_callback); + view_set_exit_callback(hid_mouse_clicker->view, hid_mouse_clicker_exit_callback); + + hid_mouse_clicker->hid = hid; + + hid_mouse_clicker->timer = furi_timer_alloc( + hid_mouse_clicker_timer_callback, FuriTimerTypePeriodic, hid_mouse_clicker); + + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { + model->transport = hid->transport; + model->rate = DEFAULT_CLICK_RATE; + }, + true); + + return hid_mouse_clicker; +} + +void hid_mouse_clicker_free(HidMouseClicker* hid_mouse_clicker) { + furi_assert(hid_mouse_clicker); + + furi_timer_stop(hid_mouse_clicker->timer); + furi_timer_free(hid_mouse_clicker->timer); + + view_free(hid_mouse_clicker->view); + + free(hid_mouse_clicker); +} + +View* hid_mouse_clicker_get_view(HidMouseClicker* hid_mouse_clicker) { + furi_assert(hid_mouse_clicker); + return hid_mouse_clicker->view; +} + +void hid_mouse_clicker_set_connected_status(HidMouseClicker* hid_mouse_clicker, bool connected) { + furi_assert(hid_mouse_clicker); + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { model->connected = connected; }, + true); +} diff --git a/applications/external/hid_app/views/hid_mouse_clicker.h b/applications/external/hid_app/views/hid_mouse_clicker.h new file mode 100644 index 0000000000..d72847baa7 --- /dev/null +++ b/applications/external/hid_app/views/hid_mouse_clicker.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +typedef struct Hid Hid; +typedef struct HidMouseClicker HidMouseClicker; + +HidMouseClicker* hid_mouse_clicker_alloc(Hid* bt_hid); + +void hid_mouse_clicker_free(HidMouseClicker* hid_mouse_clicker); + +View* hid_mouse_clicker_get_view(HidMouseClicker* hid_mouse_clicker); + +void hid_mouse_clicker_set_connected_status(HidMouseClicker* hid_mouse_clicker, bool connected); diff --git a/applications/external/hid_app/views/hid_mouse_jiggler.c b/applications/external/hid_app/views/hid_mouse_jiggler.c index d8f1f89286..15547eb26b 100644 --- a/applications/external/hid_app/views/hid_mouse_jiggler.c +++ b/applications/external/hid_app/views/hid_mouse_jiggler.c @@ -95,7 +95,7 @@ static bool hid_mouse_jiggler_input_callback(InputEvent* event, void* context) { bool consumed = false; - if(event->key == InputKeyOk) { + if(event->type == InputTypeShort && event->key == InputKeyOk) { with_view_model( hid_mouse_jiggler->view, HidMouseJigglerModel * model, From d110a3ef262e69c7c31755f21048aa7ac4a02469 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 3 May 2023 18:48:13 +0300 Subject: [PATCH 18/30] Update wifi marauder version --- .../external/wifi_marauder_companion/wifi_marauder_app.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app.h b/applications/external/wifi_marauder_companion/wifi_marauder_app.h index 89a06f904e..2f8b2f9a6b 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app.h @@ -4,7 +4,7 @@ extern "C" { #endif -#define WIFI_MARAUDER_APP_VERSION "v0.3.3" +#define WIFI_MARAUDER_APP_VERSION "v0.3.4" typedef struct WifiMarauderApp WifiMarauderApp; From 30f79f838ecf5472be407aefaab27bef67f6f861 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 3 May 2023 20:16:20 +0300 Subject: [PATCH 19/30] rename --- applications/external/hid_app/hid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/external/hid_app/hid.c b/applications/external/hid_app/hid.c index 52f4708fbb..f4f59b435b 100644 --- a/applications/external/hid_app/hid.c +++ b/applications/external/hid_app/hid.c @@ -129,7 +129,7 @@ Hid* hid_alloc(HidTransport transport) { submenu_add_item( app->device_type_submenu, "Keyboard", HidSubmenuIndexKeyboard, hid_submenu_callback, app); submenu_add_item( - app->device_type_submenu, "Numpad keyboard", HidSubmenuIndexNumpad, hid_submenu_callback, app); + app->device_type_submenu, "Numpad", HidSubmenuIndexNumpad, hid_submenu_callback, app); submenu_add_item( app->device_type_submenu, "Media", HidSubmenuIndexMedia, hid_submenu_callback, app); submenu_add_item( From 6874b3b4295b68c1035845cdc7a2c4912ea5cde3 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 3 May 2023 21:53:44 +0300 Subject: [PATCH 20/30] We don't use region provision so remove 00 from about screens --- applications/services/desktop/views/desktop_view_debug.c | 3 +-- applications/settings/about/about.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/applications/services/desktop/views/desktop_view_debug.c b/applications/services/desktop/views/desktop_view_debug.c index 8c72001b42..1fe9577127 100644 --- a/applications/services/desktop/views/desktop_view_debug.c +++ b/applications/services/desktop/views/desktop_view_debug.c @@ -37,13 +37,12 @@ void desktop_debug_render(Canvas* canvas, void* model) { snprintf( buffer, sizeof(buffer), - "%d.F%dB%dC%d %s:%s %s", + "%d.F%dB%dC%d %s %s", furi_hal_version_get_hw_version(), furi_hal_version_get_hw_target(), furi_hal_version_get_hw_body(), furi_hal_version_get_hw_connect(), furi_hal_version_get_hw_region_name_otp(), - furi_hal_region_get_name(), my_name ? my_name : "Unknown"); canvas_draw_str(canvas, 0, 19 + STATUS_BAR_Y_SHIFT, buffer); diff --git a/applications/settings/about/about.c b/applications/settings/about/about.c index 7d6724dc20..49f30ef9ca 100644 --- a/applications/settings/about/about.c +++ b/applications/settings/about/about.c @@ -127,13 +127,12 @@ static DialogMessageButton hw_version_screen(DialogsApp* dialogs, DialogMessage* furi_string_cat_printf( buffer, - "%d.F%dB%dC%d %s:%s %s\n", + "%d.F%dB%dC%d %s %s\n", furi_hal_version_get_hw_version(), furi_hal_version_get_hw_target(), furi_hal_version_get_hw_body(), furi_hal_version_get_hw_connect(), furi_hal_version_get_hw_region_name_otp(), - furi_hal_region_get_name(), my_name ? my_name : "Unknown"); furi_string_cat_printf(buffer, "Serial Number:\n"); From 3a51b3f70c110350f5366a2755af6abb394054ef Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 3 May 2023 21:58:07 +0300 Subject: [PATCH 21/30] Update changelog --- CHANGELOG.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a861b0a0f..37c6260e04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,12 @@ ### New changes -* NFC: Temp fix for Detect reader not collecting nonces -* Desktop: Temp fix for old backlight bug when locking by holding up arrow -* IR: Add Sharp and Vizio to Universal TV remote -* BLE Info: Show version instead of branch -* Plugins: Add new game - Bomberduck (by @leo-need-more-coffee | PR #450) -* Plugins: Fix `SWD Probe` plugin GPIO pins state reset on exit -* Plugins: Bluetooth Remote - new UI (by @krolchonok | PR #447) -* Plugins: Update **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator) -* Docs: Update HowToInstall (by @krolchonok | PR #443) -* OFW PR 2627: Add HID mouse auto-clicker (by @rwl4) +* Plugins: Added Numpad keyboard to HID app (by @clipboard1 | PR #452) +* Infrared: Updated universal remote assets (by @amec0e | PR #454) +* Update slideshow: Replace QR code with good old link +* OFW: Dolphin builder in ufbt; minor ufbt/fbt improvements +* OFW: Added API version to device info +* OFW: Gui: relax some asserts in view +* OFW: Move gauge calibration to separate header, add f18 calibration +* OFW: Fix TERMINFO on Linux systems #### [🎲 Download latest extra apps pack](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip) From d2ca67d261217f445abaf9b3cb0926250d1385a9 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Thu, 4 May 2023 07:04:26 +0400 Subject: [PATCH 22/30] [FL-3242] SubGhz: refactoring app (#2554) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: add SubGhzThresholdRssi * SubGhz: remove direct reading of subghz-txrx-txrx_state * SubGhz: remove direct reading subghz->txrx->hopper_state * SubGhz: remove direct reading subghz->lock * SubGhz: check load type file * SubGhz: remove direct reading subghz->txrx->rx_key_state * SubGhz: remove direct reading subghz->txrx->speaker_state * SubGhz: refactoring subghz_scene_set_type.c * SubGhz: moving "txrx" entity to a separate file * SubGhz: show error tx start * SubGhz: refactoring RPC * SubGhz: value get optimizations * SubGhz: fix name file * SubGhz: add function description * SubGhz: fix double back with a blocked transmission in this region and speacker, when a transmission is blocked in this region * SubGhz: correct spelling * SubGhz: better naming * SubGhz: simplify includes Co-authored-by: SG Co-authored-by: あく --- .../views/weather_station_receiver.c | 6 +- .../main/subghz/helpers/subghz_custom_event.h | 5 +- .../subghz_frequency_analyzer_worker.c | 2 +- .../subghz/helpers/subghz_threshold_rssi.c | 60 ++ .../subghz/helpers/subghz_threshold_rssi.h | 43 ++ .../main/subghz/helpers/subghz_txrx.c | 521 ++++++++++++++++++ .../main/subghz/helpers/subghz_txrx.h | 290 ++++++++++ .../helpers/subghz_txrx_create_potocol_key.c | 164 ++++++ .../helpers/subghz_txrx_create_potocol_key.h | 96 ++++ .../main/subghz/helpers/subghz_txrx_i.h | 27 + .../main/subghz/helpers/subghz_types.h | 7 + .../main/subghz/scenes/subghz_scene_delete.c | 4 +- .../subghz/scenes/subghz_scene_delete_raw.c | 2 +- .../subghz/scenes/subghz_scene_need_saving.c | 18 +- .../subghz/scenes/subghz_scene_read_raw.c | 229 +++----- .../subghz/scenes/subghz_scene_receiver.c | 122 ++-- .../scenes/subghz_scene_receiver_config.c | 133 +++-- .../scenes/subghz_scene_receiver_info.c | 112 ++-- .../subghz/scenes/subghz_scene_region_info.c | 3 +- .../main/subghz/scenes/subghz_scene_rpc.c | 20 +- .../subghz/scenes/subghz_scene_save_name.c | 16 +- .../subghz/scenes/subghz_scene_save_success.c | 4 +- .../main/subghz/scenes/subghz_scene_saved.c | 4 +- .../subghz/scenes/subghz_scene_set_type.c | 255 ++------- .../subghz/scenes/subghz_scene_show_error.c | 11 +- .../main/subghz/scenes/subghz_scene_start.c | 2 +- .../subghz/scenes/subghz_scene_transmitter.c | 46 +- applications/main/subghz/subghz.c | 95 +--- applications/main/subghz/subghz_i.c | 403 +++----------- applications/main/subghz/subghz_i.h | 76 +-- applications/main/subghz/views/receiver.c | 23 +- applications/main/subghz/views/receiver.h | 2 +- .../main/subghz/views/subghz_read_raw.c | 8 +- .../main/subghz/views/subghz_read_raw.h | 2 +- applications/main/subghz/views/transmitter.c | 6 +- applications/main/subghz/views/transmitter.h | 2 +- lib/subghz/environment.c | 2 + 37 files changed, 1704 insertions(+), 1117 deletions(-) create mode 100644 applications/main/subghz/helpers/subghz_threshold_rssi.c create mode 100644 applications/main/subghz/helpers/subghz_threshold_rssi.h create mode 100644 applications/main/subghz/helpers/subghz_txrx.c create mode 100644 applications/main/subghz/helpers/subghz_txrx.h create mode 100644 applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c create mode 100644 applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h create mode 100644 applications/main/subghz/helpers/subghz_txrx_i.h diff --git a/applications/external/weather_station/views/weather_station_receiver.c b/applications/external/weather_station/views/weather_station_receiver.c index f8e2e32889..c4ce1627ec 100644 --- a/applications/external/weather_station/views/weather_station_receiver.c +++ b/applications/external/weather_station/views/weather_station_receiver.c @@ -12,7 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; uint8_t type; @@ -69,10 +69,10 @@ void ws_view_receiver_set_rssi(WSReceiver* instance, float rssi) { instance->view, WSReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index 765c9e251c..285b4a60f9 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -6,14 +6,13 @@ typedef enum { SubGhzCustomEventManagerSetRAW, //SubmenuIndex - SubmenuIndexPricenton, + SubmenuIndexPricenton_433, + SubmenuIndexPricenton_315, SubmenuIndexNiceFlo12bit, SubmenuIndexNiceFlo24bit, SubmenuIndexCAME12bit, SubmenuIndexCAME24bit, SubmenuIndexCAMETwee, - SubmenuIndexNeroSketch, - SubmenuIndexNeroRadio, SubmenuIndexGateTX, SubmenuIndexDoorHan_315_00, SubmenuIndexDoorHan_433_92, diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c index 5d1a80a395..4a4445faad 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c @@ -261,7 +261,7 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc(void* cont instance->thread = furi_thread_alloc_ex( "SubGhzFAWorker", 2048, subghz_frequency_analyzer_worker_thread, instance); SubGhz* subghz = context; - instance->setting = subghz->setting; + instance->setting = subghz_txrx_get_setting(subghz->txrx); return instance; } diff --git a/applications/main/subghz/helpers/subghz_threshold_rssi.c b/applications/main/subghz/helpers/subghz_threshold_rssi.c new file mode 100644 index 0000000000..04a06bc173 --- /dev/null +++ b/applications/main/subghz/helpers/subghz_threshold_rssi.c @@ -0,0 +1,60 @@ +#include "subghz_threshold_rssi.h" +#include +#include "../subghz_i.h" + +#define TAG "SubGhzThresholdRssi" +#define THRESHOLD_RSSI_LOW_COUNT 10 + +struct SubGhzThresholdRssi { + float threshold_rssi; + uint8_t threshold_rssi_low_count; +}; + +SubGhzThresholdRssi* subghz_threshold_rssi_alloc(void) { + SubGhzThresholdRssi* instance = malloc(sizeof(SubGhzThresholdRssi)); + instance->threshold_rssi = SUBGHZ_RAW_THRESHOLD_MIN; + instance->threshold_rssi_low_count = THRESHOLD_RSSI_LOW_COUNT; + return instance; +} + +void subghz_threshold_rssi_free(SubGhzThresholdRssi* instance) { + furi_assert(instance); + free(instance); +} + +void subghz_threshold_rssi_set(SubGhzThresholdRssi* instance, float rssi) { + furi_assert(instance); + instance->threshold_rssi = rssi; +} + +float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance) { + furi_assert(instance); + return instance->threshold_rssi; +} + +SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance) { + furi_assert(instance); + float rssi = furi_hal_subghz_get_rssi(); + SubGhzThresholdRssiData ret = {.rssi = rssi, .is_above = false}; + + if(float_is_equal(instance->threshold_rssi, SUBGHZ_RAW_THRESHOLD_MIN)) { + ret.is_above = true; + } else { + if(rssi < instance->threshold_rssi) { + instance->threshold_rssi_low_count++; + if(instance->threshold_rssi_low_count > THRESHOLD_RSSI_LOW_COUNT) { + instance->threshold_rssi_low_count = THRESHOLD_RSSI_LOW_COUNT; + } + ret.is_above = false; + } else { + instance->threshold_rssi_low_count = 0; + } + + if(instance->threshold_rssi_low_count == THRESHOLD_RSSI_LOW_COUNT) { + ret.is_above = false; + } else { + ret.is_above = true; + } + } + return ret; +} diff --git a/applications/main/subghz/helpers/subghz_threshold_rssi.h b/applications/main/subghz/helpers/subghz_threshold_rssi.h new file mode 100644 index 0000000000..e28092acbc --- /dev/null +++ b/applications/main/subghz/helpers/subghz_threshold_rssi.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +typedef struct { + float rssi; /**< Current RSSI */ + bool is_above; /**< Exceeded threshold level */ +} SubGhzThresholdRssiData; + +typedef struct SubGhzThresholdRssi SubGhzThresholdRssi; + +/** Allocate SubGhzThresholdRssi + * + * @return SubGhzThresholdRssi* + */ +SubGhzThresholdRssi* subghz_threshold_rssi_alloc(void); + +/** Free SubGhzThresholdRssi + * + * @param instance Pointer to a SubGhzThresholdRssi + */ +void subghz_threshold_rssi_free(SubGhzThresholdRssi* instance); + +/** Set threshold + * + * @param instance Pointer to a SubGhzThresholdRssi + * @param rssi RSSI threshold + */ +void subghz_threshold_rssi_set(SubGhzThresholdRssi* instance, float rssi); + +/** Get threshold + * + * @param instance Pointer to a SubGhzThresholdRssi + * @return float RSSI threshold + */ +float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance); + +/** Check threshold + * + * @param instance Pointer to a SubGhzThresholdRssi + * @return SubGhzThresholdRssiData + */ +SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance); diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c new file mode 100644 index 0000000000..1517cb9989 --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -0,0 +1,521 @@ +#include "subghz_txrx_i.h" + +#include + +#define TAG "SubGhz" + +SubGhzTxRx* subghz_txrx_alloc() { + SubGhzTxRx* instance = malloc(sizeof(SubGhzTxRx)); + instance->setting = subghz_setting_alloc(); + subghz_setting_load(instance->setting, EXT_PATH("subghz/assets/setting_user")); + + instance->preset = malloc(sizeof(SubGhzRadioPreset)); + instance->preset->name = furi_string_alloc(); + subghz_txrx_set_preset( + instance, "AM650", subghz_setting_get_default_frequency(instance->setting), NULL, 0); + + instance->txrx_state = SubGhzTxRxStateSleep; + + subghz_txrx_hopper_set_state(instance, SubGhzHopperStateOFF); + subghz_txrx_speaker_set_state(instance, SubGhzSpeakerStateDisable); + + instance->worker = subghz_worker_alloc(); + instance->fff_data = flipper_format_string_alloc(); + + instance->environment = subghz_environment_alloc(); + instance->is_database_loaded = subghz_environment_load_keystore( + instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); + subghz_environment_load_keystore( + instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); + subghz_environment_set_came_atomo_rainbow_table_file_name( + instance->environment, EXT_PATH("subghz/assets/came_atomo")); + subghz_environment_set_alutech_at_4n_rainbow_table_file_name( + instance->environment, EXT_PATH("subghz/assets/alutech_at_4n")); + subghz_environment_set_nice_flor_s_rainbow_table_file_name( + instance->environment, EXT_PATH("subghz/assets/nice_flor_s")); + subghz_environment_set_protocol_registry( + instance->environment, (void*)&subghz_protocol_registry); + instance->receiver = subghz_receiver_alloc_init(instance->environment); + + subghz_worker_set_overrun_callback( + instance->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); + subghz_worker_set_pair_callback( + instance->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); + subghz_worker_set_context(instance->worker, instance->receiver); + + return instance; +} + +void subghz_txrx_free(SubGhzTxRx* instance) { + furi_assert(instance); + + subghz_worker_free(instance->worker); + subghz_receiver_free(instance->receiver); + subghz_environment_free(instance->environment); + flipper_format_free(instance->fff_data); + furi_string_free(instance->preset->name); + subghz_setting_free(instance->setting); + free(instance->preset); + free(instance); +} + +bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->is_database_loaded; +} + +void subghz_txrx_set_preset( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + uint8_t* preset_data, + size_t preset_data_size) { + furi_assert(instance); + furi_string_set(instance->preset->name, preset_name); + SubGhzRadioPreset* preset = instance->preset; + preset->frequency = frequency; + preset->data = preset_data; + preset->data_size = preset_data_size; +} + +const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset) { + UNUSED(instance); + const char* preset_name = ""; + if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { + preset_name = "AM270"; + } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { + preset_name = "AM650"; + } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { + preset_name = "FM238"; + } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { + preset_name = "FM476"; + } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { + preset_name = "CUSTOM"; + } else { + FURI_LOG_E(TAG, "Unknown preset"); + } + return preset_name; +} + +SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance) { + furi_assert(instance); + return *instance->preset; +} + +void subghz_txrx_get_frequency_and_modulation( + SubGhzTxRx* instance, + FuriString* frequency, + FuriString* modulation) { + furi_assert(instance); + SubGhzRadioPreset* preset = instance->preset; + if(frequency != NULL) { + furi_string_printf( + frequency, + "%03ld.%02ld", + preset->frequency / 1000000 % 1000, + preset->frequency / 10000 % 100); + } + if(modulation != NULL) { + furi_string_printf(modulation, "%.2s", furi_string_get_cstr(preset->name)); + } +} + +static void subghz_txrx_begin(SubGhzTxRx* instance, uint8_t* preset_data) { + furi_assert(instance); + furi_hal_subghz_reset(); + furi_hal_subghz_idle(); + furi_hal_subghz_load_custom_preset(preset_data); + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + instance->txrx_state = SubGhzTxRxStateIDLE; +} + +static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) { + furi_assert(instance); + if(!furi_hal_subghz_is_frequency_valid(frequency)) { + furi_crash("SubGhz: Incorrect RX frequency."); + } + furi_assert( + instance->txrx_state != SubGhzTxRxStateRx && instance->txrx_state != SubGhzTxRxStateSleep); + + furi_hal_subghz_idle(); + uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_subghz_flush_rx(); + subghz_txrx_speaker_on(instance); + furi_hal_subghz_rx(); + + furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, instance->worker); + subghz_worker_start(instance->worker); + instance->txrx_state = SubGhzTxRxStateRx; + return value; +} + +static void subghz_txrx_idle(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state != SubGhzTxRxStateSleep); + furi_hal_subghz_idle(); + subghz_txrx_speaker_off(instance); + instance->txrx_state = SubGhzTxRxStateIDLE; +} + +static void subghz_txrx_rx_end(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state == SubGhzTxRxStateRx); + + if(subghz_worker_is_running(instance->worker)) { + subghz_worker_stop(instance->worker); + furi_hal_subghz_stop_async_rx(); + } + furi_hal_subghz_idle(); + subghz_txrx_speaker_off(instance); + instance->txrx_state = SubGhzTxRxStateIDLE; +} + +void subghz_txrx_sleep(SubGhzTxRx* instance) { + furi_assert(instance); + furi_hal_subghz_sleep(); + instance->txrx_state = SubGhzTxRxStateSleep; +} + +static bool subghz_txrx_tx(SubGhzTxRx* instance, uint32_t frequency) { + furi_assert(instance); + if(!furi_hal_subghz_is_frequency_valid(frequency)) { + furi_crash("SubGhz: Incorrect TX frequency."); + } + furi_assert(instance->txrx_state != SubGhzTxRxStateSleep); + furi_hal_subghz_idle(); + furi_hal_subghz_set_frequency_and_path(frequency); + furi_hal_gpio_write(&gpio_cc1101_g0, false); + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + bool ret = furi_hal_subghz_tx(); + if(ret) { + subghz_txrx_speaker_on(instance); + instance->txrx_state = SubGhzTxRxStateTx; + } + + return ret; +} + +SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format) { + furi_assert(instance); + furi_assert(flipper_format); + + subghz_txrx_stop(instance); + + SubGhzTxRxStartTxState ret = SubGhzTxRxStartTxStateErrorParserOthers; + FuriString* temp_str = furi_string_alloc(); + uint32_t repeat = 200; + do { + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) { + FURI_LOG_E(TAG, "Missing Protocol"); + break; + } + if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable Repeat"); + break; + } + ret = SubGhzTxRxStartTxStateOk; + + SubGhzRadioPreset* preset = instance->preset; + instance->transmitter = + subghz_transmitter_alloc_init(instance->environment, furi_string_get_cstr(temp_str)); + + if(instance->transmitter) { + if(subghz_transmitter_deserialize(instance->transmitter, flipper_format) == + SubGhzProtocolStatusOk) { + if(strcmp(furi_string_get_cstr(preset->name), "") != 0) { + subghz_txrx_begin( + instance, + subghz_setting_get_preset_data_by_name( + instance->setting, furi_string_get_cstr(preset->name))); + if(preset->frequency) { + if(!subghz_txrx_tx(instance, preset->frequency)) { + FURI_LOG_E(TAG, "Only Rx"); + ret = SubGhzTxRxStartTxStateErrorOnlyRx; + } + } else { + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + + } else { + FURI_LOG_E( + TAG, "Unknown name preset \" %s \"", furi_string_get_cstr(preset->name)); + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + + if(ret == SubGhzTxRxStartTxStateOk) { + //Start TX + furi_hal_subghz_start_async_tx( + subghz_transmitter_yield, instance->transmitter); + } + } else { + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + } else { + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + if(ret != SubGhzTxRxStartTxStateOk) { + subghz_transmitter_free(instance->transmitter); + if(instance->txrx_state != SubGhzTxRxStateIDLE) { + subghz_txrx_idle(instance); + } + } + + } while(false); + furi_string_free(temp_str); + return ret; +} + +void subghz_txrx_rx_start(SubGhzTxRx* instance) { + furi_assert(instance); + subghz_txrx_stop(instance); + subghz_txrx_begin( + instance, + subghz_setting_get_preset_data_by_name( + subghz_txrx_get_setting(instance), furi_string_get_cstr(instance->preset->name))); + subghz_txrx_rx(instance, instance->preset->frequency); +} + +void subghz_txrx_set_need_save_callback( + SubGhzTxRx* instance, + SubGhzTxRxNeedSaveCallback callback, + void* context) { + furi_assert(instance); + instance->need_save_callback = callback; + instance->need_save_context = context; +} + +static void subghz_txrx_tx_stop(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state == SubGhzTxRxStateTx); + //Stop TX + furi_hal_subghz_stop_async_tx(); + subghz_transmitter_stop(instance->transmitter); + subghz_transmitter_free(instance->transmitter); + + //if protocol dynamic then we save the last upload + if(instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) { + if(instance->need_save_callback) { + instance->need_save_callback(instance->need_save_context); + } + } + subghz_txrx_idle(instance); + subghz_txrx_speaker_off(instance); + //Todo: Show message + // notification_message(notifications, &sequence_reset_red); +} + +FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->fff_data; +} + +SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->setting; +} + +void subghz_txrx_stop(SubGhzTxRx* instance) { + furi_assert(instance); + + switch(instance->txrx_state) { + case SubGhzTxRxStateTx: + subghz_txrx_tx_stop(instance); + subghz_txrx_speaker_unmute(instance); + break; + case SubGhzTxRxStateRx: + subghz_txrx_rx_end(instance); + subghz_txrx_speaker_mute(instance); + break; + + default: + break; + } +} + +void subghz_txrx_hopper_update(SubGhzTxRx* instance) { + furi_assert(instance); + + switch(instance->hopper_state) { + case SubGhzHopperStateOFF: + case SubGhzHopperStatePause: + return; + case SubGhzHopperStateRSSITimeOut: + if(instance->hopper_timeout != 0) { + instance->hopper_timeout--; + return; + } + break; + default: + break; + } + float rssi = -127.0f; + if(instance->hopper_state != SubGhzHopperStateRSSITimeOut) { + // See RSSI Calculation timings in CC1101 17.3 RSSI + rssi = furi_hal_subghz_get_rssi(); + + // Stay if RSSI is high enough + if(rssi > -90.0f) { + instance->hopper_timeout = 10; + instance->hopper_state = SubGhzHopperStateRSSITimeOut; + return; + } + } else { + instance->hopper_state = SubGhzHopperStateRunnig; + } + // Select next frequency + if(instance->hopper_idx_frequency < + subghz_setting_get_hopper_frequency_count(instance->setting) - 1) { + instance->hopper_idx_frequency++; + } else { + instance->hopper_idx_frequency = 0; + } + + if(instance->txrx_state == SubGhzTxRxStateRx) { + subghz_txrx_rx_end(instance); + }; + if(instance->txrx_state == SubGhzTxRxStateIDLE) { + subghz_receiver_reset(instance->receiver); + instance->preset->frequency = + subghz_setting_get_hopper_frequency(instance->setting, instance->hopper_idx_frequency); + subghz_txrx_rx(instance, instance->preset->frequency); + } +} + +SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->hopper_state; +} + +void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state) { + furi_assert(instance); + instance->hopper_state = state; +} + +void subghz_txrx_hopper_unpause(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->hopper_state == SubGhzHopperStatePause) { + instance->hopper_state = SubGhzHopperStateRunnig; + } +} + +void subghz_txrx_hopper_pause(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->hopper_state == SubGhzHopperStateRunnig) { + instance->hopper_state = SubGhzHopperStatePause; + } +} + +void subghz_txrx_speaker_on(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_acquire(30)) { + furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + } else { + instance->speaker_state = SubGhzSpeakerStateDisable; + } + } +} + +void subghz_txrx_speaker_off(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->speaker_state != SubGhzSpeakerStateDisable) { + if(furi_hal_speaker_is_mine()) { + furi_hal_subghz_set_async_mirror_pin(NULL); + furi_hal_speaker_release(); + if(instance->speaker_state == SubGhzSpeakerStateShutdown) + instance->speaker_state = SubGhzSpeakerStateDisable; + } + } +} + +void subghz_txrx_speaker_mute(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_is_mine()) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } + } +} + +void subghz_txrx_speaker_unmute(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_is_mine()) { + furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + } + } +} + +void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state) { + furi_assert(instance); + instance->speaker_state = state; +} + +SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->speaker_state; +} + +bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol) { + furi_assert(instance); + furi_assert(name_protocol); + bool res = false; + instance->decoder_result = + subghz_receiver_search_decoder_base_by_name(instance->receiver, name_protocol); + if(instance->decoder_result) { + res = true; + } + return res; +} + +SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->decoder_result; +} + +bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance) { + furi_assert(instance); + return ( + (instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == + SubGhzProtocolFlag_Save); +} + +bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type) { + furi_assert(instance); + const SubGhzProtocol* protocol = instance->decoder_result->protocol; + if(check_type) { + return ( + ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) && + protocol->encoder->deserialize && protocol->type == SubGhzProtocolTypeStatic); + } + return ( + ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) && + protocol->encoder->deserialize); +} + +void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter) { + furi_assert(instance); + subghz_receiver_set_filter(instance->receiver, filter); +} + +void subghz_txrx_set_rx_calback( + SubGhzTxRx* instance, + SubGhzReceiverCallback callback, + void* context) { + subghz_receiver_set_rx_callback(instance->receiver, callback, context); +} + +void subghz_txrx_set_raw_file_encoder_worker_callback_end( + SubGhzTxRx* instance, + SubGhzProtocolEncoderRAWCallbackEnd callback, + void* context) { + subghz_protocol_raw_file_encoder_worker_set_callback_end( + (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(instance->transmitter), + callback, + context); +} diff --git a/applications/main/subghz/helpers/subghz_txrx.h b/applications/main/subghz/helpers/subghz_txrx.h new file mode 100644 index 0000000000..0f2daf05d4 --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -0,0 +1,290 @@ +#pragma once + +#include "subghz_types.h" + +#include +#include +#include +#include +#include + +typedef struct SubGhzTxRx SubGhzTxRx; + +typedef void (*SubGhzTxRxNeedSaveCallback)(void* context); + +typedef enum { + SubGhzTxRxStartTxStateOk, + SubGhzTxRxStartTxStateErrorOnlyRx, + SubGhzTxRxStartTxStateErrorParserOthers, +} SubGhzTxRxStartTxState; + +/** + * Allocate SubGhzTxRx + * + * @return SubGhzTxRx* pointer to SubGhzTxRx + */ +SubGhzTxRx* subghz_txrx_alloc(); + +/** + * Free SubGhzTxRx + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_free(SubGhzTxRx* instance); + +/** + * Check if the database is loaded + * + * @param instance Pointer to a SubGhzTxRx + * @return bool True if the database is loaded + */ +bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance); + +/** + * Set preset + * + * @param instance Pointer to a SubGhzTxRx + * @param preset_name Name of preset + * @param frequency Frequency in Hz + * @param preset_data Data of preset + * @param preset_data_size Size of preset data + */ +void subghz_txrx_set_preset( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + uint8_t* preset_data, + size_t preset_data_size); + +/** + * Get name of preset + * + * @param instance Pointer to a SubGhzTxRx + * @param preset String of preset + * @return const char* Name of preset + */ +const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset); + +/** + * Get of preset + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzRadioPreset Preset + */ +SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance); + +/** + * Get string frequency and modulation + * + * @param instance Pointer to a SubGhzTxRx + * @param frequency Pointer to a string frequency + * @param modulation Pointer to a string modulation + */ +void subghz_txrx_get_frequency_and_modulation( + SubGhzTxRx* instance, + FuriString* frequency, + FuriString* modulation); + +/** + * Start TX CC1101 + * + * @param instance Pointer to a SubGhzTxRx + * @param flipper_format Pointer to a FlipperFormat + * @return SubGhzTxRxStartTxState + */ +SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format); + +/** + * Start RX CC1101 + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_rx_start(SubGhzTxRx* instance); + +/** + * Stop TX/RX CC1101 + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_stop(SubGhzTxRx* instance); + +/** + * Set sleep mode CC1101 + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_sleep(SubGhzTxRx* instance); + +/** + * Update frequency CC1101 in automatic mode (hopper) + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_hopper_update(SubGhzTxRx* instance); + +/** + * Get state hopper + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzHopperState + */ +SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance); + +/** + * Set state hopper + * + * @param instance Pointer to a SubGhzTxRx + * @param state State hopper + */ +void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state); + +/** + * Unpause hopper + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_hopper_unpause(SubGhzTxRx* instance); + +/** + * Set pause hopper + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_hopper_pause(SubGhzTxRx* instance); + +/** + * Speaker on + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_speaker_on(SubGhzTxRx* instance); + +/** + * Speaker off + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_speaker_off(SubGhzTxRx* instance); + +/** + * Speaker mute + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_speaker_mute(SubGhzTxRx* instance); + +/** + * Speaker unmute + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_speaker_unmute(SubGhzTxRx* instance); + +/** + * Set state speaker + * + * @param instance Pointer to a SubGhzTxRx + * @param state State speaker + */ +void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state); + +/** + * Get state speaker + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzSpeakerState + */ +SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance); + +/** + * load decoder by name protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param name_protocol Name protocol + * @return bool True if the decoder is loaded + */ +bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol); + +/** + * Get decoder + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzProtocolDecoderBase* Pointer to a SubGhzProtocolDecoderBase + */ +SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance); + +/** + * Set callback for save data + * + * @param instance Pointer to a SubGhzTxRx + * @param callback Callback for save data + * @param context Context for callback + */ +void subghz_txrx_set_need_save_callback( + SubGhzTxRx* instance, + SubGhzTxRxNeedSaveCallback callback, + void* context); + +/** + * Get pointer to a load data key + * + * @param instance Pointer to a SubGhzTxRx + * @return FlipperFormat* + */ +FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance); + +/** + * Get pointer to a SugGhzSetting + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzSetting* + */ +SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance); + +/** + * Is it possible to save this protocol + * + * @param instance Pointer to a SubGhzTxRx + * @return bool True if it is possible to save this protocol + */ +bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance); + +/** + * Is it possible to send this protocol + * + * @param instance Pointer to a SubGhzTxRx + * @return bool True if it is possible to send this protocol + */ +bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type); + +/** + * Set filter, what types of decoder to use + * + * @param instance Pointer to a SubGhzTxRx + * @param filter Filter + */ +void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter); + +/** + * Set callback for receive data + * + * @param instance Pointer to a SubGhzTxRx + * @param callback Callback for receive data + * @param context Context for callback + */ +void subghz_txrx_set_rx_calback( + SubGhzTxRx* instance, + SubGhzReceiverCallback callback, + void* context); + +/** + * Set callback for Raw decoder, end of data transfer + * + * @param instance Pointer to a SubGhzTxRx + * @param callback Callback for Raw decoder, end of data transfer + * @param context Context for callback + */ +void subghz_txrx_set_raw_file_encoder_worker_callback_end( + SubGhzTxRx* instance, + SubGhzProtocolEncoderRAWCallbackEnd callback, + void* context); diff --git a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c new file mode 100644 index 0000000000..41e4f7c4ef --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c @@ -0,0 +1,164 @@ +#include "subghz_txrx_i.h" +#include "subghz_txrx_create_potocol_key.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define TAG "SubGhzCreateProtocolKey" + +bool subghz_txrx_gen_data_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit) { + furi_assert(context); + SubGhzTxRx* instance = context; + + bool res = false; + + subghz_txrx_set_preset(instance, preset_name, frequency, NULL, 0); + instance->decoder_result = + subghz_receiver_search_decoder_base_by_name(instance->receiver, protocol_name); + + if(instance->decoder_result == NULL) { + //TODO: Error + // furi_string_set(error_str, "Protocol not\nfound!"); + // scene_manager_next_scene(scene_manager, SubGhzSceneShowErrorSub); + FURI_LOG_E(TAG, "Protocol not found!"); + return false; + } + + do { + Stream* fff_data_stream = flipper_format_get_raw_stream(instance->fff_data); + stream_clean(fff_data_stream); + if(subghz_protocol_decoder_base_serialize( + instance->decoder_result, instance->fff_data, instance->preset) != + SubGhzProtocolStatusOk) { + FURI_LOG_E(TAG, "Unable to serialize"); + break; + } + if(!flipper_format_update_uint32(instance->fff_data, "Bit", &bit, 1)) { + FURI_LOG_E(TAG, "Unable to update Bit"); + break; + } + + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF; + } + if(!flipper_format_update_hex(instance->fff_data, "Key", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to update Key"); + break; + } + res = true; + } while(false); + return res; +} + +bool subghz_txrx_gen_data_protocol_and_te( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit, + uint32_t te) { + furi_assert(instance); + bool ret = false; + if(subghz_txrx_gen_data_protocol(instance, preset_name, frequency, protocol_name, key, bit)) { + if(!flipper_format_update_uint32(instance->fff_data, "TE", (uint32_t*)&te, 1)) { + FURI_LOG_E(TAG, "Unable to update Te"); + } else { + ret = true; + } + } + return ret; +} + +bool subghz_txrx_gen_keelog_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency, + const char* name_sysmem, + uint32_t serial, + uint8_t btn, + uint16_t cnt) { + furi_assert(instance); + + bool ret = false; + serial &= 0x0FFFFFFF; + instance->transmitter = + subghz_transmitter_alloc_init(instance->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); + subghz_txrx_set_preset(instance, name_preset, frequency, NULL, 0); + if(instance->transmitter) { + subghz_protocol_keeloq_create_data( + subghz_transmitter_get_protocol_instance(instance->transmitter), + instance->fff_data, + serial, + btn, + cnt, + name_sysmem, + instance->preset); + ret = true; + } + subghz_transmitter_free(instance->transmitter); + return ret; +} + +bool subghz_txrx_gen_secplus_v2_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint32_t cnt) { + furi_assert(instance); + + bool ret = false; + instance->transmitter = + subghz_transmitter_alloc_init(instance->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); + subghz_txrx_set_preset(instance, name_preset, frequency, NULL, 0); + if(instance->transmitter) { + subghz_protocol_secplus_v2_create_data( + subghz_transmitter_get_protocol_instance(instance->transmitter), + instance->fff_data, + serial, + btn, + cnt, + instance->preset); + ret = true; + } + return ret; +} + +bool subghz_txrx_gen_secplus_v1_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency) { + furi_assert(instance); + + bool ret = false; + uint32_t serial = (uint32_t)rand(); + while(!subghz_protocol_secplus_v1_check_fixed(serial)) { + serial = (uint32_t)rand(); + } + if(subghz_txrx_gen_data_protocol( + instance, + name_preset, + frequency, + SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, + (uint64_t)serial << 32 | 0xE6000000, + 42)) { + ret = true; + } + return ret; +} \ No newline at end of file diff --git a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h new file mode 100644 index 0000000000..5eed93034f --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h @@ -0,0 +1,96 @@ +#pragma once +#include "subghz_types.h" +#include "subghz_txrx.h" + +/** + * Generate data for protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param preset_name Name of preset + * @param frequency Frequency in Hz + * @param protocol_name Name of protocol + * @param key Key + * @param bit Bit + * @return bool True if success + */ +bool subghz_txrx_gen_data_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit); + +/** + * Generate data for protocol and te + * + * @param instance Pointer to a SubGhzTxRx + * @param preset_name Name of preset + * @param frequency Frequency in Hz + * @param protocol_name Name of protocol + * @param key Key + * @param bit Bit + * @param te Te + * @return bool True if success + */ +bool subghz_txrx_gen_data_protocol_and_te( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit, + uint32_t te); + +/** + * Generate data Keeloq protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param name_preset Name of preset + * @param frequency Frequency in Hz + * @param name_sysmem Name of Keeloq sysmem + * @param serial Serial number + * @param btn Button + * @param cnt Counter + * @return bool True if success + */ +bool subghz_txrx_gen_keelog_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency, + const char* name_sysmem, + uint32_t serial, + uint8_t btn, + uint16_t cnt); + +/** + * Generate data SecPlus v2 protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param name_preset Name of preset + * @param frequency Frequency in Hz + * @param serial Serial number + * @param btn Button + * @param cnt Counter + * @return bool True if success + */ +bool subghz_txrx_gen_secplus_v2_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint32_t cnt); + +/** + * Generate data SecPlus v1 protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param name_preset Name of preset + * @param frequency Frequency in Hz + * @return bool True if success + */ +bool subghz_txrx_gen_secplus_v1_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency); \ No newline at end of file diff --git a/applications/main/subghz/helpers/subghz_txrx_i.h b/applications/main/subghz/helpers/subghz_txrx_i.h new file mode 100644 index 0000000000..bd0ad8b7be --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx_i.h @@ -0,0 +1,27 @@ +#pragma once + +#include "subghz_txrx.h" + +struct SubGhzTxRx { + SubGhzWorker* worker; + + SubGhzEnvironment* environment; + SubGhzReceiver* receiver; + SubGhzTransmitter* transmitter; + SubGhzProtocolDecoderBase* decoder_result; + FlipperFormat* fff_data; + + SubGhzRadioPreset* preset; + SubGhzSetting* setting; + + uint8_t hopper_timeout; + uint8_t hopper_idx_frequency; + bool is_database_loaded; + SubGhzHopperState hopper_state; + + SubGhzTxRxState txrx_state; + SubGhzSpeakerState speaker_state; + + SubGhzTxRxNeedSaveCallback need_save_callback; + void* need_save_context; +}; diff --git a/applications/main/subghz/helpers/subghz_types.h b/applications/main/subghz/helpers/subghz_types.h index 2bd2f6820c..46bf940f46 100644 --- a/applications/main/subghz/helpers/subghz_types.h +++ b/applications/main/subghz/helpers/subghz_types.h @@ -77,3 +77,10 @@ typedef enum { SubGhzViewIdTestCarrier, SubGhzViewIdTestPacket, } SubGhzViewId; + +/** SubGhz load type file */ +typedef enum { + SubGhzLoadTypeFileNoLoad, + SubGhzLoadTypeFileKey, + SubGhzLoadTypeFileRaw, +} SubGhzLoadTypeFile; diff --git a/applications/main/subghz/scenes/subghz_scene_delete.c b/applications/main/subghz/scenes/subghz_scene_delete.c index 94814b1432..0d14cd23a3 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete.c +++ b/applications/main/subghz/scenes/subghz_scene_delete.c @@ -19,7 +19,7 @@ void subghz_scene_delete_on_enter(void* context) { modulation_str = furi_string_alloc(); text = furi_string_alloc(); - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); widget_add_string_element( subghz->widget, 78, @@ -37,7 +37,7 @@ void subghz_scene_delete_on_enter(void* context) { AlignTop, FontSecondary, furi_string_get_cstr(modulation_str)); - subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text); + subghz_protocol_decoder_base_get_string(subghz_txrx_get_decoder(subghz->txrx), text); widget_add_string_multiline_element( subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text)); diff --git a/applications/main/subghz/scenes/subghz_scene_delete_raw.c b/applications/main/subghz/scenes/subghz_scene_delete_raw.c index fa4fc6f642..8dff442a87 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_delete_raw.c @@ -33,7 +33,7 @@ void subghz_scene_delete_raw_on_enter(void* context) { widget_add_string_element( subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal"); - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); widget_add_string_element( subghz->widget, 35, diff --git a/applications/main/subghz/scenes/subghz_scene_need_saving.c b/applications/main/subghz/scenes/subghz_scene_need_saving.c index e157246aae..f29f26309c 100644 --- a/applications/main/subghz/scenes/subghz_scene_need_saving.c +++ b/applications/main/subghz/scenes/subghz_scene_need_saving.c @@ -37,27 +37,23 @@ void subghz_scene_need_saving_on_enter(void* context) { bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeBack) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); scene_manager_previous_scene(subghz->scene_manager); return true; } else if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneStay) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); scene_manager_previous_scene(subghz->scene_manager); return true; } else if(event.event == SubGhzCustomEventSceneExit) { - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; - subghz_preset_init( - subghz, - "AM650", - subghz_setting_get_default_frequency(subghz->setting), - NULL, - 0); + SubGhzRxKeyState state = subghz_rx_key_state_get(subghz); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + + if(state == SubGhzRxKeyStateExit) { + subghz_set_default_preset(subghz); scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); } else { - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; scene_manager_previous_scene(subghz->scene_manager); } diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 09440b32bb..6e576a8618 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -3,11 +3,9 @@ #include #include #include -#include #define RAW_FILE_NAME "Raw_signal_" #define TAG "SubGhzSceneReadRAW" -#define RAW_THRESHOLD_RSSI_LOW_COUNT 10 bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { bool ret = false; @@ -15,12 +13,13 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { FuriString* temp_str; temp_str = furi_string_alloc(); do { - if(!flipper_format_rewind(subghz->txrx->fff_data)) { + FlipperFormat* fff_data = subghz_txrx_get_fff_data(subghz->txrx); + if(!flipper_format_rewind(fff_data)) { FURI_LOG_E(TAG, "Rewind error"); break; } - if(!flipper_format_read_string(subghz->txrx->fff_data, "File_name", temp_str)) { + if(!flipper_format_read_string(fff_data, "File_name", temp_str)) { FURI_LOG_E(TAG, "Missing File_name"); break; } @@ -38,13 +37,10 @@ static void subghz_scene_read_raw_update_statusbar(void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); subghz_read_raw_add_data_statusbar( subghz->subghz_read_raw, furi_string_get_cstr(frequency_str), @@ -69,13 +65,13 @@ void subghz_scene_read_raw_callback_end_tx(void* context) { void subghz_scene_read_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); - switch(subghz->txrx->rx_key_state) { + float threshold_rssi = subghz_threshold_rssi_get(subghz->threshold_rssi); + switch(subghz_rx_key_state_get(subghz)) { case SubGhzRxKeyStateBack: subghz_read_raw_set_status( - subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "", subghz->txrx->raw_threshold_rssi); + subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "", threshold_rssi); break; case SubGhzRxKeyStateRAWLoad: path_extract_filename(subghz->file_path, file_name, true); @@ -83,8 +79,7 @@ void subghz_scene_read_raw_on_enter(void* context) { subghz->subghz_read_raw, SubGhzReadRAWStatusLoadKeyTX, furi_string_get_cstr(file_name), - subghz->txrx->raw_threshold_rssi); - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + threshold_rssi); break; case SubGhzRxKeyStateRAWSave: path_extract_filename(subghz->file_path, file_name, true); @@ -92,66 +87,51 @@ void subghz_scene_read_raw_on_enter(void* context) { subghz->subghz_read_raw, SubGhzReadRAWStatusSaveKey, furi_string_get_cstr(file_name), - subghz->txrx->raw_threshold_rssi); - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + threshold_rssi); break; default: subghz_read_raw_set_status( - subghz->subghz_read_raw, - SubGhzReadRAWStatusStart, - "", - subghz->txrx->raw_threshold_rssi); - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz->subghz_read_raw, SubGhzReadRAWStatusStart, "", threshold_rssi); break; } + + if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateBack) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + } furi_string_free(file_name); subghz_scene_read_raw_update_statusbar(subghz); //set callback view raw subghz_read_raw_set_callback(subghz->subghz_read_raw, subghz_scene_read_raw_callback, subghz); - subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME); - furi_assert(subghz->txrx->decoder_result); + furi_check(subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, SUBGHZ_PROTOCOL_RAW_NAME)); //set filter RAW feed - subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_RAW); + subghz_txrx_receiver_set_filter(subghz->txrx, SubGhzProtocolFlag_RAW); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReadRAW); } bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; bool consumed = false; + SubGhzProtocolDecoderRAW* decoder_raw = + (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx); if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { case SubGhzCustomEventViewReadRAWBack: - //Stop TX - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } - //Stop RX - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; + + subghz_txrx_stop(subghz->txrx); //Stop save file - subghz_protocol_raw_save_to_file_stop( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); + subghz_protocol_raw_save_to_file_stop(decoder_raw); subghz->state_notifications = SubGhzNotificationStateIDLE; //needed save? - if((subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) || - (subghz->txrx->rx_key_state == SubGhzRxKeyStateBack)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateExit; + if((subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) || + (subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateBack)) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateExit); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { //Restore default setting - subghz_preset_init( - subghz, - "AM650", - subghz_setting_get_default_frequency(subghz->setting), - NULL, - 0); + subghz_set_default_preset(subghz); if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneSaved)) { if(!scene_manager_search_and_switch_to_previous_scene( @@ -165,16 +145,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { break; case SubGhzCustomEventViewReadRAWTXRXStop: - //Stop TX - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } - //Stop RX - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; + subghz_txrx_stop(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateIDLE; consumed = true; break; @@ -187,13 +158,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { break; case SubGhzCustomEventViewReadRAWErase: - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) { + if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) { if(subghz_scene_read_raw_update_filename(subghz)) { furi_string_set(subghz->file_path_tmp, subghz->file_path); subghz_delete_file(subghz); } } - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); notification_message(subghz->notifications, &sequence_reset_rgb); consumed = true; break; @@ -203,7 +174,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz_scene_read_raw_update_filename(subghz)) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet); - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW); consumed = true; } else { @@ -223,33 +194,22 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) { //start send subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - } - if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || - (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { - if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; - subghz_read_raw_set_status( - subghz->subghz_read_raw, - SubGhzReadRAWStatusIDLE, - "", - subghz->txrx->raw_threshold_rssi); - } else { - if(scene_manager_has_previous_scene( - subghz->scene_manager, SubGhzSceneSaved) || - !scene_manager_has_previous_scene( - subghz->scene_manager, SubGhzSceneStart)) { - DOLPHIN_DEED(DolphinDeedSubGhzSend); - } - // set callback end tx - subghz_protocol_raw_file_encoder_worker_set_callback_end( - (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( - subghz->txrx->transmitter), - subghz_scene_read_raw_callback_end_tx, - subghz); - subghz->state_notifications = SubGhzNotificationStateTx; + if(!subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); + subghz_read_raw_set_status( + subghz->subghz_read_raw, + SubGhzReadRAWStatusIDLE, + "", + subghz_threshold_rssi_get(subghz->threshold_rssi)); + } else { + if(scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneSaved) || + !scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneStart)) { + DOLPHIN_DEED(DolphinDeedSubGhzSend); } + // set callback end tx + subghz_txrx_set_raw_file_encoder_worker_callback_end( + subghz->txrx, subghz_scene_read_raw_callback_end_tx, subghz); + subghz->state_notifications = SubGhzNotificationStateTx; } } else { if(!scene_manager_search_and_switch_to_previous_scene( @@ -263,33 +223,22 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { case SubGhzCustomEventViewReadRAWSendStop: subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_speaker_unmute(subghz); - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } + subghz_txrx_stop(subghz->txrx); subghz_read_raw_stop_send(subghz->subghz_read_raw); consumed = true; break; case SubGhzCustomEventViewReadRAWIDLE: - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; - - size_t spl_count = subghz_protocol_raw_get_sample_write( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); + subghz_txrx_stop(subghz->txrx); + size_t spl_count = subghz_protocol_raw_get_sample_write(decoder_raw); - subghz_protocol_raw_save_to_file_stop( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); + subghz_protocol_raw_save_to_file_stop(decoder_raw); - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); furi_string_printf( temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION); subghz_protocol_raw_gen_fff_data( - subghz->txrx->fff_data, furi_string_get_cstr(temp_str)); + subghz_txrx_get_fff_data(subghz->txrx), furi_string_get_cstr(temp_str)); furi_string_free(temp_str); if(spl_count > 0) { @@ -299,32 +248,21 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { } subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); consumed = true; break; case SubGhzCustomEventViewReadRAWREC: - if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) { + if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateIDLE) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { - subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT; - if(subghz_protocol_raw_save_to_file_init( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, - RAW_FILE_NAME, - subghz->txrx->preset)) { + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + if(subghz_protocol_raw_save_to_file_init(decoder_raw, RAW_FILE_NAME, &preset)) { DOLPHIN_DEED(DolphinDeedSubGhzRawRec); - if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || - (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, - furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } + subghz_txrx_rx_start(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } else { furi_string_set(subghz->error_str, "Function requires\nan SD card."); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); @@ -337,7 +275,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSetRAW); - subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); } else { if(!scene_manager_search_and_switch_to_previous_scene( @@ -356,41 +294,15 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { switch(subghz->state_notifications) { case SubGhzNotificationStateRx: notification_message(subghz->notifications, &sequence_blink_cyan_10); - subghz_read_raw_update_sample_write( - subghz->subghz_read_raw, - subghz_protocol_raw_get_sample_write( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result)); - - float rssi = furi_hal_subghz_get_rssi(); - if(float_is_equal(subghz->txrx->raw_threshold_rssi, SUBGHZ_RAW_TRESHOLD_MIN)) { - subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true); - subghz_protocol_raw_save_to_file_pause( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); - } else { - if(rssi < subghz->txrx->raw_threshold_rssi) { - subghz->txrx->raw_threshold_rssi_low_count++; - if(subghz->txrx->raw_threshold_rssi_low_count > RAW_THRESHOLD_RSSI_LOW_COUNT) { - subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT; - } - subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false); - } else { - subghz->txrx->raw_threshold_rssi_low_count = 0; - } - - if(subghz->txrx->raw_threshold_rssi_low_count == RAW_THRESHOLD_RSSI_LOW_COUNT) { - subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false); - subghz_protocol_raw_save_to_file_pause( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, true); - subghz_speaker_mute(subghz); - } else { - subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true); - subghz_protocol_raw_save_to_file_pause( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); - subghz_speaker_unmute(subghz); - } - } + subghz_read_raw_update_sample_write( + subghz->subghz_read_raw, subghz_protocol_raw_get_sample_write(decoder_raw)); + SubGhzThresholdRssiData ret_rssi = + subghz_threshold_get_rssi_data(subghz->threshold_rssi); + subghz_read_raw_add_data_rssi( + subghz->subghz_read_raw, ret_rssi.rssi, ret_rssi.is_above); + subghz_protocol_raw_save_to_file_pause(decoder_raw, !ret_rssi.is_above); break; case SubGhzNotificationStateTx: notification_message(subghz->notifications, &sequence_blink_magenta_10); @@ -407,13 +319,10 @@ void subghz_scene_read_raw_on_exit(void* context) { SubGhz* subghz = context; //Stop CC1101 - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; + subghz_txrx_stop(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateIDLE; notification_message(subghz->notifications, &sequence_reset_rgb); //filter restoration - subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); + subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 93c369092e..dcc22b91cc 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -35,16 +35,12 @@ static const NotificationSequence subghs_sequence_rx_locked = { static void subghz_scene_receiver_update_statusbar(void* context) { SubGhz* subghz = context; - FuriString* history_stat_str; - history_stat_str = furi_string_alloc(); - if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { - FuriString* frequency_str; - FuriString* modulation_str; + FuriString* history_stat_str = furi_string_alloc(); + if(!subghz_history_get_text_space_left(subghz->history, history_stat_str)) { + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); subghz_view_receiver_add_data_statusbar( subghz->subghz_receiver, @@ -74,80 +70,68 @@ static void subghz_scene_add_to_history_callback( void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* str_buff; - str_buff = furi_string_alloc(); + SubGhzHistory* history = subghz->history; + FuriString* str_buff = furi_string_alloc(); + + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); - if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { + if(subghz_history_add_to_history(history, decoder_base, &preset)) { furi_string_reset(str_buff); subghz->state_notifications = SubGhzNotificationStateRxDone; - - subghz_history_get_text_item_menu( - subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1); + uint16_t item_history = subghz_history_get_item(history); + subghz_history_get_text_item_menu(history, str_buff, item_history - 1); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, furi_string_get_cstr(str_buff), - subghz_history_get_type_protocol( - subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1)); + subghz_history_get_type_protocol(history, item_history - 1)); subghz_scene_receiver_update_statusbar(subghz); } subghz_receiver_reset(receiver); furi_string_free(str_buff); - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } void subghz_scene_receiver_on_enter(void* context) { SubGhz* subghz = context; + SubGhzHistory* history = subghz->history; FuriString* str_buff; str_buff = furi_string_alloc(); - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) { - subghz_preset_init( - subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0); - subghz_history_reset(subghz->txrx->history); - subghz->txrx->rx_key_state = SubGhzRxKeyStateStart; + if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateIDLE) { + subghz_set_default_preset(subghz); + subghz_history_reset(history); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart); } - subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock); + subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz_is_locked(subghz)); //Load history to receiver subghz_view_receiver_exit(subghz->subghz_receiver); - for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) { + for(uint8_t i = 0; i < subghz_history_get_item(history); i++) { furi_string_reset(str_buff); - subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i); + subghz_history_get_text_item_menu(history, str_buff, i); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, furi_string_get_cstr(str_buff), - subghz_history_get_type_protocol(subghz->txrx->history, i)); - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; + subghz_history_get_type_protocol(history, i)); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } furi_string_free(str_buff); subghz_scene_receiver_update_statusbar(subghz); subghz_view_receiver_set_callback( subghz->subghz_receiver, subghz_scene_receiver_callback, subghz); - subghz_receiver_set_rx_callback( - subghz->txrx->receiver, subghz_scene_add_to_history_callback, subghz); + subghz_txrx_set_rx_calback(subghz->txrx, subghz_scene_add_to_history_callback, subghz); subghz->state_notifications = SubGhzNotificationStateRx; - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - }; - if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || - (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } - subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen); + subghz_txrx_rx_start(subghz->txrx); + subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen); //to use a universal decoder, we are looking for a link to it - subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, SUBGHZ_PROTOCOL_BIN_RAW_NAME); - furi_assert(subghz->txrx->decoder_result); + furi_check( + subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, SUBGHZ_PROTOCOL_BIN_RAW_NAME)); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver); } @@ -160,41 +144,31 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { case SubGhzCustomEventViewReceiverBack: // Stop CC1101 Rx subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; - subghz->txrx->hopper_state = SubGhzHopperStateOFF; - subghz->txrx->idx_menu_chosen = 0; - subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); - - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateExit; + subghz_txrx_stop(subghz->txrx); + subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF); + subghz->idx_menu_chosen = 0; + subghz_txrx_set_rx_calback(subghz->txrx, NULL, subghz); + + if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateExit); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; - subghz_preset_init( - subghz, - "AM650", - subghz_setting_get_default_frequency(subghz->setting), - NULL, - 0); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + subghz_set_default_preset(subghz); scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); } consumed = true; break; case SubGhzCustomEventViewReceiverOK: - subghz->txrx->idx_menu_chosen = - subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); + subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo); consumed = true; break; case SubGhzCustomEventViewReceiverConfig: subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz->txrx->idx_menu_chosen = - subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); + subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig); consumed = true; break; @@ -203,30 +177,30 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { consumed = true; break; case SubGhzCustomEventViewReceiverUnlock: - subghz->lock = SubGhzLockOff; + subghz_unlock(subghz); consumed = true; break; default: break; } } else if(event.type == SceneManagerEventTypeTick) { - if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { - subghz_hopper_update(subghz); + if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) { + subghz_txrx_hopper_update(subghz->txrx); subghz_scene_receiver_update_statusbar(subghz); } - //get RSSI - float rssi = furi_hal_subghz_get_rssi(); - subghz_receiver_rssi(subghz->subghz_receiver, rssi); + SubGhzThresholdRssiData ret_rssi = subghz_threshold_get_rssi_data(subghz->threshold_rssi); + + subghz_receiver_rssi(subghz->subghz_receiver, ret_rssi.rssi); subghz_protocol_decoder_bin_raw_data_input_rssi( - (SubGhzProtocolDecoderBinRAW*)subghz->txrx->decoder_result, rssi); + (SubGhzProtocolDecoderBinRAW*)subghz_txrx_get_decoder(subghz->txrx), ret_rssi.rssi); switch(subghz->state_notifications) { case SubGhzNotificationStateRx: notification_message(subghz->notifications, &sequence_blink_cyan_10); break; case SubGhzNotificationStateRxDone: - if(subghz->lock != SubGhzLockOn) { + if(!subghz_is_locked(subghz)) { notification_message(subghz->notifications, &subghs_sequence_rx); } else { notification_message(subghz->notifications, &subghs_sequence_rx_locked); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index 895e433428..55a8f6b44a 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -72,13 +72,15 @@ const uint32_t bin_raw_value[BIN_RAW_COUNT] = { uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) { furi_assert(context); SubGhz* subghz = context; + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + uint8_t index = 0; - for(uint8_t i = 0; i < subghz_setting_get_frequency_count(subghz->setting); i++) { - if(value == subghz_setting_get_frequency(subghz->setting, i)) { + for(uint8_t i = 0; i < subghz_setting_get_frequency_count(setting); i++) { + if(value == subghz_setting_get_frequency(setting, i)) { index = i; break; } else { - index = subghz_setting_get_frequency_default_index(subghz->setting); + index = subghz_setting_get_frequency_default_index(setting); } } return index; @@ -87,13 +89,15 @@ uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void* context) { furi_assert(context); SubGhz* subghz = context; + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + uint8_t index = 0; - for(uint8_t i = 0; i < subghz_setting_get_preset_count(subghz->setting); i++) { - if(!strcmp(subghz_setting_get_preset_name(subghz->setting, i), preset_name)) { + for(uint8_t i = 0; i < subghz_setting_get_preset_count(setting); i++) { + if(!strcmp(subghz_setting_get_preset_name(setting, i), preset_name)) { index = i; break; } else { - // index = subghz_setting_get_frequency_default_index(subghz->setting); + // index = subghz_setting_get_frequency_default_index(subghz_txrx_get_setting(subghz->txrx)); } } return index; @@ -122,70 +126,84 @@ uint8_t subghz_scene_receiver_config_hopper_value_index( static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); - if(subghz->txrx->hopper_state == SubGhzHopperStateOFF) { + if(subghz_txrx_hopper_get_state(subghz->txrx) == SubGhzHopperStateOFF) { char text_buf[10] = {0}; + uint32_t frequency = subghz_setting_get_frequency(setting, index); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + snprintf( text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_frequency(subghz->setting, index) / 1000000, - (subghz_setting_get_frequency(subghz->setting, index) % 1000000) / 10000); + frequency / 1000000, + (frequency % 1000000) / 10000); variable_item_set_current_value_text(item, text_buf); - subghz->txrx->preset->frequency = subghz_setting_get_frequency(subghz->setting, index); + subghz_txrx_set_preset( + subghz->txrx, + furi_string_get_cstr(preset.name), + frequency, + preset.data, + preset.data_size); } else { variable_item_set_current_value_index( - item, subghz_setting_get_frequency_default_index(subghz->setting)); + item, subghz_setting_get_frequency_default_index(setting)); } } static void subghz_scene_receiver_config_set_preset(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text( - item, subghz_setting_get_preset_name(subghz->setting, index)); - subghz_preset_init( - subghz, - subghz_setting_get_preset_name(subghz->setting, index), - subghz->txrx->preset->frequency, - subghz_setting_get_preset_data(subghz->setting, index), - subghz_setting_get_preset_data_size(subghz->setting, index)); + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + + variable_item_set_current_value_text(item, subghz_setting_get_preset_name(setting, index)); + + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + subghz_txrx_set_preset( + subghz->txrx, + subghz_setting_get_preset_name(setting, index), + preset.frequency, + subghz_setting_get_preset_data(setting, index), + subghz_setting_get_preset_data_size(setting, index)); } static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + VariableItem* frequency_item = (VariableItem*)scene_manager_get_scene_state( + subghz->scene_manager, SubGhzSceneReceiverConfig); variable_item_set_current_value_text(item, hopping_text[index]); if(hopping_value[index] == SubGhzHopperStateOFF) { char text_buf[10] = {0}; + uint32_t frequency = subghz_setting_get_default_frequency(setting); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + snprintf( text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_default_frequency(subghz->setting) / 1000000, - (subghz_setting_get_default_frequency(subghz->setting) % 1000000) / 10000); - variable_item_set_current_value_text( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - text_buf); - subghz->txrx->preset->frequency = subghz_setting_get_default_frequency(subghz->setting); + frequency / 1000000, + (frequency % 1000000) / 10000); + variable_item_set_current_value_text(frequency_item, text_buf); + + subghz_txrx_set_preset( + subghz->txrx, + furi_string_get_cstr(preset.name), + frequency, + preset.data, + preset.data_size); variable_item_set_current_value_index( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - subghz_setting_get_frequency_default_index(subghz->setting)); + frequency_item, subghz_setting_get_frequency_default_index(setting)); } else { - variable_item_set_current_value_text( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - " -----"); + variable_item_set_current_value_text(frequency_item, " -----"); variable_item_set_current_value_index( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - subghz_setting_get_frequency_default_index(subghz->setting)); + frequency_item, subghz_setting_get_frequency_default_index(setting)); } - subghz->txrx->hopper_state = hopping_value[index]; + subghz_txrx_hopper_set_state(subghz->txrx, hopping_value[index]); } static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { @@ -193,7 +211,7 @@ static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, speaker_text[index]); - subghz->txrx->speaker_state = speaker_value[index]; + subghz_txrx_speaker_set_state(subghz->txrx, speaker_value[index]); } static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) { @@ -201,8 +219,8 @@ static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, bin_raw_text[index]); - subghz->txrx->filter = bin_raw_value[index]; - subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); + subghz->filter = bin_raw_value[index]; + subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); } static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) { @@ -210,7 +228,7 @@ static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* it uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, raw_theshold_rssi_text[index]); - subghz->txrx->raw_threshold_rssi = raw_theshold_rssi_value[index]; + subghz_threshold_rssi_set(subghz->threshold_rssi, raw_theshold_rssi_value[index]); } static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) { @@ -226,25 +244,27 @@ void subghz_scene_receiver_config_on_enter(void* context) { SubGhz* subghz = context; VariableItem* item; uint8_t value_index; + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); item = variable_item_list_add( subghz->variable_item_list, "Frequency:", - subghz_setting_get_frequency_count(subghz->setting), + subghz_setting_get_frequency_count(setting), subghz_scene_receiver_config_set_frequency, subghz); - value_index = - subghz_scene_receiver_config_next_frequency(subghz->txrx->preset->frequency, subghz); + value_index = subghz_scene_receiver_config_next_frequency(preset.frequency, subghz); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item); variable_item_set_current_value_index(item, value_index); char text_buf[10] = {0}; + uint32_t frequency = subghz_setting_get_frequency(setting, value_index); snprintf( text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_frequency(subghz->setting, value_index) / 1000000, - (subghz_setting_get_frequency(subghz->setting, value_index) % 1000000) / 10000); + frequency / 1000000, + (frequency % 1000000) / 10000); variable_item_set_current_value_text(item, text_buf); if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != @@ -256,7 +276,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_set_hopping_running, subghz); value_index = subghz_scene_receiver_config_hopper_value_index( - subghz->txrx->hopper_state, hopping_value, HOPPING_COUNT, subghz); + subghz_txrx_hopper_get_state(subghz->txrx), hopping_value, HOPPING_COUNT, subghz); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, hopping_text[value_index]); } @@ -264,14 +284,14 @@ void subghz_scene_receiver_config_on_enter(void* context) { item = variable_item_list_add( subghz->variable_item_list, "Modulation:", - subghz_setting_get_preset_count(subghz->setting), + subghz_setting_get_preset_count(setting), subghz_scene_receiver_config_set_preset, subghz); - value_index = subghz_scene_receiver_config_next_preset( - furi_string_get_cstr(subghz->txrx->preset->name), subghz); + value_index = + subghz_scene_receiver_config_next_preset(furi_string_get_cstr(preset.name), subghz); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text( - item, subghz_setting_get_preset_name(subghz->setting, value_index)); + item, subghz_setting_get_preset_name(setting, value_index)); if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != SubGhzCustomEventManagerSet) { @@ -281,7 +301,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { BIN_RAW_COUNT, subghz_scene_receiver_config_set_bin_raw, subghz); - value_index = value_index_uint32(subghz->txrx->filter, bin_raw_value, BIN_RAW_COUNT); + value_index = value_index_uint32(subghz->filter, bin_raw_value, BIN_RAW_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, bin_raw_text[value_index]); } @@ -292,7 +312,8 @@ void subghz_scene_receiver_config_on_enter(void* context) { SPEAKER_COUNT, subghz_scene_receiver_config_set_speaker, subghz); - value_index = value_index_uint32(subghz->txrx->speaker_state, speaker_value, SPEAKER_COUNT); + value_index = value_index_uint32( + subghz_txrx_speaker_get_state(subghz->txrx), speaker_value, SPEAKER_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, speaker_text[value_index]); @@ -313,7 +334,9 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_set_raw_threshold_rssi, subghz); value_index = value_index_float( - subghz->txrx->raw_threshold_rssi, raw_theshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT); + subghz_threshold_rssi_get(subghz->threshold_rssi), + raw_theshold_rssi_value, + RAW_THRESHOLD_RSSI_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, raw_theshold_rssi_text[value_index]); } @@ -326,7 +349,7 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneSettingLock) { - subghz->lock = SubGhzLockOn; + subghz_lock(subghz); scene_manager_previous_scene(subghz->scene_manager); consumed = true; } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 152334ad63..9b57165e76 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -19,20 +19,19 @@ void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, v static bool subghz_scene_receiver_info_update_parser(void* context) { SubGhz* subghz = context; - subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, - subghz_history_get_protocol_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); - if(subghz->txrx->decoder_result) { + if(subghz_txrx_load_decoder_by_name_protocol( + subghz->txrx, + subghz_history_get_protocol_name(subghz->history, subghz->idx_menu_chosen))) { //todo we are trying to deserialize without checking for errors, since it is assumed that we just received this chignal subghz_protocol_decoder_base_deserialize( - subghz->txrx->decoder_result, - subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); + subghz_txrx_get_decoder(subghz->txrx), + subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen)); SubGhzRadioPreset* preset = - subghz_history_get_radio_preset(subghz->txrx->history, subghz->txrx->idx_menu_chosen); - subghz_preset_init( - subghz, + subghz_history_get_radio_preset(subghz->history, subghz->idx_menu_chosen); + subghz_txrx_set_preset( + subghz->txrx, furi_string_get_cstr(preset->name), preset->frequency, preset->data, @@ -47,15 +46,11 @@ void subghz_scene_receiver_info_on_enter(void* context) { SubGhz* subghz = context; if(subghz_scene_receiver_info_update_parser(subghz)) { - FuriString* frequency_str; - FuriString* modulation_str; - FuriString* text; + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); + FuriString* text = furi_string_alloc(); - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - text = furi_string_alloc(); - - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); widget_add_string_element( subghz->widget, 78, @@ -73,7 +68,7 @@ void subghz_scene_receiver_info_on_enter(void* context) { AlignTop, FontSecondary, furi_string_get_cstr(modulation_str)); - subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text); + subghz_protocol_decoder_base_get_string(subghz_txrx_get_decoder(subghz->txrx), text); widget_add_string_multiline_element( subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text)); @@ -81,8 +76,7 @@ void subghz_scene_receiver_info_on_enter(void* context) { furi_string_free(modulation_str); furi_string_free(text); - if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == - SubGhzProtocolFlag_Save) { + if(subghz_txrx_protocol_is_serializable(subghz->txrx)) { widget_add_button_element( subghz->widget, GuiButtonTypeRight, @@ -90,10 +84,7 @@ void subghz_scene_receiver_info_on_enter(void* context) { subghz_scene_receiver_info_callback, subghz); } - if(((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == - SubGhzProtocolFlag_Send) && - subghz->txrx->decoder_result->protocol->encoder->deserialize && - subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeStatic) { + if(subghz_txrx_protocol_is_transmittable(subghz->txrx, true)) { widget_add_button_element( subghz->widget, GuiButtonTypeCenter, @@ -114,82 +105,49 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneReceiverInfoTxStart) { - //CC1101 Stop RX -> Start TX - if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { - subghz->txrx->hopper_state = SubGhzHopperStatePause; - } - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - } if(!subghz_scene_receiver_info_update_parser(subghz)) { return false; } - if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE || - subghz->txrx->txrx_state == SubGhzTxRxStateSleep) { - if(!subghz_tx_start( - subghz, - subghz_history_get_raw_data( - subghz->txrx->history, subghz->txrx->idx_menu_chosen))) { - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - } - if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, - furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } - if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { - subghz->txrx->hopper_state = SubGhzHopperStateRunnig; - } - subghz->state_notifications = SubGhzNotificationStateRx; - } else { - subghz->state_notifications = SubGhzNotificationStateTx; - } + //CC1101 Stop RX -> Start TX + subghz_txrx_hopper_pause(subghz->txrx); + if(!subghz_tx_start( + subghz, + subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen))) { + subghz_txrx_rx_start(subghz->txrx); + subghz_txrx_hopper_unpause(subghz->txrx); + subghz->state_notifications = SubGhzNotificationStateRx; + } else { + subghz->state_notifications = SubGhzNotificationStateTx; } return true; } else if(event.event == SubGhzCustomEventSceneReceiverInfoTxStop) { //CC1101 Stop Tx -> Start RX subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - } - if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } - if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { - subghz->txrx->hopper_state = SubGhzHopperStateRunnig; - } + + subghz_txrx_rx_start(subghz->txrx); + + subghz_txrx_hopper_unpause(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; return true; } else if(event.event == SubGhzCustomEventSceneReceiverInfoSave) { //CC1101 Stop RX -> Save subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz->txrx->hopper_state = SubGhzHopperStateOFF; - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - } + subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF); + + subghz_txrx_stop(subghz->txrx); if(!subghz_scene_receiver_info_update_parser(subghz)) { return false; } - if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == - SubGhzProtocolFlag_Save) { + if(subghz_txrx_protocol_is_serializable(subghz->txrx)) { subghz_file_name_clear(subghz); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); } return true; } } else if(event.type == SceneManagerEventTypeTick) { - if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { - subghz_hopper_update(subghz); + if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) { + subghz_txrx_hopper_update(subghz->txrx); } switch(subghz->state_notifications) { case SubGhzNotificationStateTx: diff --git a/applications/main/subghz/scenes/subghz_scene_region_info.c b/applications/main/subghz/scenes/subghz_scene_region_info.c index 82486314d9..b98394af07 100644 --- a/applications/main/subghz/scenes/subghz_scene_region_info.c +++ b/applications/main/subghz/scenes/subghz_scene_region_info.c @@ -5,8 +5,7 @@ void subghz_scene_region_info_on_enter(void* context) { SubGhz* subghz = context; const FuriHalRegion* const region = furi_hal_region_get(); - FuriString* buffer; - buffer = furi_string_alloc(); + FuriString* buffer = furi_string_alloc(); if(region) { furi_string_cat_printf(buffer, "Region: %s, bands:\n", region->country_code); for(uint16_t i = 0; i < region->bands_count; ++i) { diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index a1c0e41fd6..aa6f132d76 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -3,6 +3,7 @@ typedef enum { SubGhzRpcStateIdle, SubGhzRpcStateLoaded, + SubGhzRpcStateTx, } SubGhzRpcState; void subghz_scene_rpc_on_enter(void* context) { @@ -38,9 +39,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { view_dispatcher_stop(subghz->view_dispatcher); } else if(event.event == SubGhzCustomEventSceneRpcButtonPress) { bool result = false; - if((subghz->txrx->txrx_state == SubGhzTxRxStateSleep) && - (state == SubGhzRpcStateLoaded)) { - result = subghz_tx_start(subghz, subghz->txrx->fff_data); + if((state == SubGhzRpcStateLoaded)) { + result = subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); + state = SubGhzRpcStateTx; if(result) subghz_blink_start(subghz); } if(!result) { @@ -52,10 +53,10 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonPress, result); } else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) { bool result = false; - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { + if(state == SubGhzRpcStateTx) { + subghz_txrx_stop(subghz->txrx); subghz_blink_stop(subghz); - subghz_tx_stop(subghz); - subghz_sleep(subghz); + state = SubGhzRpcStateIdle; result = true; } rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonRelease, result); @@ -93,10 +94,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { void subghz_scene_rpc_on_exit(void* context) { SubGhz* subghz = context; - - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); + SubGhzRpcState state = scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneRpc); + if(state != SubGhzRpcStateIdle) { + subghz_txrx_stop(subghz->txrx); subghz_blink_stop(subghz); } diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index 255ba228bc..2a292a1ef3 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -35,10 +35,8 @@ void subghz_scene_save_name_on_enter(void* context) { TextInput* text_input = subghz->text_input; bool dev_name_empty = false; - FuriString* file_name; - FuriString* dir_name; - file_name = furi_string_alloc(); - dir_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); + FuriString* dir_name = furi_string_alloc(); if(!subghz_path_is_file(subghz->file_path)) { char file_name_buf[SUBGHZ_MAX_LEN_NAME] = {0}; @@ -69,7 +67,7 @@ void subghz_scene_save_name_on_enter(void* context) { subghz_scene_save_name_text_input_callback, subghz, subghz->file_name_tmp, - MAX_TEXT_INPUT_LEN, // buffer size + MAX_TEXT_INPUT_LEN, dev_name_empty); ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( @@ -106,7 +104,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { SubGhzCustomEventManagerNoSet) { subghz_save_protocol_to_file( subghz, - subghz->txrx->fff_data, + subghz_txrx_get_fff_data(subghz->txrx), furi_string_get_cstr(subghz->file_path)); scene_manager_set_scene_state( subghz->scene_manager, @@ -115,8 +113,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { } else { subghz_save_protocol_to_file( subghz, - subghz_history_get_raw_data( - subghz->txrx->history, subghz->txrx->idx_menu_chosen), + subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen), furi_string_get_cstr(subghz->file_path)); } } @@ -124,7 +121,8 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != SubGhzCustomEventManagerNoSet) { subghz_protocol_raw_gen_fff_data( - subghz->txrx->fff_data, furi_string_get_cstr(subghz->file_path)); + subghz_txrx_get_fff_data(subghz->txrx), + furi_string_get_cstr(subghz->file_path)); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet); } else { diff --git a/applications/main/subghz/scenes/subghz_scene_save_success.c b/applications/main/subghz/scenes/subghz_scene_save_success.c index 2977975f7f..40ade5a535 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_success.c +++ b/applications/main/subghz/scenes/subghz_scene_save_success.c @@ -26,10 +26,10 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event) if(event.event == SubGhzCustomEventSceneSaveSuccess) { if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneReceiver)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWSave; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWSave); if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneReadRAW)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneSaved)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved); diff --git a/applications/main/subghz/scenes/subghz_scene_saved.c b/applications/main/subghz/scenes/subghz_scene_saved.c index 62ade3508e..8b198e3395 100644 --- a/applications/main/subghz/scenes/subghz_scene_saved.c +++ b/applications/main/subghz/scenes/subghz_scene_saved.c @@ -4,8 +4,8 @@ void subghz_scene_saved_on_enter(void* context) { SubGhz* subghz = context; if(subghz_load_protocol_from_file(subghz)) { - if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + if(subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); } else { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSavedMenu); diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 2134377e3a..32e0d65884 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -1,63 +1,10 @@ #include "../subghz_i.h" -#include -#include -#include +#include "../helpers/subghz_txrx_create_potocol_key.h" #include -#include -#include #include #define TAG "SubGhzSetType" -bool subghz_scene_set_type_submenu_gen_data_protocol( - void* context, - const char* protocol_name, - uint64_t key, - uint32_t bit, - uint32_t frequency, - const char* preset_name) { - furi_assert(context); - SubGhz* subghz = context; - - bool res = false; - - subghz_preset_init(subghz, preset_name, frequency, NULL, 0); - subghz->txrx->decoder_result = - subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, protocol_name); - - if(subghz->txrx->decoder_result == NULL) { - furi_string_set(subghz->error_str, "Protocol not\nfound!"); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); - return false; - } - - do { - Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); - stream_clean(fff_data_stream); - if(subghz_protocol_decoder_base_serialize( - subghz->txrx->decoder_result, subghz->txrx->fff_data, subghz->txrx->preset) != - SubGhzProtocolStatusOk) { - FURI_LOG_E(TAG, "Unable to serialize"); - break; - } - if(!flipper_format_update_uint32(subghz->txrx->fff_data, "Bit", &bit, 1)) { - FURI_LOG_E(TAG, "Unable to update Bit"); - break; - } - - uint8_t key_data[sizeof(uint64_t)] = {0}; - for(size_t i = 0; i < sizeof(uint64_t); i++) { - key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF; - } - if(!flipper_format_update_hex(subghz->txrx->fff_data, "Key", key_data, sizeof(uint64_t))) { - FURI_LOG_E(TAG, "Unable to update Key"); - break; - } - res = true; - } while(false); - return res; -} - void subghz_scene_set_type_submenu_callback(void* context, uint32_t index) { SubGhz* subghz = context; view_dispatcher_send_custom_event(subghz->view_dispatcher, index); @@ -69,7 +16,13 @@ void subghz_scene_set_type_on_enter(void* context) { submenu_add_item( subghz->submenu, "Princeton_433", - SubmenuIndexPricenton, + SubmenuIndexPricenton_433, + subghz_scene_set_type_submenu_callback, + subghz); + submenu_add_item( + subghz->submenu, + "Princeton_315", + SubmenuIndexPricenton_315, subghz_scene_set_type_submenu_callback, subghz); submenu_add_item( @@ -108,10 +61,6 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexCAMETwee, subghz_scene_set_type_submenu_callback, subghz); - // submenu_add_item( - // subghz->submenu, "Nero Sketch", SubmenuIndexNeroSketch, subghz_scene_set_type_submenu_callback, subghz); - // submenu_add_item( - // subghz->submenu, "Nero Radio", SubmenuIndexNeroRadio, subghz_scene_set_type_submenu_callback, subghz); submenu_add_item( subghz->submenu, "Gate TX_433", @@ -172,94 +121,59 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { bool generated_protocol = false; if(event.type == SceneManagerEventTypeCustom) { - //ToDo Fix - uint32_t key = subghz_random_serial(); + uint32_t key = (uint32_t)rand(); switch(event.event) { - case SubmenuIndexPricenton: + case SubmenuIndexPricenton_433: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 433920000, "AM650")) { - uint32_t te = 400; - flipper_format_update_uint32(subghz->txrx->fff_data, "TE", (uint32_t*)&te, 1); - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol_and_te( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400); + break; + case SubmenuIndexPricenton_315: + key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 + generated_protocol = subghz_txrx_gen_data_protocol_and_te( + subghz->txrx, "AM650", 315000000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400); break; case SubmenuIndexNiceFlo12bit: key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12); break; case SubmenuIndexNiceFlo24bit: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24); break; case SubmenuIndexCAME12bit: key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 12, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 12); break; case SubmenuIndexCAME24bit: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 24, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 24); break; case SubmenuIndexLinear_300_00: key = (key & 0x3FF); - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10, 300000000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 300000000, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10); break; case SubmenuIndexCAMETwee: key = (key & 0x0FFFFFF0); key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE); - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54, 433920000, "AM650")) { - generated_protocol = true; - } + + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54); break; - // case SubmenuIndexNeroSketch: - // /* code */ - // break; - // case SubmenuIndexNeroRadio: - // /* code */ - // break; case SubmenuIndexGateTX: key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?) uint64_t rev_key = subghz_protocol_blocks_reverse_key(key, 24); - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24); break; case SubmenuIndexDoorHan_433_92: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); - subghz_preset_init( - subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_keeloq_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key & 0x0FFFFFFF, - 0x2, - 0x0003, - "DoorHan", - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_txrx_gen_keelog_protocol( + subghz->txrx, "AM650", 433920000, "DoorHan", key, 0x2, 0x0003); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -267,23 +181,8 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexDoorHan_315_00: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); - subghz_preset_init(subghz, "AM650", 315000000, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_keeloq_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key & 0x0FFFFFFF, - 0x2, - 0x0003, - "DoorHan", - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_txrx_gen_keelog_protocol( + subghz->txrx, "AM650", 315000000, "DoorHan", key, 0x2, 0x0003); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -291,86 +190,24 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexLiftMaster_315_00: - while(!subghz_protocol_secplus_v1_check_fixed(key)) { - key = subghz_random_serial(); - } - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, - SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, - (uint64_t)key << 32 | 0xE6000000, - 42, - 315000000, - "AM650")) { - generated_protocol = true; - } + generated_protocol = + subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 315000000); break; case SubmenuIndexLiftMaster_390_00: - while(!subghz_protocol_secplus_v1_check_fixed(key)) { - key = subghz_random_serial(); - } - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, - SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, - (uint64_t)key << 32 | 0xE6000000, - 42, - 390000000, - "AM650")) { - generated_protocol = true; - } + generated_protocol = + subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 390000000); break; case SubmenuIndexSecPlus_v2_310_00: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); - subghz_preset_init(subghz, "AM650", 310000000, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_secplus_v2_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key, - 0x68, - 0xE500000, - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_txrx_gen_secplus_v2_protocol( + subghz->txrx, "AM650", 310000000, key, 0x68, 0xE500000); break; case SubmenuIndexSecPlus_v2_315_00: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); - subghz_preset_init(subghz, "AM650", 315000000, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_secplus_v2_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key, - 0x68, - 0xE500000, - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_txrx_gen_secplus_v2_protocol( + subghz->txrx, "AM650", 315000000, key, 0x68, 0xE500000); break; case SubmenuIndexSecPlus_v2_390_00: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); - subghz_preset_init(subghz, "AM650", 390000000, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_secplus_v2_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key, - 0x68, - 0xE500000, - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_txrx_gen_secplus_v2_protocol( + subghz->txrx, "AM650", 390000000, key, 0x68, 0xE500000); break; default: return false; diff --git a/applications/main/subghz/scenes/subghz_scene_show_error.c b/applications/main/subghz/scenes/subghz_scene_show_error.c index eadfb21146..d52eca9b6c 100644 --- a/applications/main/subghz/scenes/subghz_scene_show_error.c +++ b/applications/main/subghz/scenes/subghz_scene_show_error.c @@ -50,9 +50,10 @@ void subghz_scene_show_error_on_enter(void* context) { bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; + SubGhzCustomEvent scene_state = + scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError); if(event.type == SceneManagerEventTypeBack) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { return false; } else { scene_manager_search_and_switch_to_previous_scene( @@ -61,14 +62,12 @@ bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { return true; } else if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneShowErrorOk) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); } return true; } else if(event.event == SubGhzCustomEventSceneShowErrorBack) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { //exit app if(!scene_manager_previous_scene(subghz->scene_manager)) { scene_manager_stop(subghz->scene_manager); diff --git a/applications/main/subghz/scenes/subghz_scene_start.c b/applications/main/subghz/scenes/subghz_scene_start.c index a50f73a810..a41e4b06f4 100644 --- a/applications/main/subghz/scenes/subghz_scene_start.c +++ b/applications/main/subghz/scenes/subghz_scene_start.c @@ -70,7 +70,7 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.event == SubmenuIndexReadRAW) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneStart, SubmenuIndexReadRAW); - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); return true; } else if(event.event == SubmenuIndexRead) { diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 712e50071c..1c193c1794 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -11,32 +11,24 @@ void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) { bool subghz_scene_transmitter_update_data_show(void* context) { SubGhz* subghz = context; bool ret = false; - if(subghz->txrx->decoder_result) { - FuriString* key_str; - FuriString* frequency_str; - FuriString* modulation_str; + SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(subghz->txrx); - key_str = furi_string_alloc(); - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - uint8_t show_button = 0; + if(decoder) { + FuriString* key_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); if(subghz_protocol_decoder_base_deserialize( - subghz->txrx->decoder_result, subghz->txrx->fff_data) == SubGhzProtocolStatusOk) { - subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, key_str); + decoder, subghz_txrx_get_fff_data(subghz->txrx)) == SubGhzProtocolStatusOk) { + subghz_protocol_decoder_base_get_string(decoder, key_str); - if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == - SubGhzProtocolFlag_Send) { - show_button = 1; - } - - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); subghz_view_transmitter_add_data_to_show( subghz->subghz_transmitter, furi_string_get_cstr(key_str), furi_string_get_cstr(frequency_str), furi_string_get_cstr(modulation_str), - show_button); + subghz_txrx_protocol_is_transmittable(subghz->txrx, false)); ret = true; } furi_string_free(frequency_str); @@ -65,24 +57,16 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventViewTransmitterSendStart) { subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - } - if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || - (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { - if(subghz_tx_start(subghz, subghz->txrx->fff_data)) { - subghz->state_notifications = SubGhzNotificationStateTx; - subghz_scene_transmitter_update_data_show(subghz); - DOLPHIN_DEED(DolphinDeedSubGhzSend); - } + + if(subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { + subghz->state_notifications = SubGhzNotificationStateTx; + subghz_scene_transmitter_update_data_show(subghz); + DOLPHIN_DEED(DolphinDeedSubGhzSend); } return true; } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } + subghz_txrx_stop(subghz->txrx); return true; } else if(event.event == SubGhzCustomEventViewTransmitterBack) { subghz->state_notifications = SubGhzNotificationStateIDLE; diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 25233fe21c..09963584af 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -1,9 +1,6 @@ /* Abandon hope, all ye who enter here. */ -#include "subghz/types.h" #include "subghz_i.h" -#include -#include bool subghz_custom_event_callback(void* context, uint32_t event) { furi_assert(context); @@ -49,16 +46,6 @@ static void subghz_rpc_command_callback(RpcAppSystemEvent event, void* context) } } -void subghz_blink_start(SubGhz* instance) { - furi_assert(instance); - notification_message(instance->notifications, &sequence_blink_start_magenta); -} - -void subghz_blink_stop(SubGhz* instance) { - furi_assert(instance); - notification_message(instance->notifications, &sequence_blink_stop); -} - SubGhz* subghz_alloc() { SubGhz* subghz = malloc(sizeof(SubGhz)); @@ -163,45 +150,18 @@ SubGhz* subghz_alloc() { SubGhzViewIdStatic, subghz_test_static_get_view(subghz->subghz_test_static)); - //init setting - subghz->setting = subghz_setting_alloc(); - subghz_setting_load(subghz->setting, EXT_PATH("subghz/assets/setting_user")); - - //init Worker & Protocol & History & KeyBoard - subghz->lock = SubGhzLockOff; - subghz->txrx = malloc(sizeof(SubGhzTxRx)); - subghz->txrx->preset = malloc(sizeof(SubGhzRadioPreset)); - subghz->txrx->preset->name = furi_string_alloc(); - subghz_preset_init( - subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0); - - subghz->txrx->txrx_state = SubGhzTxRxStateSleep; - subghz->txrx->hopper_state = SubGhzHopperStateOFF; - subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; - subghz->txrx->raw_threshold_rssi = SUBGHZ_RAW_TRESHOLD_MIN; - subghz->txrx->history = subghz_history_alloc(); - subghz->txrx->worker = subghz_worker_alloc(); - subghz->txrx->fff_data = flipper_format_string_alloc(); - - subghz->txrx->environment = subghz_environment_alloc(); - subghz_environment_set_came_atomo_rainbow_table_file_name( - subghz->txrx->environment, EXT_PATH("subghz/assets/came_atomo")); - subghz_environment_set_alutech_at_4n_rainbow_table_file_name( - subghz->txrx->environment, EXT_PATH("subghz/assets/alutech_at_4n")); - subghz_environment_set_nice_flor_s_rainbow_table_file_name( - subghz->txrx->environment, EXT_PATH("subghz/assets/nice_flor_s")); - subghz_environment_set_protocol_registry( - subghz->txrx->environment, (void*)&subghz_protocol_registry); - subghz->txrx->receiver = subghz_receiver_alloc_init(subghz->txrx->environment); - subghz->txrx->filter = SubGhzProtocolFlag_Decodable; - subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); - - subghz_worker_set_overrun_callback( - subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); - subghz_worker_set_pair_callback( - subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); - subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->receiver); + //init threshold rssi + subghz->threshold_rssi = subghz_threshold_rssi_alloc(); + + subghz_unlock(subghz); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + subghz->history = subghz_history_alloc(); + subghz->filter = SubGhzProtocolFlag_Decodable; + + //init TxRx & History & KeyBoard + subghz->txrx = subghz_txrx_alloc(); + subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); + subghz_txrx_set_need_save_callback(subghz->txrx, subghz_save_to_file, subghz); //Init Error_str subghz->error_str = furi_string_alloc(); @@ -219,7 +179,9 @@ void subghz_free(SubGhz* subghz) { subghz->rpc_ctx = NULL; } - subghz_speaker_off(subghz); + subghz_txrx_speaker_off(subghz->txrx); + subghz_txrx_stop(subghz->txrx); + subghz_txrx_sleep(subghz->txrx); // Packet Test view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestPacket); @@ -282,18 +244,14 @@ void subghz_free(SubGhz* subghz) { furi_record_close(RECORD_GUI); subghz->gui = NULL; - //setting - subghz_setting_free(subghz->setting); + // threshold rssi + subghz_threshold_rssi_free(subghz->threshold_rssi); //Worker & Protocol & History - subghz_receiver_free(subghz->txrx->receiver); - subghz_environment_free(subghz->txrx->environment); - subghz_worker_free(subghz->txrx->worker); - flipper_format_free(subghz->txrx->fff_data); - subghz_history_free(subghz->txrx->history); - furi_string_free(subghz->txrx->preset->name); - free(subghz->txrx->preset); - free(subghz->txrx); + subghz_history_free(subghz->history); + + //TxRx + subghz_txrx_free(subghz->txrx); //Error string furi_string_free(subghz->error_str); @@ -319,11 +277,6 @@ int32_t subghz_app(void* p) { return 1; } - //Load database - bool load_database = subghz_environment_load_keystore( - subghz->txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); - subghz_environment_load_keystore( - subghz->txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); // Check argument and run corresponding scene if(p && strlen(p)) { uint32_t rpc_ctx = 0; @@ -340,9 +293,9 @@ int32_t subghz_app(void* p) { if(subghz_key_load(subghz, p, true)) { furi_string_set(subghz->file_path, (const char*)p); - if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { + if(subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw) { //Load Raw TX - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); } else { //Load transmitter TX @@ -358,7 +311,7 @@ int32_t subghz_app(void* p) { view_dispatcher_attach_to_gui( subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen); furi_string_set(subghz->file_path, SUBGHZ_APP_FOLDER); - if(load_database) { + if(subghz_txrx_is_database_loaded(subghz->txrx)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); } else { scene_manager_set_scene_state( diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 18d87c76b5..8036ed5f7a 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -18,214 +18,42 @@ #define TAG "SubGhz" -void subghz_preset_init( - void* context, - const char* preset_name, - uint32_t frequency, - uint8_t* preset_data, - size_t preset_data_size) { - furi_assert(context); - SubGhz* subghz = context; - furi_string_set(subghz->txrx->preset->name, preset_name); - subghz->txrx->preset->frequency = frequency; - subghz->txrx->preset->data = preset_data; - subghz->txrx->preset->data_size = preset_data_size; -} - -bool subghz_set_preset(SubGhz* subghz, const char* preset) { - if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { - furi_string_set(subghz->txrx->preset->name, "AM270"); - } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { - furi_string_set(subghz->txrx->preset->name, "AM650"); - } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { - furi_string_set(subghz->txrx->preset->name, "FM238"); - } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { - furi_string_set(subghz->txrx->preset->name, "FM476"); - } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { - furi_string_set(subghz->txrx->preset->name, "CUSTOM"); - } else { - FURI_LOG_E(TAG, "Unknown preset"); - return false; - } - return true; -} - -void subghz_get_frequency_modulation(SubGhz* subghz, FuriString* frequency, FuriString* modulation) { +void subghz_set_default_preset(SubGhz* subghz) { furi_assert(subghz); - if(frequency != NULL) { - furi_string_printf( - frequency, - "%03ld.%02ld", - subghz->txrx->preset->frequency / 1000000 % 1000, - subghz->txrx->preset->frequency / 10000 % 100); - } - if(modulation != NULL) { - furi_string_printf(modulation, "%.2s", furi_string_get_cstr(subghz->txrx->preset->name)); - } + subghz_txrx_set_preset( + subghz->txrx, + "AM650", + subghz_setting_get_default_frequency(subghz_txrx_get_setting(subghz->txrx)), + NULL, + 0); } -void subghz_begin(SubGhz* subghz, uint8_t* preset_data) { +void subghz_blink_start(SubGhz* subghz) { furi_assert(subghz); - furi_hal_subghz_reset(); - furi_hal_subghz_idle(); - furi_hal_subghz_load_custom_preset(preset_data); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); - subghz->txrx->txrx_state = SubGhzTxRxStateIDLE; + notification_message(subghz->notifications, &sequence_blink_stop); + notification_message(subghz->notifications, &sequence_blink_start_magenta); } -uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency) { +void subghz_blink_stop(SubGhz* subghz) { furi_assert(subghz); - if(!furi_hal_subghz_is_frequency_valid(frequency)) { - furi_crash("SubGhz: Incorrect RX frequency."); - } - furi_assert( - subghz->txrx->txrx_state != SubGhzTxRxStateRx && - subghz->txrx->txrx_state != SubGhzTxRxStateSleep); - - furi_hal_subghz_idle(); - uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); - furi_hal_subghz_flush_rx(); - subghz_speaker_on(subghz); - furi_hal_subghz_rx(); - - furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz->txrx->worker); - subghz_worker_start(subghz->txrx->worker); - subghz->txrx->txrx_state = SubGhzTxRxStateRx; - return value; -} - -static bool subghz_tx(SubGhz* subghz, uint32_t frequency) { - furi_assert(subghz); - if(!furi_hal_subghz_is_frequency_valid(frequency)) { - furi_crash("SubGhz: Incorrect TX frequency."); - } - furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep); - furi_hal_subghz_idle(); - furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_write(&gpio_cc1101_g0, false); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - bool ret = furi_hal_subghz_tx(); - if(ret) { - subghz_speaker_on(subghz); - subghz->txrx->txrx_state = SubGhzTxRxStateTx; - } - return ret; -} - -void subghz_idle(SubGhz* subghz) { - furi_assert(subghz); - furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep); - furi_hal_subghz_idle(); - subghz_speaker_off(subghz); - subghz->txrx->txrx_state = SubGhzTxRxStateIDLE; -} - -void subghz_rx_end(SubGhz* subghz) { - furi_assert(subghz); - furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateRx); - - if(subghz_worker_is_running(subghz->txrx->worker)) { - subghz_worker_stop(subghz->txrx->worker); - furi_hal_subghz_stop_async_rx(); - } - furi_hal_subghz_idle(); - subghz_speaker_off(subghz); - subghz->txrx->txrx_state = SubGhzTxRxStateIDLE; -} - -void subghz_sleep(SubGhz* subghz) { - furi_assert(subghz); - furi_hal_subghz_sleep(); - subghz->txrx->txrx_state = SubGhzTxRxStateSleep; + notification_message(subghz->notifications, &sequence_blink_stop); } bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) { - furi_assert(subghz); - - bool ret = false; - FuriString* temp_str; - temp_str = furi_string_alloc(); - uint32_t repeat = 200; - do { - if(!flipper_format_rewind(flipper_format)) { - FURI_LOG_E(TAG, "Rewind error"); - break; - } - if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) { - FURI_LOG_E(TAG, "Missing Protocol"); - break; - } - if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { - FURI_LOG_E(TAG, "Unable Repeat"); - break; - } - - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, furi_string_get_cstr(temp_str)); - - if(subghz->txrx->transmitter) { - if(subghz_transmitter_deserialize(subghz->txrx->transmitter, flipper_format) == - SubGhzProtocolStatusOk) { - if(strcmp(furi_string_get_cstr(subghz->txrx->preset->name), "") != 0) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - } else { - FURI_LOG_E( - TAG, - "Unknown name preset \" %s \"", - furi_string_get_cstr(subghz->txrx->preset->name)); - subghz_begin( - subghz, subghz_setting_get_preset_data_by_name(subghz->setting, "AM650")); - } - if(subghz->txrx->preset->frequency) { - ret = subghz_tx(subghz, subghz->txrx->preset->frequency); - } else { - ret = subghz_tx(subghz, 433920000); - } - if(ret) { - //Start TX - furi_hal_subghz_start_async_tx( - subghz_transmitter_yield, subghz->txrx->transmitter); - } else { - subghz_dialog_message_show_only_rx(subghz); - } - } else { - dialog_message_show_storage_error( - subghz->dialogs, "Error in protocol\nparameters\ndescription"); - } - } - if(!ret) { - subghz_transmitter_free(subghz->txrx->transmitter); - if(subghz->txrx->txrx_state != SubGhzTxRxStateSleep) { - subghz_idle(subghz); - } - } - - } while(false); - furi_string_free(temp_str); - return ret; -} + switch(subghz_txrx_tx_start(subghz->txrx, flipper_format)) { + case SubGhzTxRxStartTxStateErrorParserOthers: + dialog_message_show_storage_error( + subghz->dialogs, "Error in protocol\nparameters\ndescription"); + break; + case SubGhzTxRxStartTxStateErrorOnlyRx: + subghz_dialog_message_show_only_rx(subghz); + break; -void subghz_tx_stop(SubGhz* subghz) { - furi_assert(subghz); - furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateTx); - //Stop TX - furi_hal_subghz_stop_async_tx(); - subghz_transmitter_stop(subghz->txrx->transmitter); - subghz_transmitter_free(subghz->txrx->transmitter); - - //if protocol dynamic then we save the last upload - if((subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) && - (subghz_path_is_file(subghz->file_path))) { - subghz_save_protocol_to_file( - subghz, subghz->txrx->fff_data, furi_string_get_cstr(subghz->file_path)); + default: + return true; + break; } - subghz_idle(subghz); - subghz_speaker_off(subghz); - notification_message(subghz->notifications, &sequence_reset_red); + return false; } void subghz_dialog_message_show_only_rx(SubGhz* subghz) { @@ -254,11 +82,11 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); + Stream* fff_data_stream = + flipper_format_get_raw_stream(subghz_txrx_get_fff_data(subghz->txrx)); SubGhzLoadKeyState load_key_state = SubGhzLoadKeyStateParseErr; - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t temp_data32; do { @@ -281,6 +109,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { break; } + //Load frequency if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { FURI_LOG_E(TAG, "Missing Frequency"); break; @@ -291,58 +120,61 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { break; } - subghz->txrx->preset->frequency = temp_data32; - + //Load preset if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { FURI_LOG_E(TAG, "Missing Preset"); break; } - if(!subghz_set_preset(subghz, furi_string_get_cstr(temp_str))) { + furi_string_set_str( + temp_str, subghz_txrx_get_preset_name(subghz->txrx, furi_string_get_cstr(temp_str))); + if(!strcmp(furi_string_get_cstr(temp_str), "")) { break; } + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); - if(!strcmp(furi_string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) { + if(!strcmp(furi_string_get_cstr(temp_str), "CUSTOM")) { //Todo add Custom_preset_module //delete preset if it already exists - subghz_setting_delete_custom_preset( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name)); + subghz_setting_delete_custom_preset(setting, furi_string_get_cstr(temp_str)); //load custom preset from file if(!subghz_setting_load_custom_preset( - subghz->setting, - furi_string_get_cstr(subghz->txrx->preset->name), - fff_data_file)) { + setting, furi_string_get_cstr(temp_str), fff_data_file)) { FURI_LOG_E(TAG, "Missing Custom preset"); break; } } - size_t preset_index = subghz_setting_get_inx_preset_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name)); - subghz_preset_init( - subghz, - furi_string_get_cstr(subghz->txrx->preset->name), - subghz->txrx->preset->frequency, - subghz_setting_get_preset_data(subghz->setting, preset_index), - subghz_setting_get_preset_data_size(subghz->setting, preset_index)); - + size_t preset_index = + subghz_setting_get_inx_preset_by_name(setting, furi_string_get_cstr(temp_str)); + subghz_txrx_set_preset( + subghz->txrx, + furi_string_get_cstr(temp_str), + temp_data32, + subghz_setting_get_preset_data(setting, preset_index), + subghz_setting_get_preset_data_size(setting, preset_index)); + + //Load protocol if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { FURI_LOG_E(TAG, "Missing Protocol"); break; } + + FlipperFormat* fff_data = subghz_txrx_get_fff_data(subghz->txrx); if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) { //if RAW - subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, file_path); + subghz->load_type_file = SubGhzLoadTypeFileRaw; + subghz_protocol_raw_gen_fff_data(fff_data, file_path); } else { + subghz->load_type_file = SubGhzLoadTypeFileKey; stream_copy_full( flipper_format_get_raw_stream(fff_data_file), - flipper_format_get_raw_stream(subghz->txrx->fff_data)); + flipper_format_get_raw_stream(fff_data)); } - subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, furi_string_get_cstr(temp_str)); - if(subghz->txrx->decoder_result) { + if(subghz_txrx_load_decoder_by_name_protocol( + subghz->txrx, furi_string_get_cstr(temp_str))) { SubGhzProtocolStatus status = subghz_protocol_decoder_base_deserialize( - subghz->txrx->decoder_result, subghz->txrx->fff_data); + subghz_txrx_get_decoder(subghz->txrx), fff_data); if(status != SubGhzProtocolStatusOk) { load_key_state = SubGhzLoadKeyStateProtocolDescriptionErr; break; @@ -381,17 +213,18 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { } } +SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz) { + furi_assert(subghz); + return subghz->load_type_file; +} + bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) { furi_assert(subghz); Storage* storage = furi_record_open(RECORD_STORAGE); - FuriString* temp_str; - FuriString* file_name; - FuriString* file_path; - - temp_str = furi_string_alloc(); - file_name = furi_string_alloc(); - file_path = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); + FuriString* file_path = furi_string_alloc(); bool res = false; @@ -438,8 +271,7 @@ bool subghz_save_protocol_to_file( Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); bool saved = false; - FuriString* file_dir; - file_dir = furi_string_alloc(); + FuriString* file_dir = furi_string_alloc(); path_extract_dirname(dev_file_name, file_dir); do { @@ -467,11 +299,21 @@ bool subghz_save_protocol_to_file( return saved; } +void subghz_save_to_file(void* context) { + furi_assert(context); + SubGhz* subghz = context; + if(subghz_path_is_file(subghz->file_path)) { + subghz_save_protocol_to_file( + subghz, + subghz_txrx_get_fff_data(subghz->txrx), + furi_string_get_cstr(subghz->file_path)); + } +} + bool subghz_load_protocol_from_file(SubGhz* subghz) { furi_assert(subghz); - FuriString* file_path; - file_path = furi_string_alloc(); + FuriString* file_path = furi_string_alloc(); DialogsFileBrowserOptions browser_options; dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px); @@ -551,92 +393,27 @@ bool subghz_path_is_file(FuriString* path) { return furi_string_end_with(path, SUBGHZ_APP_EXTENSION); } -uint32_t subghz_random_serial(void) { - return (uint32_t)rand(); -} - -void subghz_hopper_update(SubGhz* subghz) { +void subghz_lock(SubGhz* subghz) { furi_assert(subghz); - - switch(subghz->txrx->hopper_state) { - case SubGhzHopperStateOFF: - case SubGhzHopperStatePause: - return; - case SubGhzHopperStateRSSITimeOut: - if(subghz->txrx->hopper_timeout != 0) { - subghz->txrx->hopper_timeout--; - return; - } - break; - default: - break; - } - float rssi = -127.0f; - if(subghz->txrx->hopper_state != SubGhzHopperStateRSSITimeOut) { - // See RSSI Calculation timings in CC1101 17.3 RSSI - rssi = furi_hal_subghz_get_rssi(); - - // Stay if RSSI is high enough - if(rssi > -90.0f) { - subghz->txrx->hopper_timeout = 10; - subghz->txrx->hopper_state = SubGhzHopperStateRSSITimeOut; - return; - } - } else { - subghz->txrx->hopper_state = SubGhzHopperStateRunnig; - } - // Select next frequency - if(subghz->txrx->hopper_idx_frequency < - subghz_setting_get_hopper_frequency_count(subghz->setting) - 1) { - subghz->txrx->hopper_idx_frequency++; - } else { - subghz->txrx->hopper_idx_frequency = 0; - } - - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - }; - if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { - subghz_receiver_reset(subghz->txrx->receiver); - subghz->txrx->preset->frequency = subghz_setting_get_hopper_frequency( - subghz->setting, subghz->txrx->hopper_idx_frequency); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } + subghz->lock = SubGhzLockOn; } -void subghz_speaker_on(SubGhz* subghz) { - if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { - if(furi_hal_speaker_acquire(30)) { - furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); - } else { - subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; - } - } +void subghz_unlock(SubGhz* subghz) { + furi_assert(subghz); + subghz->lock = SubGhzLockOff; } -void subghz_speaker_off(SubGhz* subghz) { - if(subghz->txrx->speaker_state != SubGhzSpeakerStateDisable) { - if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(NULL); - furi_hal_speaker_release(); - if(subghz->txrx->speaker_state == SubGhzSpeakerStateShutdown) - subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; - } - } +bool subghz_is_locked(SubGhz* subghz) { + furi_assert(subghz); + return (subghz->lock == SubGhzLockOn); } -void subghz_speaker_mute(SubGhz* subghz) { - if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { - if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(NULL); - } - } +void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state) { + furi_assert(subghz); + subghz->rx_key_state = state; } -void subghz_speaker_unmute(SubGhz* subghz) { - if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { - if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); - } - } +SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz) { + furi_assert(subghz); + return subghz->rx_key_state; } diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 65480c6fd0..fc3404c07e 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -25,10 +25,6 @@ #include #include -#include -#include -#include -#include #include "subghz_history.h" @@ -37,33 +33,11 @@ #include "rpc/rpc_app.h" -#define SUBGHZ_MAX_LEN_NAME 64 - -struct SubGhzTxRx { - SubGhzWorker* worker; - - SubGhzEnvironment* environment; - SubGhzReceiver* receiver; - SubGhzTransmitter* transmitter; - SubGhzProtocolFlag filter; - SubGhzProtocolDecoderBase* decoder_result; - FlipperFormat* fff_data; - - SubGhzRadioPreset* preset; - SubGhzHistory* history; - uint16_t idx_menu_chosen; - SubGhzTxRxState txrx_state; - SubGhzHopperState hopper_state; - SubGhzSpeakerState speaker_state; - uint8_t hopper_timeout; - uint8_t hopper_idx_frequency; - SubGhzRxKeyState rx_key_state; +#include "helpers/subghz_threshold_rssi.h" - float raw_threshold_rssi; - uint8_t raw_threshold_rssi_low_count; -}; +#include "helpers/subghz_txrx.h" -typedef struct SubGhzTxRx SubGhzTxRx; +#define SUBGHZ_MAX_LEN_NAME 64 struct SubGhz { Gui* gui; @@ -93,47 +67,43 @@ struct SubGhz { SubGhzTestStatic* subghz_test_static; SubGhzTestCarrier* subghz_test_carrier; SubGhzTestPacket* subghz_test_packet; + + SubGhzProtocolFlag filter; FuriString* error_str; - SubGhzSetting* setting; SubGhzLock lock; - + SubGhzThresholdRssi* threshold_rssi; + SubGhzRxKeyState rx_key_state; + SubGhzHistory* history; + uint16_t idx_menu_chosen; + SubGhzLoadTypeFile load_type_file; void* rpc_ctx; }; -void subghz_preset_init( - void* context, - const char* preset_name, - uint32_t frequency, - uint8_t* preset_data, - size_t preset_data_size); -bool subghz_set_preset(SubGhz* subghz, const char* preset); -void subghz_get_frequency_modulation(SubGhz* subghz, FuriString* frequency, FuriString* modulation); -void subghz_begin(SubGhz* subghz, uint8_t* preset_data); -uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency); -void subghz_rx_end(SubGhz* subghz); -void subghz_sleep(SubGhz* subghz); - -void subghz_blink_start(SubGhz* instance); -void subghz_blink_stop(SubGhz* instance); +void subghz_set_default_preset(SubGhz* subghz); +void subghz_blink_start(SubGhz* subghz); +void subghz_blink_stop(SubGhz* subghz); bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format); -void subghz_tx_stop(SubGhz* subghz); void subghz_dialog_message_show_only_rx(SubGhz* subghz); + bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog); bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len); bool subghz_save_protocol_to_file( SubGhz* subghz, FlipperFormat* flipper_format, const char* dev_file_name); +void subghz_save_to_file(void* context); bool subghz_load_protocol_from_file(SubGhz* subghz); bool subghz_rename_file(SubGhz* subghz); bool subghz_file_available(SubGhz* subghz); bool subghz_delete_file(SubGhz* subghz); void subghz_file_name_clear(SubGhz* subghz); bool subghz_path_is_file(FuriString* path); -uint32_t subghz_random_serial(void); -void subghz_hopper_update(SubGhz* subghz); -void subghz_speaker_on(SubGhz* subghz); -void subghz_speaker_off(SubGhz* subghz); -void subghz_speaker_mute(SubGhz* subghz); -void subghz_speaker_unmute(SubGhz* subghz); +SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz); + +void subghz_lock(SubGhz* subghz); +void subghz_unlock(SubGhz* subghz); +bool subghz_is_locked(SubGhz* subghz); + +void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state); +SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz); diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index acc39e2581..f84ddfed08 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -12,7 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; @@ -44,7 +44,7 @@ typedef enum { } SubGhzViewReceiverBarShow; struct SubGhzViewReceiver { - SubGhzLock lock; + bool lock; uint8_t lock_count; FuriTimer* timer; View* view; @@ -70,20 +70,21 @@ void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi) { instance->view, SubGhzViewReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); } -void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock lock) { +void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, bool lock) { furi_assert(subghz_receiver); subghz_receiver->lock_count = 0; - if(lock == SubGhzLockOn) { - subghz_receiver->lock = lock; + + if(lock == true) { + subghz_receiver->lock = true; with_view_model( subghz_receiver->view, SubGhzViewReceiverModel * model, @@ -280,7 +281,7 @@ static void subghz_view_receiver_timer_callback(void* context) { subghz_receiver->callback( SubGhzCustomEventViewReceiverOffDisplay, subghz_receiver->context); } else { - subghz_receiver->lock = SubGhzLockOff; + subghz_receiver->lock = false; subghz_receiver->callback(SubGhzCustomEventViewReceiverUnlock, subghz_receiver->context); } subghz_receiver->lock_count = 0; @@ -290,7 +291,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { furi_assert(context); SubGhzViewReceiver* subghz_receiver = context; - if(subghz_receiver->lock == SubGhzLockOn) { + if(subghz_receiver->lock == true) { with_view_model( subghz_receiver->view, SubGhzViewReceiverModel * model, @@ -310,7 +311,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { SubGhzViewReceiverModel * model, { model->bar_show = SubGhzViewReceiverBarShowUnlock; }, true); - //subghz_receiver->lock = SubGhzLockOff; + //subghz_receiver->lock = false; furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(650)); } @@ -394,7 +395,7 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() { // View allocation and configuration subghz_receiver->view = view_alloc(); - subghz_receiver->lock = SubGhzLockOff; + subghz_receiver->lock = false; subghz_receiver->lock_count = 0; view_allocate_model( subghz_receiver->view, ViewModelTypeLocking, sizeof(SubGhzViewReceiverModel)); diff --git a/applications/main/subghz/views/receiver.h b/applications/main/subghz/views/receiver.h index 9b12ccfee8..5119105e93 100644 --- a/applications/main/subghz/views/receiver.h +++ b/applications/main/subghz/views/receiver.h @@ -10,7 +10,7 @@ typedef void (*SubGhzViewReceiverCallback)(SubGhzCustomEvent event, void* contex void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi); -void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock keyboard); +void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, bool keyboard); void subghz_view_receiver_set_callback( SubGhzViewReceiver* subghz_receiver, diff --git a/applications/main/subghz/views/subghz_read_raw.c b/applications/main/subghz/views/subghz_read_raw.c index 87c8a30828..2ff598b605 100644 --- a/applications/main/subghz/views/subghz_read_raw.c +++ b/applications/main/subghz/views/subghz_read_raw.c @@ -60,10 +60,10 @@ void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi, bool tra furi_assert(instance); uint8_t u_rssi = 0; - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { u_rssi = 0; } else { - u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7); + u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7); } with_view_model( @@ -261,9 +261,9 @@ void subghz_read_raw_draw_threshold_rssi(Canvas* canvas, SubGhzReadRAWModel* mod uint8_t x = 118; uint8_t y = 48; - if(model->raw_threshold_rssi > SUBGHZ_RAW_TRESHOLD_MIN) { + if(model->raw_threshold_rssi > SUBGHZ_RAW_THRESHOLD_MIN) { uint8_t x = 118; - y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7); + y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7); uint8_t width = 3; for(uint8_t i = 0; i < x; i += width * 2) { diff --git a/applications/main/subghz/views/subghz_read_raw.h b/applications/main/subghz/views/subghz_read_raw.h index bc87119239..31aa9db6fd 100644 --- a/applications/main/subghz/views/subghz_read_raw.h +++ b/applications/main/subghz/views/subghz_read_raw.h @@ -3,7 +3,7 @@ #include #include "../helpers/subghz_custom_event.h" -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct SubGhzReadRAW SubGhzReadRAW; diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 4a13460a37..86dc17a38f 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -14,7 +14,7 @@ typedef struct { FuriString* frequency_str; FuriString* preset_str; FuriString* key_str; - uint8_t show_button; + bool show_button; } SubGhzViewTransmitterModel; void subghz_view_transmitter_set_callback( @@ -32,7 +32,7 @@ void subghz_view_transmitter_add_data_to_show( const char* key_str, const char* frequency_str, const char* preset_str, - uint8_t show_button) { + bool show_button) { furi_assert(subghz_transmitter); with_view_model( subghz_transmitter->view, @@ -104,7 +104,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { furi_string_reset(model->frequency_str); furi_string_reset(model->preset_str); furi_string_reset(model->key_str); - model->show_button = 0; + model->show_button = false; }, false); return false; diff --git a/applications/main/subghz/views/transmitter.h b/applications/main/subghz/views/transmitter.h index 64bcbd1afa..06aae7c6bf 100644 --- a/applications/main/subghz/views/transmitter.h +++ b/applications/main/subghz/views/transmitter.h @@ -23,4 +23,4 @@ void subghz_view_transmitter_add_data_to_show( const char* key_str, const char* frequency_str, const char* preset_str, - uint8_t show_button); + bool show_button); diff --git a/lib/subghz/environment.c b/lib/subghz/environment.c index b39b259d41..5ded243c41 100644 --- a/lib/subghz/environment.c +++ b/lib/subghz/environment.c @@ -16,6 +16,7 @@ SubGhzEnvironment* subghz_environment_alloc() { instance->protocol_registry = NULL; instance->came_atomo_rainbow_table_file_name = NULL; instance->nice_flor_s_rainbow_table_file_name = NULL; + instance->alutech_at_4n_rainbow_table_file_name = NULL; return instance; } @@ -26,6 +27,7 @@ void subghz_environment_free(SubGhzEnvironment* instance) { instance->protocol_registry = NULL; instance->came_atomo_rainbow_table_file_name = NULL; instance->nice_flor_s_rainbow_table_file_name = NULL; + instance->alutech_at_4n_rainbow_table_file_name = NULL; subghz_keystore_free(instance->keystore); free(instance); From a7d1ec03e878c062ba07132474720d0d54d26b97 Mon Sep 17 00:00:00 2001 From: Sergey Gavrilov Date: Wed, 3 May 2023 20:48:13 -0700 Subject: [PATCH 23/30] [FL-3270] Loader refactoring, part 1 (#2593) * Loader: menu part * Settings: remove unused loader api * Desktop: get loader from record_open * CLI: remove unneeded loader api * gitignore: ignore .old files * Loader: now really a service * Loader: working service prototype * Loader: cli, system start hooks * CI/CD: make happy * Loader: autorun * Loader: lock and unlock * Loader: rearrange code * Gui, module menu: fix memleak * Updater test: add timeout * added update timeouts and max run duration * Github: revert updater test workflow changes * Loader: less missleading message in info cli command Co-authored-by: doomwastaken Co-authored-by: Aleksandr Kutuzov --- .gitignore | 1 + applications/services/cli/cli_commands.c | 2 - .../desktop/scenes/desktop_scene_main.c | 8 +- applications/services/gui/modules/menu.c | 2 + applications/services/loader/application.fam | 9 + applications/services/loader/loader.c | 553 +++++++----------- applications/services/loader/loader.h | 13 +- applications/services/loader/loader_cli.c | 117 ++++ applications/services/loader/loader_i.h | 79 ++- applications/services/loader/loader_menu.c | 187 ++++++ applications/services/loader/loader_menu.h | 30 + .../settings/system/system_settings.c | 3 - firmware/targets/f18/api_symbols.csv | 7 +- firmware/targets/f7/api_symbols.csv | 7 +- 14 files changed, 615 insertions(+), 403 deletions(-) create mode 100644 applications/services/loader/loader_cli.c create mode 100644 applications/services/loader/loader_menu.c create mode 100644 applications/services/loader/loader_menu.h diff --git a/.gitignore b/.gitignore index 89e129acea..bf17a94e28 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.swp *.swo *.gdb_history +*.old # LSP diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index 0f042f6c48..3f94deebcf 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -220,11 +220,9 @@ void cli_command_sysctl_debug(Cli* cli, FuriString* args, void* context) { UNUSED(context); if(!furi_string_cmp(args, "0")) { furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); - loader_update_menu(); printf("Debug disabled."); } else if(!furi_string_cmp(args, "1")) { furi_hal_rtc_set_flag(FuriHalRtcFlagDebug); - loader_update_menu(); printf("Debug enabled."); } else { cli_print_usage("sysctl debug", "<1|0>", furi_string_get_cstr(args)); diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index 4d1fa49505..053ac56f1e 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -106,10 +106,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { - case DesktopMainEventOpenMenu: - loader_show_menu(); + case DesktopMainEventOpenMenu: { + Loader* loader = furi_record_open(RECORD_LOADER); + loader_show_menu(loader); + furi_record_close(RECORD_LOADER); consumed = true; - break; + } break; case DesktopMainEventOpenLockMenu: scene_manager_next_scene(desktop->scene_manager, DesktopSceneLockMenu); diff --git a/applications/services/gui/modules/menu.c b/applications/services/gui/modules/menu.c index 3e3b6c2e48..afae8b8fa2 100644 --- a/applications/services/gui/modules/menu.c +++ b/applications/services/gui/modules/menu.c @@ -154,6 +154,8 @@ Menu* menu_alloc() { void menu_free(Menu* menu) { furi_assert(menu); menu_reset(menu); + with_view_model( + menu->view, MenuModel * model, { MenuItemArray_clear(model->items); }, false); view_free(menu->view); free(menu); } diff --git a/applications/services/loader/application.fam b/applications/services/loader/application.fam index 49f3c41488..f4d006e076 100644 --- a/applications/services/loader/application.fam +++ b/applications/services/loader/application.fam @@ -5,6 +5,7 @@ App( entry_point="loader_srv", cdefines=["SRV_LOADER"], requires=["gui"], + provides=["loader_start"], stack_size=2 * 1024, order=90, sdk_headers=[ @@ -12,3 +13,11 @@ App( "firmware_api/firmware_api.h", ], ) + +App( + appid="loader_start", + apptype=FlipperAppType.STARTUP, + entry_point="loader_on_system_start", + requires=["loader"], + order=90, +) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index f83d47d63d..be16e5091f 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -1,76 +1,114 @@ -#include "applications.h" -#include -#include "loader/loader.h" +#include "loader.h" #include "loader_i.h" +#include "loader_menu.h" +#include +#include + +#define TAG "Loader" +#define LOADER_MAGIC_THREAD_VALUE 0xDEADBEEF +// api + +LoaderStatus loader_start(Loader* loader, const char* name, const char* args) { + LoaderMessage message; + LoaderMessageLoaderStatusResult result; + + message.type = LoaderMessageTypeStartByName; + message.start.name = name; + message.start.args = args; + message.api_lock = api_lock_alloc_locked(); + message.status_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} -#define TAG "LoaderSrv" - -#define LOADER_THREAD_FLAG_SHOW_MENU (1 << 0) -#define LOADER_THREAD_FLAG_ALL (LOADER_THREAD_FLAG_SHOW_MENU) - -static Loader* loader_instance = NULL; +bool loader_lock(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeLock; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} -static bool - loader_start_application(const FlipperApplication* application, const char* arguments) { - loader_instance->application = application; +void loader_unlock(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeUnlock; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} - furi_assert(loader_instance->application_arguments == NULL); - if(arguments && strlen(arguments) > 0) { - loader_instance->application_arguments = strdup(arguments); - } +bool loader_is_locked(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeIsLocked; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} - FURI_LOG_I(TAG, "Starting: %s", loader_instance->application->name); +void loader_show_menu(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeShowMenu; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} - FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); - if(mode > FuriHalRtcHeapTrackModeNone) { - furi_thread_enable_heap_trace(loader_instance->application_thread); - } else { - furi_thread_disable_heap_trace(loader_instance->application_thread); - } +FuriPubSub* loader_get_pubsub(Loader* loader) { + furi_assert(loader); + // it's safe to return pubsub without locking + // because it's never freed and loader is never exited + // also the loader instance cannot be obtained until the pubsub is created + return loader->pubsub; +} - furi_thread_set_name(loader_instance->application_thread, loader_instance->application->name); - furi_thread_set_appid( - loader_instance->application_thread, loader_instance->application->appid); - furi_thread_set_stack_size( - loader_instance->application_thread, loader_instance->application->stack_size); - furi_thread_set_context( - loader_instance->application_thread, loader_instance->application_arguments); - furi_thread_set_callback( - loader_instance->application_thread, loader_instance->application->app); +// callbacks - furi_thread_start(loader_instance->application_thread); +static void loader_menu_closed_callback(void* context) { + Loader* loader = context; + LoaderMessage message; + message.type = LoaderMessageTypeMenuClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} - return true; +static void loader_menu_click_callback(const char* name, void* context) { + Loader* loader = context; + loader_start(loader, name, NULL); } -static void loader_menu_callback(void* _ctx, uint32_t index) { - UNUSED(index); - const FlipperApplication* application = _ctx; +static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { + furi_assert(context); - furi_assert(application->app); - furi_assert(application->name); + Loader* loader = context; + LoaderEvent event; - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return; - } + if(thread_state == FuriThreadStateRunning) { + event.type = LoaderEventTypeApplicationStarted; + furi_pubsub_publish(loader->pubsub, &event); + } else if(thread_state == FuriThreadStateStopped) { + LoaderMessage message; + message.type = LoaderMessageTypeAppClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); - loader_start_application(application, NULL); + event.type = LoaderEventTypeApplicationStopped; + furi_pubsub_publish(loader->pubsub, &event); + } } -static void loader_submenu_callback(void* context, uint32_t index) { - UNUSED(index); - uint32_t view_id = (uint32_t)context; - view_dispatcher_switch_to_view(loader_instance->view_dispatcher, view_id); -} +// implementation -static void loader_cli_print_usage() { - printf("Usage:\r\n"); - printf("loader \r\n"); - printf("Cmd list:\r\n"); - printf("\tlist\t - List available applications\r\n"); - printf("\topen \t - Open application by name\r\n"); - printf("\tinfo\t - Show loader state\r\n"); +static Loader* loader_alloc() { + Loader* loader = malloc(sizeof(Loader)); + loader->pubsub = furi_pubsub_alloc(); + loader->queue = furi_message_queue_alloc(1, sizeof(LoaderMessage)); + loader->loader_menu = NULL; + loader->app.args = NULL; + loader->app.name = NULL; + loader->app.thread = NULL; + loader->app.insomniac = false; + return loader; } static FlipperApplication const* loader_find_application_by_name_in_list( @@ -85,7 +123,7 @@ static FlipperApplication const* loader_find_application_by_name_in_list( return NULL; } -const FlipperApplication* loader_find_application_by_name(const char* name) { +static const FlipperApplication* loader_find_application_by_name(const char* name) { const FlipperApplication* application = NULL; application = loader_find_application_by_name_in_list(name, FLIPPER_APPS, FLIPPER_APPS_COUNT); if(!application) { @@ -100,346 +138,167 @@ const FlipperApplication* loader_find_application_by_name(const char* name) { return application; } -static void loader_cli_open(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - if(loader_is_locked(instance)) { - if(instance->application) { - furi_assert(instance->application->name); - printf("Can't start, %s application is running", instance->application->name); - } else { - printf("Can't start, furi application is running"); - } - return; - } - - FuriString* application_name; - application_name = furi_string_alloc(); - - do { - if(!args_read_probably_quoted_string_and_trim(args, application_name)) { - printf("No application provided\r\n"); - break; - } +static void + loader_start_internal_app(Loader* loader, const FlipperApplication* app, const char* args) { + FURI_LOG_I(TAG, "Starting %s", app->name); - const FlipperApplication* application = - loader_find_application_by_name(furi_string_get_cstr(application_name)); - if(!application) { - printf("%s doesn't exists\r\n", furi_string_get_cstr(application_name)); - break; - } + // store args + furi_assert(loader->app.args == NULL); + if(args && strlen(args) > 0) { + loader->app.args = strdup(args); + } - furi_string_trim(args); - if(!loader_start_application(application, furi_string_get_cstr(args))) { - printf("Can't start, furi application is running"); - return; - } else { - // We must to increment lock counter to keep balance - // TODO: rewrite whole thing, it's complex as hell - FURI_CRITICAL_ENTER(); - instance->lock_count++; - FURI_CRITICAL_EXIT(); - } - } while(false); + // store name + furi_assert(loader->app.name == NULL); + loader->app.name = strdup(app->name); - furi_string_free(application_name); -} + // setup app thread + loader->app.thread = + furi_thread_alloc_ex(app->name, app->stack_size, app->app, loader->app.args); + furi_thread_set_appid(loader->app.thread, app->appid); -static void loader_cli_list(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - UNUSED(args); - UNUSED(instance); - printf("Applications:\r\n"); - for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { - printf("\t%s\r\n", FLIPPER_APPS[i].name); + // setup heap trace + FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); + if(mode > FuriHalRtcHeapTrackModeNone) { + furi_thread_enable_heap_trace(loader->app.thread); + } else { + furi_thread_disable_heap_trace(loader->app.thread); } -} -static void loader_cli_info(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - UNUSED(args); - if(!loader_is_locked(instance)) { - printf("No application is running\r\n"); + // setup insomnia + if(!(app->flags & FlipperApplicationFlagInsomniaSafe)) { + furi_hal_power_insomnia_enter(); + loader->app.insomniac = true; } else { - printf("Running application: "); - if(instance->application) { - furi_assert(instance->application->name); - printf("%s\r\n", instance->application->name); - } else { - printf("unknown\r\n"); - } + loader->app.insomniac = false; } -} -static void loader_cli(Cli* cli, FuriString* args, void* _ctx) { - furi_assert(_ctx); - Loader* instance = _ctx; + // setup app thread callbacks + furi_thread_set_state_context(loader->app.thread, loader); + furi_thread_set_state_callback(loader->app.thread, loader_thread_state_callback); - FuriString* cmd; - cmd = furi_string_alloc(); - - do { - if(!args_read_string_and_trim(args, cmd)) { - loader_cli_print_usage(); - break; - } - - if(furi_string_cmp_str(cmd, "list") == 0) { - loader_cli_list(cli, args, instance); - break; - } - - if(furi_string_cmp_str(cmd, "open") == 0) { - loader_cli_open(cli, args, instance); - break; - } - - if(furi_string_cmp_str(cmd, "info") == 0) { - loader_cli_info(cli, args, instance); - break; - } - - loader_cli_print_usage(); - } while(false); - - furi_string_free(cmd); + // start app thread + furi_thread_start(loader->app.thread); } -LoaderStatus loader_start(Loader* instance, const char* name, const char* args) { - UNUSED(instance); - furi_assert(name); +// process messages - const FlipperApplication* application = loader_find_application_by_name(name); - - if(!application) { - FURI_LOG_E(TAG, "Can't find application with name %s", name); - return LoaderStatusErrorUnknownApp; +static void loader_do_menu_show(Loader* loader) { + if(!loader->loader_menu) { + loader->loader_menu = loader_menu_alloc(); + loader_menu_set_closed_callback(loader->loader_menu, loader_menu_closed_callback, loader); + loader_menu_set_click_callback(loader->loader_menu, loader_menu_click_callback, loader); + loader_menu_start(loader->loader_menu); } - - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return LoaderStatusErrorAppStarted; - } - - if(!loader_start_application(application, args)) { - return LoaderStatusErrorInternal; - } - - return LoaderStatusOk; } -bool loader_lock(Loader* instance) { - FURI_CRITICAL_ENTER(); - bool result = false; - if(instance->lock_count == 0) { - instance->lock_count++; - result = true; +static void loader_do_menu_closed(Loader* loader) { + if(loader->loader_menu) { + loader_menu_stop(loader->loader_menu); + loader_menu_free(loader->loader_menu); + loader->loader_menu = NULL; } - FURI_CRITICAL_EXIT(); - return result; } -void loader_unlock(Loader* instance) { - FURI_CRITICAL_ENTER(); - if(instance->lock_count > 0) instance->lock_count--; - FURI_CRITICAL_EXIT(); +static bool loader_do_is_locked(Loader* loader) { + return loader->app.thread != NULL; } -bool loader_is_locked(const Loader* instance) { - return instance->lock_count > 0; -} - -static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { - furi_assert(context); - - Loader* instance = context; - LoaderEvent event; - - if(thread_state == FuriThreadStateRunning) { - event.type = LoaderEventTypeApplicationStarted; - furi_pubsub_publish(loader_instance->pubsub, &event); - - if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) { - furi_hal_power_insomnia_enter(); - } - } else if(thread_state == FuriThreadStateStopped) { - FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); - - if(loader_instance->application_arguments) { - free(loader_instance->application_arguments); - loader_instance->application_arguments = NULL; - } - - if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) { - furi_hal_power_insomnia_exit(); - } - loader_unlock(instance); - - event.type = LoaderEventTypeApplicationStopped; - furi_pubsub_publish(loader_instance->pubsub, &event); +static LoaderStatus loader_do_start_by_name(Loader* loader, const char* name, const char* args) { + if(loader_do_is_locked(loader)) { + return LoaderStatusErrorAppStarted; } -} -static uint32_t loader_hide_menu(void* context) { - UNUSED(context); - return VIEW_NONE; -} + const FlipperApplication* app = loader_find_application_by_name(name); -static uint32_t loader_back_to_primary_menu(void* context) { - furi_assert(context); - Submenu* submenu = context; - submenu_set_selected_item(submenu, 0); - return LoaderMenuViewPrimary; -} + if(!app) { + return LoaderStatusErrorUnknownApp; + } -static Loader* loader_alloc() { - Loader* instance = malloc(sizeof(Loader)); - - instance->application_thread = furi_thread_alloc(); - - furi_thread_set_state_context(instance->application_thread, instance); - furi_thread_set_state_callback(instance->application_thread, loader_thread_state_callback); - - instance->pubsub = furi_pubsub_alloc(); - -#ifdef SRV_CLI - instance->cli = furi_record_open(RECORD_CLI); - cli_add_command( - instance->cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, instance); -#else - UNUSED(loader_cli); -#endif - - instance->loader_thread = furi_thread_get_current_id(); - - // Gui - instance->gui = furi_record_open(RECORD_GUI); - instance->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_attach_to_gui( - instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); - // Primary menu - instance->primary_menu = menu_alloc(); - view_set_previous_callback(menu_get_view(instance->primary_menu), loader_hide_menu); - view_dispatcher_add_view( - instance->view_dispatcher, LoaderMenuViewPrimary, menu_get_view(instance->primary_menu)); - // Settings menu - instance->settings_menu = submenu_alloc(); - view_set_context(submenu_get_view(instance->settings_menu), instance->settings_menu); - view_set_previous_callback( - submenu_get_view(instance->settings_menu), loader_back_to_primary_menu); - view_dispatcher_add_view( - instance->view_dispatcher, - LoaderMenuViewSettings, - submenu_get_view(instance->settings_menu)); - - view_dispatcher_enable_queue(instance->view_dispatcher); - - return instance; + loader_start_internal_app(loader, app, args); + return LoaderStatusOk; } -static void loader_free(Loader* instance) { - furi_assert(instance); - - if(instance->cli) { - furi_record_close(RECORD_CLI); +static bool loader_do_lock(Loader* loader) { + if(loader->app.thread) { + return false; } - furi_pubsub_free(instance->pubsub); - - furi_thread_free(instance->application_thread); - - menu_free(loader_instance->primary_menu); - view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewPrimary); - submenu_free(loader_instance->settings_menu); - view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewSettings); - view_dispatcher_free(loader_instance->view_dispatcher); - - furi_record_close(RECORD_GUI); + loader->app.thread = (FuriThread*)LOADER_MAGIC_THREAD_VALUE; + return true; +} - free(instance); - instance = NULL; +static void loader_do_unlock(Loader* loader) { + furi_assert(loader->app.thread == (FuriThread*)LOADER_MAGIC_THREAD_VALUE); + loader->app.thread = NULL; } -static void loader_build_menu() { - FURI_LOG_I(TAG, "Building main menu"); - size_t i; - for(i = 0; i < FLIPPER_APPS_COUNT; i++) { - menu_add_item( - loader_instance->primary_menu, - FLIPPER_APPS[i].name, - FLIPPER_APPS[i].icon, - i, - loader_menu_callback, - (void*)&FLIPPER_APPS[i]); +static void loader_do_app_closed(Loader* loader) { + furi_assert(loader->app.thread); + FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); + if(loader->app.args) { + free(loader->app.args); + loader->app.args = NULL; } - menu_add_item( - loader_instance->primary_menu, - "Settings", - &A_Settings_14, - i++, - loader_submenu_callback, - (void*)LoaderMenuViewSettings); -} -static void loader_build_submenu() { - FURI_LOG_I(TAG, "Building settings menu"); - for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { - submenu_add_item( - loader_instance->settings_menu, - FLIPPER_SETTINGS_APPS[i].name, - i, - loader_menu_callback, - (void*)&FLIPPER_SETTINGS_APPS[i]); + if(loader->app.insomniac) { + furi_hal_power_insomnia_exit(); } -} -void loader_show_menu() { - furi_assert(loader_instance); - furi_thread_flags_set(loader_instance->loader_thread, LOADER_THREAD_FLAG_SHOW_MENU); -} + free(loader->app.name); + loader->app.name = NULL; -void loader_update_menu() { - menu_reset(loader_instance->primary_menu); - loader_build_menu(); + furi_thread_free(loader->app.thread); + loader->app.thread = NULL; } +// app + int32_t loader_srv(void* p) { UNUSED(p); + Loader* loader = loader_alloc(); + furi_record_create(RECORD_LOADER, loader); + FURI_LOG_I(TAG, "Executing system start hooks"); for(size_t i = 0; i < FLIPPER_ON_SYSTEM_START_COUNT; i++) { FLIPPER_ON_SYSTEM_START[i](); } - FURI_LOG_I(TAG, "Starting"); - loader_instance = loader_alloc(); - - loader_build_menu(); - loader_build_submenu(); - - FURI_LOG_I(TAG, "Started"); - - furi_record_create(RECORD_LOADER, loader_instance); - if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) { - loader_start(loader_instance, FLIPPER_AUTORUN_APP_NAME, NULL); + loader_do_start_by_name(loader, FLIPPER_AUTORUN_APP_NAME, NULL); } - while(1) { - uint32_t flags = - furi_thread_flags_wait(LOADER_THREAD_FLAG_ALL, FuriFlagWaitAny, FuriWaitForever); - if(flags & LOADER_THREAD_FLAG_SHOW_MENU) { - menu_set_selected_item(loader_instance->primary_menu, 0); - view_dispatcher_switch_to_view( - loader_instance->view_dispatcher, LoaderMenuViewPrimary); - view_dispatcher_run(loader_instance->view_dispatcher); + LoaderMessage message; + while(true) { + if(furi_message_queue_get(loader->queue, &message, FuriWaitForever) == FuriStatusOk) { + switch(message.type) { + case LoaderMessageTypeStartByName: + message.status_value->value = + loader_do_start_by_name(loader, message.start.name, message.start.args); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeShowMenu: + loader_do_menu_show(loader); + break; + case LoaderMessageTypeMenuClosed: + loader_do_menu_closed(loader); + break; + case LoaderMessageTypeIsLocked: + message.bool_value->value = loader_do_is_locked(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeAppClosed: + loader_do_app_closed(loader); + break; + case LoaderMessageTypeLock: + message.bool_value->value = loader_do_lock(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeUnlock: + loader_do_unlock(loader); + } } } - furi_record_destroy(RECORD_LOADER); - loader_free(loader_instance); - return 0; -} - -FuriPubSub* loader_get_pubsub(Loader* instance) { - return instance->pubsub; -} +} \ No newline at end of file diff --git a/applications/services/loader/loader.h b/applications/services/loader/loader.h index 8dbc4fc358..e3a691b768 100644 --- a/applications/services/loader/loader.h +++ b/applications/services/loader/loader.h @@ -1,7 +1,5 @@ #pragma once - -#include -#include +#include #ifdef __cplusplus extern "C" { @@ -43,17 +41,14 @@ bool loader_lock(Loader* instance); void loader_unlock(Loader* instance); /** Get loader lock status */ -bool loader_is_locked(const Loader* instance); - -/** Show primary loader */ -void loader_show_menu(); +bool loader_is_locked(Loader* instance); /** Show primary loader */ -void loader_update_menu(); +void loader_show_menu(Loader* instance); /** Show primary loader */ FuriPubSub* loader_get_pubsub(Loader* instance); #ifdef __cplusplus } -#endif +#endif \ No newline at end of file diff --git a/applications/services/loader/loader_cli.c b/applications/services/loader/loader_cli.c new file mode 100644 index 0000000000..2d46022157 --- /dev/null +++ b/applications/services/loader/loader_cli.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include "loader.h" + +static void loader_cli_print_usage() { + printf("Usage:\r\n"); + printf("loader \r\n"); + printf("Cmd list:\r\n"); + printf("\tlist\t - List available applications\r\n"); + printf("\topen \t - Open application by name\r\n"); + printf("\tinfo\t - Show loader state\r\n"); +} + +static void loader_cli_list() { + printf("Applications:\r\n"); + for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { + printf("\t%s\r\n", FLIPPER_APPS[i].name); + } + printf("Settings:\r\n"); + for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { + printf("\t%s\r\n", FLIPPER_SETTINGS_APPS[i].name); + } +} + +static void loader_cli_info(Loader* loader) { + if(!loader_is_locked(loader)) { + printf("No application is running\r\n"); + } else { + // TODO: print application name ??? + printf("Application is running\r\n"); + } +} + +static void loader_cli_open(FuriString* args, Loader* loader) { + FuriString* app_name = furi_string_alloc(); + + do { + if(!args_read_probably_quoted_string_and_trim(args, app_name)) { + printf("No application provided\r\n"); + break; + } + furi_string_trim(args); + + const char* args_str = furi_string_get_cstr(args); + if(strlen(args_str) == 0) { + args_str = NULL; + } + + const char* app_name_str = furi_string_get_cstr(app_name); + + LoaderStatus status = loader_start(loader, app_name_str, args_str); + + switch(status) { + case LoaderStatusOk: + break; + case LoaderStatusErrorAppStarted: + printf("Can't start, application is running"); + break; + case LoaderStatusErrorUnknownApp: + printf("%s doesn't exists\r\n", app_name_str); + break; + case LoaderStatusErrorInternal: + printf("Internal error\r\n"); + break; + } + } while(false); + + furi_string_free(app_name); +} + +static void loader_cli(Cli* cli, FuriString* args, void* context) { + UNUSED(cli); + UNUSED(context); + Loader* loader = furi_record_open(RECORD_LOADER); + + FuriString* cmd; + cmd = furi_string_alloc(); + + do { + if(!args_read_string_and_trim(args, cmd)) { + loader_cli_print_usage(); + break; + } + + if(furi_string_cmp_str(cmd, "list") == 0) { + loader_cli_list(); + break; + } + + if(furi_string_cmp_str(cmd, "open") == 0) { + loader_cli_open(args, loader); + break; + } + + if(furi_string_cmp_str(cmd, "info") == 0) { + loader_cli_info(loader); + break; + } + + loader_cli_print_usage(); + } while(false); + + furi_string_free(cmd); + furi_record_close(RECORD_LOADER); +} + +void loader_on_system_start() { +#ifdef SRV_CLI + Cli* cli = furi_record_open(RECORD_CLI); + cli_add_command(cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, NULL); + furi_record_close(RECORD_CLI); +#else + UNUSED(loader_cli); +#endif +} \ No newline at end of file diff --git a/applications/services/loader/loader_i.h b/applications/services/loader/loader_i.h index 00028cd6b1..2e3f10dad0 100644 --- a/applications/services/loader/loader_i.h +++ b/applications/services/loader/loader_i.h @@ -1,39 +1,56 @@ -#include "loader.h" - +#pragma once #include -#include -#include -#include -#include - -#include - -#include -#include +#include +#include "loader.h" +#include "loader_menu.h" -#include -#include +typedef struct { + char* args; + char* name; + FuriThread* thread; + bool insomniac; +} LoaderAppData; struct Loader { - FuriThreadId loader_thread; - - const FlipperApplication* application; - FuriThread* application_thread; - char* application_arguments; - - Cli* cli; - Gui* gui; - - ViewDispatcher* view_dispatcher; - Menu* primary_menu; - Submenu* settings_menu; - - volatile uint8_t lock_count; - FuriPubSub* pubsub; + FuriMessageQueue* queue; + LoaderMenu* loader_menu; + LoaderAppData app; }; typedef enum { - LoaderMenuViewPrimary, - LoaderMenuViewSettings, -} LoaderMenuView; + LoaderMessageTypeStartByName, + LoaderMessageTypeAppClosed, + LoaderMessageTypeShowMenu, + LoaderMessageTypeMenuClosed, + LoaderMessageTypeLock, + LoaderMessageTypeUnlock, + LoaderMessageTypeIsLocked, +} LoaderMessageType; + +typedef struct { + const char* name; + const char* args; +} LoaderMessageStartByName; + +typedef struct { + LoaderStatus value; +} LoaderMessageLoaderStatusResult; + +typedef struct { + bool value; +} LoaderMessageBoolResult; + +typedef struct { + FuriApiLock api_lock; + LoaderMessageType type; + + union { + LoaderMessageStartByName start; + }; + + union { + LoaderMessageLoaderStatusResult* status_value; + LoaderMessageBoolResult* bool_value; + }; +} LoaderMessage; diff --git a/applications/services/loader/loader_menu.c b/applications/services/loader/loader_menu.c new file mode 100644 index 0000000000..ec853661fb --- /dev/null +++ b/applications/services/loader/loader_menu.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include + +#include "loader_menu.h" + +#define TAG "LoaderMenu" + +struct LoaderMenu { + Gui* gui; + ViewDispatcher* view_dispatcher; + Menu* primary_menu; + Submenu* settings_menu; + + void (*closed_callback)(void*); + void* closed_callback_context; + + void (*click_callback)(const char*, void*); + void* click_callback_context; + + FuriThread* thread; +}; + +typedef enum { + LoaderMenuViewPrimary, + LoaderMenuViewSettings, +} LoaderMenuView; + +static int32_t loader_menu_thread(void* p); + +LoaderMenu* loader_menu_alloc() { + LoaderMenu* loader_menu = malloc(sizeof(LoaderMenu)); + loader_menu->gui = furi_record_open(RECORD_GUI); + loader_menu->view_dispatcher = view_dispatcher_alloc(); + loader_menu->primary_menu = menu_alloc(); + loader_menu->settings_menu = submenu_alloc(); + loader_menu->thread = NULL; + return loader_menu; +} + +void loader_menu_free(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + // check if thread is running + furi_assert(!loader_menu->thread); + + submenu_free(loader_menu->settings_menu); + menu_free(loader_menu->primary_menu); + view_dispatcher_free(loader_menu->view_dispatcher); + furi_record_close(RECORD_GUI); + free(loader_menu); +} + +void loader_menu_start(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + furi_assert(!loader_menu->thread); + loader_menu->thread = furi_thread_alloc_ex(TAG, 1024, loader_menu_thread, loader_menu); + furi_thread_start(loader_menu->thread); +} + +void loader_menu_stop(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + furi_assert(loader_menu->thread); + view_dispatcher_stop(loader_menu->view_dispatcher); + furi_thread_join(loader_menu->thread); + furi_thread_free(loader_menu->thread); + loader_menu->thread = NULL; +} + +void loader_menu_set_closed_callback( + LoaderMenu* loader_menu, + void (*callback)(void*), + void* context) { + loader_menu->closed_callback = callback; + loader_menu->closed_callback_context = context; +} + +void loader_menu_set_click_callback( + LoaderMenu* loader_menu, + void (*callback)(const char*, void*), + void* context) { + loader_menu->click_callback = callback; + loader_menu->click_callback_context = context; +} + +static void loader_menu_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* name = FLIPPER_APPS[index].name; + if(loader_menu->click_callback) { + loader_menu->click_callback(name, loader_menu->click_callback_context); + } +} + +static void loader_menu_settings_menu_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* name = FLIPPER_SETTINGS_APPS[index].name; + if(loader_menu->click_callback) { + loader_menu->click_callback(name, loader_menu->click_callback_context); + } +} + +static void loader_menu_switch_to_settings(void* context, uint32_t index) { + UNUSED(index); + LoaderMenu* loader_menu = context; + view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); +} + +static uint32_t loader_menu_switch_to_primary(void* context) { + UNUSED(context); + return LoaderMenuViewPrimary; +} + +static uint32_t loader_menu_exit(void* context) { + UNUSED(context); + return VIEW_NONE; +} + +static void loader_menu_build_menu(LoaderMenu* loader_menu) { + size_t i; + for(i = 0; i < FLIPPER_APPS_COUNT; i++) { + menu_add_item( + loader_menu->primary_menu, + FLIPPER_APPS[i].name, + FLIPPER_APPS[i].icon, + i, + loader_menu_callback, + (void*)loader_menu); + } + menu_add_item( + loader_menu->primary_menu, + "Settings", + &A_Settings_14, + i++, + loader_menu_switch_to_settings, + loader_menu); +}; + +static void loader_menu_build_submenu(LoaderMenu* loader_menu) { + for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { + submenu_add_item( + loader_menu->settings_menu, + FLIPPER_SETTINGS_APPS[i].name, + i, + loader_menu_settings_menu_callback, + loader_menu); + } +} + +static int32_t loader_menu_thread(void* p) { + LoaderMenu* loader_menu = p; + furi_assert(loader_menu); + + loader_menu_build_menu(loader_menu); + loader_menu_build_submenu(loader_menu); + + view_dispatcher_attach_to_gui( + loader_menu->view_dispatcher, loader_menu->gui, ViewDispatcherTypeFullscreen); + + // Primary menu + View* primary_view = menu_get_view(loader_menu->primary_menu); + view_set_context(primary_view, loader_menu->primary_menu); + view_set_previous_callback(primary_view, loader_menu_exit); + view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary, primary_view); + + // Settings menu + View* settings_view = submenu_get_view(loader_menu->settings_menu); + view_set_context(settings_view, loader_menu->settings_menu); + view_set_previous_callback(settings_view, loader_menu_switch_to_primary); + view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewSettings, settings_view); + + view_dispatcher_enable_queue(loader_menu->view_dispatcher); + view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); + + // run view dispatcher + view_dispatcher_run(loader_menu->view_dispatcher); + + view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); + view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); + + if(loader_menu->closed_callback) { + loader_menu->closed_callback(loader_menu->closed_callback_context); + } + + return 0; +} \ No newline at end of file diff --git a/applications/services/loader/loader_menu.h b/applications/services/loader/loader_menu.h new file mode 100644 index 0000000000..7405b87be7 --- /dev/null +++ b/applications/services/loader/loader_menu.h @@ -0,0 +1,30 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct LoaderMenu LoaderMenu; + +LoaderMenu* loader_menu_alloc(); + +void loader_menu_free(LoaderMenu* loader_menu); + +void loader_menu_start(LoaderMenu* loader_menu); + +void loader_menu_stop(LoaderMenu* loader_menu); + +void loader_menu_set_closed_callback( + LoaderMenu* loader_menu, + void (*callback)(void*), + void* context); + +void loader_menu_set_click_callback( + LoaderMenu* loader_menu, + void (*callback)(const char*, void*), + void* context); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/settings/system/system_settings.c b/applications/settings/system/system_settings.c index 597710a53f..dd3c0dc6bd 100644 --- a/applications/settings/system/system_settings.c +++ b/applications/settings/system/system_settings.c @@ -43,7 +43,6 @@ static void debug_changed(VariableItem* item) { } else { furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); } - loader_update_menu(); } const char* const heap_trace_mode_text[] = { @@ -137,8 +136,6 @@ static void hand_orient_changed(VariableItem* item) { } else { furi_hal_rtc_reset_flag(FuriHalRtcFlagHandOrient); } - - loader_update_menu(); } const char* const sleep_method[] = { diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index f84bf074e1..bc6844d350 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.3,, +Version,+,24.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1375,12 +1375,11 @@ Function,-,ldiv,ldiv_t,"long, long" Function,-,llabs,long long,long long Function,-,lldiv,lldiv_t,"long long, long long" Function,+,loader_get_pubsub,FuriPubSub*,Loader* -Function,+,loader_is_locked,_Bool,const Loader* +Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* -Function,+,loader_show_menu,void, +Function,+,loader_show_menu,void,Loader* Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* -Function,+,loader_update_menu,void, Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* Function,+,loading_get_view,View*,Loading* diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index c176b2d7e1..1c8424fe8c 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.3,, +Version,+,24.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1795,12 +1795,11 @@ Function,-,llround,long long int,double Function,-,llroundf,long long int,float Function,-,llroundl,long long int,long double Function,+,loader_get_pubsub,FuriPubSub*,Loader* -Function,+,loader_is_locked,_Bool,const Loader* +Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* -Function,+,loader_show_menu,void, +Function,+,loader_show_menu,void,Loader* Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* -Function,+,loader_update_menu,void, Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* Function,+,loading_get_view,View*,Loading* From ac05387803b7f0c71594959b1c060fb765a58d29 Mon Sep 17 00:00:00 2001 From: Sergey Gavrilov Date: Wed, 3 May 2023 20:48:13 -0700 Subject: [PATCH 24/30] [FL-3270] Loader refactoring, part 1 (#2593) * Loader: menu part * Settings: remove unused loader api * Desktop: get loader from record_open * CLI: remove unneeded loader api * gitignore: ignore .old files * Loader: now really a service * Loader: working service prototype * Loader: cli, system start hooks * CI/CD: make happy * Loader: autorun * Loader: lock and unlock * Loader: rearrange code * Gui, module menu: fix memleak * Updater test: add timeout * added update timeouts and max run duration * Github: revert updater test workflow changes * Loader: less missleading message in info cli command Co-authored-by: doomwastaken Co-authored-by: Aleksandr Kutuzov --- .gitignore | 1 + applications/services/cli/cli_commands.c | 2 - .../desktop/scenes/desktop_scene_main.c | 8 +- applications/services/loader/application.fam | 9 + applications/services/loader/loader.c | 553 +++++++----------- applications/services/loader/loader.h | 13 +- applications/services/loader/loader_cli.c | 117 ++++ applications/services/loader/loader_i.h | 79 ++- applications/services/loader/loader_menu.c | 187 ++++++ applications/services/loader/loader_menu.h | 30 + .../settings/system/system_settings.c | 3 - firmware/targets/f18/api_symbols.csv | 7 +- firmware/targets/f7/api_symbols.csv | 7 +- 13 files changed, 613 insertions(+), 403 deletions(-) create mode 100644 applications/services/loader/loader_cli.c create mode 100644 applications/services/loader/loader_menu.c create mode 100644 applications/services/loader/loader_menu.h diff --git a/.gitignore b/.gitignore index eacfec1e49..f199a48beb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.swp *.swo *.gdb_history +*.old # LSP diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index 4e3e1104ae..a6b23c9422 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -230,11 +230,9 @@ void cli_command_sysctl_debug(Cli* cli, FuriString* args, void* context) { UNUSED(context); if(!furi_string_cmp(args, "0")) { furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); - loader_update_menu(); printf("Debug disabled."); } else if(!furi_string_cmp(args, "1")) { furi_hal_rtc_set_flag(FuriHalRtcFlagDebug); - loader_update_menu(); printf("Debug enabled."); } else { cli_print_usage("sysctl debug", "<1|0>", furi_string_get_cstr(args)); diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index fd04ff917e..9109ef309f 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -90,10 +90,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { - case DesktopMainEventOpenMenu: - loader_show_menu(); + case DesktopMainEventOpenMenu: { + Loader* loader = furi_record_open(RECORD_LOADER); + loader_show_menu(loader); + furi_record_close(RECORD_LOADER); consumed = true; - break; + } break; case DesktopMainEventOpenLockMenu: scene_manager_next_scene(desktop->scene_manager, DesktopSceneLockMenu); diff --git a/applications/services/loader/application.fam b/applications/services/loader/application.fam index 49f3c41488..f4d006e076 100644 --- a/applications/services/loader/application.fam +++ b/applications/services/loader/application.fam @@ -5,6 +5,7 @@ App( entry_point="loader_srv", cdefines=["SRV_LOADER"], requires=["gui"], + provides=["loader_start"], stack_size=2 * 1024, order=90, sdk_headers=[ @@ -12,3 +13,11 @@ App( "firmware_api/firmware_api.h", ], ) + +App( + appid="loader_start", + apptype=FlipperAppType.STARTUP, + entry_point="loader_on_system_start", + requires=["loader"], + order=90, +) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index f83d47d63d..be16e5091f 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -1,76 +1,114 @@ -#include "applications.h" -#include -#include "loader/loader.h" +#include "loader.h" #include "loader_i.h" +#include "loader_menu.h" +#include +#include + +#define TAG "Loader" +#define LOADER_MAGIC_THREAD_VALUE 0xDEADBEEF +// api + +LoaderStatus loader_start(Loader* loader, const char* name, const char* args) { + LoaderMessage message; + LoaderMessageLoaderStatusResult result; + + message.type = LoaderMessageTypeStartByName; + message.start.name = name; + message.start.args = args; + message.api_lock = api_lock_alloc_locked(); + message.status_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} -#define TAG "LoaderSrv" - -#define LOADER_THREAD_FLAG_SHOW_MENU (1 << 0) -#define LOADER_THREAD_FLAG_ALL (LOADER_THREAD_FLAG_SHOW_MENU) - -static Loader* loader_instance = NULL; +bool loader_lock(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeLock; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} -static bool - loader_start_application(const FlipperApplication* application, const char* arguments) { - loader_instance->application = application; +void loader_unlock(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeUnlock; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} - furi_assert(loader_instance->application_arguments == NULL); - if(arguments && strlen(arguments) > 0) { - loader_instance->application_arguments = strdup(arguments); - } +bool loader_is_locked(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeIsLocked; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} - FURI_LOG_I(TAG, "Starting: %s", loader_instance->application->name); +void loader_show_menu(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeShowMenu; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} - FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); - if(mode > FuriHalRtcHeapTrackModeNone) { - furi_thread_enable_heap_trace(loader_instance->application_thread); - } else { - furi_thread_disable_heap_trace(loader_instance->application_thread); - } +FuriPubSub* loader_get_pubsub(Loader* loader) { + furi_assert(loader); + // it's safe to return pubsub without locking + // because it's never freed and loader is never exited + // also the loader instance cannot be obtained until the pubsub is created + return loader->pubsub; +} - furi_thread_set_name(loader_instance->application_thread, loader_instance->application->name); - furi_thread_set_appid( - loader_instance->application_thread, loader_instance->application->appid); - furi_thread_set_stack_size( - loader_instance->application_thread, loader_instance->application->stack_size); - furi_thread_set_context( - loader_instance->application_thread, loader_instance->application_arguments); - furi_thread_set_callback( - loader_instance->application_thread, loader_instance->application->app); +// callbacks - furi_thread_start(loader_instance->application_thread); +static void loader_menu_closed_callback(void* context) { + Loader* loader = context; + LoaderMessage message; + message.type = LoaderMessageTypeMenuClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} - return true; +static void loader_menu_click_callback(const char* name, void* context) { + Loader* loader = context; + loader_start(loader, name, NULL); } -static void loader_menu_callback(void* _ctx, uint32_t index) { - UNUSED(index); - const FlipperApplication* application = _ctx; +static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { + furi_assert(context); - furi_assert(application->app); - furi_assert(application->name); + Loader* loader = context; + LoaderEvent event; - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return; - } + if(thread_state == FuriThreadStateRunning) { + event.type = LoaderEventTypeApplicationStarted; + furi_pubsub_publish(loader->pubsub, &event); + } else if(thread_state == FuriThreadStateStopped) { + LoaderMessage message; + message.type = LoaderMessageTypeAppClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); - loader_start_application(application, NULL); + event.type = LoaderEventTypeApplicationStopped; + furi_pubsub_publish(loader->pubsub, &event); + } } -static void loader_submenu_callback(void* context, uint32_t index) { - UNUSED(index); - uint32_t view_id = (uint32_t)context; - view_dispatcher_switch_to_view(loader_instance->view_dispatcher, view_id); -} +// implementation -static void loader_cli_print_usage() { - printf("Usage:\r\n"); - printf("loader \r\n"); - printf("Cmd list:\r\n"); - printf("\tlist\t - List available applications\r\n"); - printf("\topen \t - Open application by name\r\n"); - printf("\tinfo\t - Show loader state\r\n"); +static Loader* loader_alloc() { + Loader* loader = malloc(sizeof(Loader)); + loader->pubsub = furi_pubsub_alloc(); + loader->queue = furi_message_queue_alloc(1, sizeof(LoaderMessage)); + loader->loader_menu = NULL; + loader->app.args = NULL; + loader->app.name = NULL; + loader->app.thread = NULL; + loader->app.insomniac = false; + return loader; } static FlipperApplication const* loader_find_application_by_name_in_list( @@ -85,7 +123,7 @@ static FlipperApplication const* loader_find_application_by_name_in_list( return NULL; } -const FlipperApplication* loader_find_application_by_name(const char* name) { +static const FlipperApplication* loader_find_application_by_name(const char* name) { const FlipperApplication* application = NULL; application = loader_find_application_by_name_in_list(name, FLIPPER_APPS, FLIPPER_APPS_COUNT); if(!application) { @@ -100,346 +138,167 @@ const FlipperApplication* loader_find_application_by_name(const char* name) { return application; } -static void loader_cli_open(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - if(loader_is_locked(instance)) { - if(instance->application) { - furi_assert(instance->application->name); - printf("Can't start, %s application is running", instance->application->name); - } else { - printf("Can't start, furi application is running"); - } - return; - } - - FuriString* application_name; - application_name = furi_string_alloc(); - - do { - if(!args_read_probably_quoted_string_and_trim(args, application_name)) { - printf("No application provided\r\n"); - break; - } +static void + loader_start_internal_app(Loader* loader, const FlipperApplication* app, const char* args) { + FURI_LOG_I(TAG, "Starting %s", app->name); - const FlipperApplication* application = - loader_find_application_by_name(furi_string_get_cstr(application_name)); - if(!application) { - printf("%s doesn't exists\r\n", furi_string_get_cstr(application_name)); - break; - } + // store args + furi_assert(loader->app.args == NULL); + if(args && strlen(args) > 0) { + loader->app.args = strdup(args); + } - furi_string_trim(args); - if(!loader_start_application(application, furi_string_get_cstr(args))) { - printf("Can't start, furi application is running"); - return; - } else { - // We must to increment lock counter to keep balance - // TODO: rewrite whole thing, it's complex as hell - FURI_CRITICAL_ENTER(); - instance->lock_count++; - FURI_CRITICAL_EXIT(); - } - } while(false); + // store name + furi_assert(loader->app.name == NULL); + loader->app.name = strdup(app->name); - furi_string_free(application_name); -} + // setup app thread + loader->app.thread = + furi_thread_alloc_ex(app->name, app->stack_size, app->app, loader->app.args); + furi_thread_set_appid(loader->app.thread, app->appid); -static void loader_cli_list(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - UNUSED(args); - UNUSED(instance); - printf("Applications:\r\n"); - for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { - printf("\t%s\r\n", FLIPPER_APPS[i].name); + // setup heap trace + FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); + if(mode > FuriHalRtcHeapTrackModeNone) { + furi_thread_enable_heap_trace(loader->app.thread); + } else { + furi_thread_disable_heap_trace(loader->app.thread); } -} -static void loader_cli_info(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - UNUSED(args); - if(!loader_is_locked(instance)) { - printf("No application is running\r\n"); + // setup insomnia + if(!(app->flags & FlipperApplicationFlagInsomniaSafe)) { + furi_hal_power_insomnia_enter(); + loader->app.insomniac = true; } else { - printf("Running application: "); - if(instance->application) { - furi_assert(instance->application->name); - printf("%s\r\n", instance->application->name); - } else { - printf("unknown\r\n"); - } + loader->app.insomniac = false; } -} -static void loader_cli(Cli* cli, FuriString* args, void* _ctx) { - furi_assert(_ctx); - Loader* instance = _ctx; + // setup app thread callbacks + furi_thread_set_state_context(loader->app.thread, loader); + furi_thread_set_state_callback(loader->app.thread, loader_thread_state_callback); - FuriString* cmd; - cmd = furi_string_alloc(); - - do { - if(!args_read_string_and_trim(args, cmd)) { - loader_cli_print_usage(); - break; - } - - if(furi_string_cmp_str(cmd, "list") == 0) { - loader_cli_list(cli, args, instance); - break; - } - - if(furi_string_cmp_str(cmd, "open") == 0) { - loader_cli_open(cli, args, instance); - break; - } - - if(furi_string_cmp_str(cmd, "info") == 0) { - loader_cli_info(cli, args, instance); - break; - } - - loader_cli_print_usage(); - } while(false); - - furi_string_free(cmd); + // start app thread + furi_thread_start(loader->app.thread); } -LoaderStatus loader_start(Loader* instance, const char* name, const char* args) { - UNUSED(instance); - furi_assert(name); +// process messages - const FlipperApplication* application = loader_find_application_by_name(name); - - if(!application) { - FURI_LOG_E(TAG, "Can't find application with name %s", name); - return LoaderStatusErrorUnknownApp; +static void loader_do_menu_show(Loader* loader) { + if(!loader->loader_menu) { + loader->loader_menu = loader_menu_alloc(); + loader_menu_set_closed_callback(loader->loader_menu, loader_menu_closed_callback, loader); + loader_menu_set_click_callback(loader->loader_menu, loader_menu_click_callback, loader); + loader_menu_start(loader->loader_menu); } - - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return LoaderStatusErrorAppStarted; - } - - if(!loader_start_application(application, args)) { - return LoaderStatusErrorInternal; - } - - return LoaderStatusOk; } -bool loader_lock(Loader* instance) { - FURI_CRITICAL_ENTER(); - bool result = false; - if(instance->lock_count == 0) { - instance->lock_count++; - result = true; +static void loader_do_menu_closed(Loader* loader) { + if(loader->loader_menu) { + loader_menu_stop(loader->loader_menu); + loader_menu_free(loader->loader_menu); + loader->loader_menu = NULL; } - FURI_CRITICAL_EXIT(); - return result; } -void loader_unlock(Loader* instance) { - FURI_CRITICAL_ENTER(); - if(instance->lock_count > 0) instance->lock_count--; - FURI_CRITICAL_EXIT(); +static bool loader_do_is_locked(Loader* loader) { + return loader->app.thread != NULL; } -bool loader_is_locked(const Loader* instance) { - return instance->lock_count > 0; -} - -static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { - furi_assert(context); - - Loader* instance = context; - LoaderEvent event; - - if(thread_state == FuriThreadStateRunning) { - event.type = LoaderEventTypeApplicationStarted; - furi_pubsub_publish(loader_instance->pubsub, &event); - - if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) { - furi_hal_power_insomnia_enter(); - } - } else if(thread_state == FuriThreadStateStopped) { - FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); - - if(loader_instance->application_arguments) { - free(loader_instance->application_arguments); - loader_instance->application_arguments = NULL; - } - - if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) { - furi_hal_power_insomnia_exit(); - } - loader_unlock(instance); - - event.type = LoaderEventTypeApplicationStopped; - furi_pubsub_publish(loader_instance->pubsub, &event); +static LoaderStatus loader_do_start_by_name(Loader* loader, const char* name, const char* args) { + if(loader_do_is_locked(loader)) { + return LoaderStatusErrorAppStarted; } -} -static uint32_t loader_hide_menu(void* context) { - UNUSED(context); - return VIEW_NONE; -} + const FlipperApplication* app = loader_find_application_by_name(name); -static uint32_t loader_back_to_primary_menu(void* context) { - furi_assert(context); - Submenu* submenu = context; - submenu_set_selected_item(submenu, 0); - return LoaderMenuViewPrimary; -} + if(!app) { + return LoaderStatusErrorUnknownApp; + } -static Loader* loader_alloc() { - Loader* instance = malloc(sizeof(Loader)); - - instance->application_thread = furi_thread_alloc(); - - furi_thread_set_state_context(instance->application_thread, instance); - furi_thread_set_state_callback(instance->application_thread, loader_thread_state_callback); - - instance->pubsub = furi_pubsub_alloc(); - -#ifdef SRV_CLI - instance->cli = furi_record_open(RECORD_CLI); - cli_add_command( - instance->cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, instance); -#else - UNUSED(loader_cli); -#endif - - instance->loader_thread = furi_thread_get_current_id(); - - // Gui - instance->gui = furi_record_open(RECORD_GUI); - instance->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_attach_to_gui( - instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); - // Primary menu - instance->primary_menu = menu_alloc(); - view_set_previous_callback(menu_get_view(instance->primary_menu), loader_hide_menu); - view_dispatcher_add_view( - instance->view_dispatcher, LoaderMenuViewPrimary, menu_get_view(instance->primary_menu)); - // Settings menu - instance->settings_menu = submenu_alloc(); - view_set_context(submenu_get_view(instance->settings_menu), instance->settings_menu); - view_set_previous_callback( - submenu_get_view(instance->settings_menu), loader_back_to_primary_menu); - view_dispatcher_add_view( - instance->view_dispatcher, - LoaderMenuViewSettings, - submenu_get_view(instance->settings_menu)); - - view_dispatcher_enable_queue(instance->view_dispatcher); - - return instance; + loader_start_internal_app(loader, app, args); + return LoaderStatusOk; } -static void loader_free(Loader* instance) { - furi_assert(instance); - - if(instance->cli) { - furi_record_close(RECORD_CLI); +static bool loader_do_lock(Loader* loader) { + if(loader->app.thread) { + return false; } - furi_pubsub_free(instance->pubsub); - - furi_thread_free(instance->application_thread); - - menu_free(loader_instance->primary_menu); - view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewPrimary); - submenu_free(loader_instance->settings_menu); - view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewSettings); - view_dispatcher_free(loader_instance->view_dispatcher); - - furi_record_close(RECORD_GUI); + loader->app.thread = (FuriThread*)LOADER_MAGIC_THREAD_VALUE; + return true; +} - free(instance); - instance = NULL; +static void loader_do_unlock(Loader* loader) { + furi_assert(loader->app.thread == (FuriThread*)LOADER_MAGIC_THREAD_VALUE); + loader->app.thread = NULL; } -static void loader_build_menu() { - FURI_LOG_I(TAG, "Building main menu"); - size_t i; - for(i = 0; i < FLIPPER_APPS_COUNT; i++) { - menu_add_item( - loader_instance->primary_menu, - FLIPPER_APPS[i].name, - FLIPPER_APPS[i].icon, - i, - loader_menu_callback, - (void*)&FLIPPER_APPS[i]); +static void loader_do_app_closed(Loader* loader) { + furi_assert(loader->app.thread); + FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); + if(loader->app.args) { + free(loader->app.args); + loader->app.args = NULL; } - menu_add_item( - loader_instance->primary_menu, - "Settings", - &A_Settings_14, - i++, - loader_submenu_callback, - (void*)LoaderMenuViewSettings); -} -static void loader_build_submenu() { - FURI_LOG_I(TAG, "Building settings menu"); - for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { - submenu_add_item( - loader_instance->settings_menu, - FLIPPER_SETTINGS_APPS[i].name, - i, - loader_menu_callback, - (void*)&FLIPPER_SETTINGS_APPS[i]); + if(loader->app.insomniac) { + furi_hal_power_insomnia_exit(); } -} -void loader_show_menu() { - furi_assert(loader_instance); - furi_thread_flags_set(loader_instance->loader_thread, LOADER_THREAD_FLAG_SHOW_MENU); -} + free(loader->app.name); + loader->app.name = NULL; -void loader_update_menu() { - menu_reset(loader_instance->primary_menu); - loader_build_menu(); + furi_thread_free(loader->app.thread); + loader->app.thread = NULL; } +// app + int32_t loader_srv(void* p) { UNUSED(p); + Loader* loader = loader_alloc(); + furi_record_create(RECORD_LOADER, loader); + FURI_LOG_I(TAG, "Executing system start hooks"); for(size_t i = 0; i < FLIPPER_ON_SYSTEM_START_COUNT; i++) { FLIPPER_ON_SYSTEM_START[i](); } - FURI_LOG_I(TAG, "Starting"); - loader_instance = loader_alloc(); - - loader_build_menu(); - loader_build_submenu(); - - FURI_LOG_I(TAG, "Started"); - - furi_record_create(RECORD_LOADER, loader_instance); - if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) { - loader_start(loader_instance, FLIPPER_AUTORUN_APP_NAME, NULL); + loader_do_start_by_name(loader, FLIPPER_AUTORUN_APP_NAME, NULL); } - while(1) { - uint32_t flags = - furi_thread_flags_wait(LOADER_THREAD_FLAG_ALL, FuriFlagWaitAny, FuriWaitForever); - if(flags & LOADER_THREAD_FLAG_SHOW_MENU) { - menu_set_selected_item(loader_instance->primary_menu, 0); - view_dispatcher_switch_to_view( - loader_instance->view_dispatcher, LoaderMenuViewPrimary); - view_dispatcher_run(loader_instance->view_dispatcher); + LoaderMessage message; + while(true) { + if(furi_message_queue_get(loader->queue, &message, FuriWaitForever) == FuriStatusOk) { + switch(message.type) { + case LoaderMessageTypeStartByName: + message.status_value->value = + loader_do_start_by_name(loader, message.start.name, message.start.args); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeShowMenu: + loader_do_menu_show(loader); + break; + case LoaderMessageTypeMenuClosed: + loader_do_menu_closed(loader); + break; + case LoaderMessageTypeIsLocked: + message.bool_value->value = loader_do_is_locked(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeAppClosed: + loader_do_app_closed(loader); + break; + case LoaderMessageTypeLock: + message.bool_value->value = loader_do_lock(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeUnlock: + loader_do_unlock(loader); + } } } - furi_record_destroy(RECORD_LOADER); - loader_free(loader_instance); - return 0; -} - -FuriPubSub* loader_get_pubsub(Loader* instance) { - return instance->pubsub; -} +} \ No newline at end of file diff --git a/applications/services/loader/loader.h b/applications/services/loader/loader.h index 8dbc4fc358..e3a691b768 100644 --- a/applications/services/loader/loader.h +++ b/applications/services/loader/loader.h @@ -1,7 +1,5 @@ #pragma once - -#include -#include +#include #ifdef __cplusplus extern "C" { @@ -43,17 +41,14 @@ bool loader_lock(Loader* instance); void loader_unlock(Loader* instance); /** Get loader lock status */ -bool loader_is_locked(const Loader* instance); - -/** Show primary loader */ -void loader_show_menu(); +bool loader_is_locked(Loader* instance); /** Show primary loader */ -void loader_update_menu(); +void loader_show_menu(Loader* instance); /** Show primary loader */ FuriPubSub* loader_get_pubsub(Loader* instance); #ifdef __cplusplus } -#endif +#endif \ No newline at end of file diff --git a/applications/services/loader/loader_cli.c b/applications/services/loader/loader_cli.c new file mode 100644 index 0000000000..2d46022157 --- /dev/null +++ b/applications/services/loader/loader_cli.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include "loader.h" + +static void loader_cli_print_usage() { + printf("Usage:\r\n"); + printf("loader \r\n"); + printf("Cmd list:\r\n"); + printf("\tlist\t - List available applications\r\n"); + printf("\topen \t - Open application by name\r\n"); + printf("\tinfo\t - Show loader state\r\n"); +} + +static void loader_cli_list() { + printf("Applications:\r\n"); + for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { + printf("\t%s\r\n", FLIPPER_APPS[i].name); + } + printf("Settings:\r\n"); + for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { + printf("\t%s\r\n", FLIPPER_SETTINGS_APPS[i].name); + } +} + +static void loader_cli_info(Loader* loader) { + if(!loader_is_locked(loader)) { + printf("No application is running\r\n"); + } else { + // TODO: print application name ??? + printf("Application is running\r\n"); + } +} + +static void loader_cli_open(FuriString* args, Loader* loader) { + FuriString* app_name = furi_string_alloc(); + + do { + if(!args_read_probably_quoted_string_and_trim(args, app_name)) { + printf("No application provided\r\n"); + break; + } + furi_string_trim(args); + + const char* args_str = furi_string_get_cstr(args); + if(strlen(args_str) == 0) { + args_str = NULL; + } + + const char* app_name_str = furi_string_get_cstr(app_name); + + LoaderStatus status = loader_start(loader, app_name_str, args_str); + + switch(status) { + case LoaderStatusOk: + break; + case LoaderStatusErrorAppStarted: + printf("Can't start, application is running"); + break; + case LoaderStatusErrorUnknownApp: + printf("%s doesn't exists\r\n", app_name_str); + break; + case LoaderStatusErrorInternal: + printf("Internal error\r\n"); + break; + } + } while(false); + + furi_string_free(app_name); +} + +static void loader_cli(Cli* cli, FuriString* args, void* context) { + UNUSED(cli); + UNUSED(context); + Loader* loader = furi_record_open(RECORD_LOADER); + + FuriString* cmd; + cmd = furi_string_alloc(); + + do { + if(!args_read_string_and_trim(args, cmd)) { + loader_cli_print_usage(); + break; + } + + if(furi_string_cmp_str(cmd, "list") == 0) { + loader_cli_list(); + break; + } + + if(furi_string_cmp_str(cmd, "open") == 0) { + loader_cli_open(args, loader); + break; + } + + if(furi_string_cmp_str(cmd, "info") == 0) { + loader_cli_info(loader); + break; + } + + loader_cli_print_usage(); + } while(false); + + furi_string_free(cmd); + furi_record_close(RECORD_LOADER); +} + +void loader_on_system_start() { +#ifdef SRV_CLI + Cli* cli = furi_record_open(RECORD_CLI); + cli_add_command(cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, NULL); + furi_record_close(RECORD_CLI); +#else + UNUSED(loader_cli); +#endif +} \ No newline at end of file diff --git a/applications/services/loader/loader_i.h b/applications/services/loader/loader_i.h index 00028cd6b1..2e3f10dad0 100644 --- a/applications/services/loader/loader_i.h +++ b/applications/services/loader/loader_i.h @@ -1,39 +1,56 @@ -#include "loader.h" - +#pragma once #include -#include -#include -#include -#include - -#include - -#include -#include +#include +#include "loader.h" +#include "loader_menu.h" -#include -#include +typedef struct { + char* args; + char* name; + FuriThread* thread; + bool insomniac; +} LoaderAppData; struct Loader { - FuriThreadId loader_thread; - - const FlipperApplication* application; - FuriThread* application_thread; - char* application_arguments; - - Cli* cli; - Gui* gui; - - ViewDispatcher* view_dispatcher; - Menu* primary_menu; - Submenu* settings_menu; - - volatile uint8_t lock_count; - FuriPubSub* pubsub; + FuriMessageQueue* queue; + LoaderMenu* loader_menu; + LoaderAppData app; }; typedef enum { - LoaderMenuViewPrimary, - LoaderMenuViewSettings, -} LoaderMenuView; + LoaderMessageTypeStartByName, + LoaderMessageTypeAppClosed, + LoaderMessageTypeShowMenu, + LoaderMessageTypeMenuClosed, + LoaderMessageTypeLock, + LoaderMessageTypeUnlock, + LoaderMessageTypeIsLocked, +} LoaderMessageType; + +typedef struct { + const char* name; + const char* args; +} LoaderMessageStartByName; + +typedef struct { + LoaderStatus value; +} LoaderMessageLoaderStatusResult; + +typedef struct { + bool value; +} LoaderMessageBoolResult; + +typedef struct { + FuriApiLock api_lock; + LoaderMessageType type; + + union { + LoaderMessageStartByName start; + }; + + union { + LoaderMessageLoaderStatusResult* status_value; + LoaderMessageBoolResult* bool_value; + }; +} LoaderMessage; diff --git a/applications/services/loader/loader_menu.c b/applications/services/loader/loader_menu.c new file mode 100644 index 0000000000..ec853661fb --- /dev/null +++ b/applications/services/loader/loader_menu.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include + +#include "loader_menu.h" + +#define TAG "LoaderMenu" + +struct LoaderMenu { + Gui* gui; + ViewDispatcher* view_dispatcher; + Menu* primary_menu; + Submenu* settings_menu; + + void (*closed_callback)(void*); + void* closed_callback_context; + + void (*click_callback)(const char*, void*); + void* click_callback_context; + + FuriThread* thread; +}; + +typedef enum { + LoaderMenuViewPrimary, + LoaderMenuViewSettings, +} LoaderMenuView; + +static int32_t loader_menu_thread(void* p); + +LoaderMenu* loader_menu_alloc() { + LoaderMenu* loader_menu = malloc(sizeof(LoaderMenu)); + loader_menu->gui = furi_record_open(RECORD_GUI); + loader_menu->view_dispatcher = view_dispatcher_alloc(); + loader_menu->primary_menu = menu_alloc(); + loader_menu->settings_menu = submenu_alloc(); + loader_menu->thread = NULL; + return loader_menu; +} + +void loader_menu_free(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + // check if thread is running + furi_assert(!loader_menu->thread); + + submenu_free(loader_menu->settings_menu); + menu_free(loader_menu->primary_menu); + view_dispatcher_free(loader_menu->view_dispatcher); + furi_record_close(RECORD_GUI); + free(loader_menu); +} + +void loader_menu_start(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + furi_assert(!loader_menu->thread); + loader_menu->thread = furi_thread_alloc_ex(TAG, 1024, loader_menu_thread, loader_menu); + furi_thread_start(loader_menu->thread); +} + +void loader_menu_stop(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + furi_assert(loader_menu->thread); + view_dispatcher_stop(loader_menu->view_dispatcher); + furi_thread_join(loader_menu->thread); + furi_thread_free(loader_menu->thread); + loader_menu->thread = NULL; +} + +void loader_menu_set_closed_callback( + LoaderMenu* loader_menu, + void (*callback)(void*), + void* context) { + loader_menu->closed_callback = callback; + loader_menu->closed_callback_context = context; +} + +void loader_menu_set_click_callback( + LoaderMenu* loader_menu, + void (*callback)(const char*, void*), + void* context) { + loader_menu->click_callback = callback; + loader_menu->click_callback_context = context; +} + +static void loader_menu_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* name = FLIPPER_APPS[index].name; + if(loader_menu->click_callback) { + loader_menu->click_callback(name, loader_menu->click_callback_context); + } +} + +static void loader_menu_settings_menu_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* name = FLIPPER_SETTINGS_APPS[index].name; + if(loader_menu->click_callback) { + loader_menu->click_callback(name, loader_menu->click_callback_context); + } +} + +static void loader_menu_switch_to_settings(void* context, uint32_t index) { + UNUSED(index); + LoaderMenu* loader_menu = context; + view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); +} + +static uint32_t loader_menu_switch_to_primary(void* context) { + UNUSED(context); + return LoaderMenuViewPrimary; +} + +static uint32_t loader_menu_exit(void* context) { + UNUSED(context); + return VIEW_NONE; +} + +static void loader_menu_build_menu(LoaderMenu* loader_menu) { + size_t i; + for(i = 0; i < FLIPPER_APPS_COUNT; i++) { + menu_add_item( + loader_menu->primary_menu, + FLIPPER_APPS[i].name, + FLIPPER_APPS[i].icon, + i, + loader_menu_callback, + (void*)loader_menu); + } + menu_add_item( + loader_menu->primary_menu, + "Settings", + &A_Settings_14, + i++, + loader_menu_switch_to_settings, + loader_menu); +}; + +static void loader_menu_build_submenu(LoaderMenu* loader_menu) { + for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { + submenu_add_item( + loader_menu->settings_menu, + FLIPPER_SETTINGS_APPS[i].name, + i, + loader_menu_settings_menu_callback, + loader_menu); + } +} + +static int32_t loader_menu_thread(void* p) { + LoaderMenu* loader_menu = p; + furi_assert(loader_menu); + + loader_menu_build_menu(loader_menu); + loader_menu_build_submenu(loader_menu); + + view_dispatcher_attach_to_gui( + loader_menu->view_dispatcher, loader_menu->gui, ViewDispatcherTypeFullscreen); + + // Primary menu + View* primary_view = menu_get_view(loader_menu->primary_menu); + view_set_context(primary_view, loader_menu->primary_menu); + view_set_previous_callback(primary_view, loader_menu_exit); + view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary, primary_view); + + // Settings menu + View* settings_view = submenu_get_view(loader_menu->settings_menu); + view_set_context(settings_view, loader_menu->settings_menu); + view_set_previous_callback(settings_view, loader_menu_switch_to_primary); + view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewSettings, settings_view); + + view_dispatcher_enable_queue(loader_menu->view_dispatcher); + view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); + + // run view dispatcher + view_dispatcher_run(loader_menu->view_dispatcher); + + view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); + view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); + + if(loader_menu->closed_callback) { + loader_menu->closed_callback(loader_menu->closed_callback_context); + } + + return 0; +} \ No newline at end of file diff --git a/applications/services/loader/loader_menu.h b/applications/services/loader/loader_menu.h new file mode 100644 index 0000000000..7405b87be7 --- /dev/null +++ b/applications/services/loader/loader_menu.h @@ -0,0 +1,30 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct LoaderMenu LoaderMenu; + +LoaderMenu* loader_menu_alloc(); + +void loader_menu_free(LoaderMenu* loader_menu); + +void loader_menu_start(LoaderMenu* loader_menu); + +void loader_menu_stop(LoaderMenu* loader_menu); + +void loader_menu_set_closed_callback( + LoaderMenu* loader_menu, + void (*callback)(void*), + void* context); + +void loader_menu_set_click_callback( + LoaderMenu* loader_menu, + void (*callback)(const char*, void*), + void* context); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/settings/system/system_settings.c b/applications/settings/system/system_settings.c index 8cbe62da87..5ab9cc6f0d 100644 --- a/applications/settings/system/system_settings.c +++ b/applications/settings/system/system_settings.c @@ -43,7 +43,6 @@ static void debug_changed(VariableItem* item) { } else { furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); } - loader_update_menu(); } const char* const heap_trace_mode_text[] = { @@ -137,8 +136,6 @@ static void hand_orient_changed(VariableItem* item) { } else { furi_hal_rtc_reset_flag(FuriHalRtcFlagHandOrient); } - - loader_update_menu(); } const char* const sleep_method[] = { diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index f84bf074e1..bc6844d350 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.3,, +Version,+,24.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1375,12 +1375,11 @@ Function,-,ldiv,ldiv_t,"long, long" Function,-,llabs,long long,long long Function,-,lldiv,lldiv_t,"long long, long long" Function,+,loader_get_pubsub,FuriPubSub*,Loader* -Function,+,loader_is_locked,_Bool,const Loader* +Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* -Function,+,loader_show_menu,void, +Function,+,loader_show_menu,void,Loader* Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* -Function,+,loader_update_menu,void, Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* Function,+,loading_get_view,View*,Loading* diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 9c0cca01ab..a4d1b87a63 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.3,, +Version,+,24.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1839,12 +1839,11 @@ Function,-,llround,long long int,double Function,-,llroundf,long long int,float Function,-,llroundl,long long int,long double Function,+,loader_get_pubsub,FuriPubSub*,Loader* -Function,+,loader_is_locked,_Bool,const Loader* +Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* -Function,+,loader_show_menu,void, +Function,+,loader_show_menu,void,Loader* Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* -Function,+,loader_update_menu,void, Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* Function,+,loading_get_view,View*,Loading* From 1f0c2c12666df847586cd347580930964ace0f46 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 5 May 2023 02:09:21 +0300 Subject: [PATCH 25/30] SubGhz refactor merge pt 0 --- .../pocsag_pager/views/pocsag_pager_receiver.c | 6 +++--- .../weather_station/views/weather_station_receiver.c | 6 +++--- .../main/subghz/scenes/subghz_scene_show_error.c | 11 +++++------ .../main/subghz/scenes/subghz_scene_transmitter.c | 4 ++-- applications/main/subghz/views/transmitter.c | 6 +++--- applications/main/subghz/views/transmitter.h | 2 +- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/applications/external/pocsag_pager/views/pocsag_pager_receiver.c b/applications/external/pocsag_pager/views/pocsag_pager_receiver.c index 532f41984b..64939a9564 100644 --- a/applications/external/pocsag_pager/views/pocsag_pager_receiver.c +++ b/applications/external/pocsag_pager/views/pocsag_pager_receiver.c @@ -12,7 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; @@ -69,10 +69,10 @@ void pcsg_receiver_rssi(PCSGReceiver* instance, float rssi) { instance->view, PCSGReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); diff --git a/applications/external/weather_station/views/weather_station_receiver.c b/applications/external/weather_station/views/weather_station_receiver.c index 62f1adad02..e994e7830e 100644 --- a/applications/external/weather_station/views/weather_station_receiver.c +++ b/applications/external/weather_station/views/weather_station_receiver.c @@ -12,7 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; uint8_t type; @@ -69,10 +69,10 @@ void ws_view_receiver_set_rssi(WSReceiver* instance, float rssi) { instance->view, WSReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); diff --git a/applications/main/subghz/scenes/subghz_scene_show_error.c b/applications/main/subghz/scenes/subghz_scene_show_error.c index 107189cae7..4544260ef6 100644 --- a/applications/main/subghz/scenes/subghz_scene_show_error.c +++ b/applications/main/subghz/scenes/subghz_scene_show_error.c @@ -50,9 +50,10 @@ void subghz_scene_show_error_on_enter(void* context) { bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; + SubGhzCustomEvent scene_state = + scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError); if(event.type == SceneManagerEventTypeBack) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { return false; } else { scene_manager_search_and_switch_to_previous_scene( @@ -61,14 +62,12 @@ bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { return true; } else if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneShowErrorOk) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); } return true; } else if(event.event == SubGhzCustomEventSceneShowErrorBack) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { //exit app if(!scene_manager_previous_scene(subghz->scene_manager)) { scene_manager_stop(subghz->scene_manager); diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index ab9155fb7d..f20d039cb9 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -23,7 +23,7 @@ bool subghz_scene_transmitter_update_data_show(void* context) { key_str = furi_string_alloc(); frequency_str = furi_string_alloc(); modulation_str = furi_string_alloc(); - uint8_t show_button = 0; + bool show_button = false; if(subghz_protocol_decoder_base_deserialize( subghz->txrx->decoder_result, subghz->txrx->fff_data) == SubGhzProtocolStatusOk) { @@ -31,7 +31,7 @@ bool subghz_scene_transmitter_update_data_show(void* context) { if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) { - show_button = 1; + show_button = true; } subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 2bec77690e..5ae1a6e2c3 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -16,7 +16,7 @@ typedef struct { FuriString* frequency_str; FuriString* preset_str; FuriString* key_str; - uint8_t show_button; + bool show_button; FuriString* temp_button_id; bool draw_temp_button; } SubGhzViewTransmitterModel; @@ -36,7 +36,7 @@ void subghz_view_transmitter_add_data_to_show( const char* key_str, const char* frequency_str, const char* preset_str, - uint8_t show_button) { + bool show_button) { furi_assert(subghz_transmitter); with_view_model( subghz_transmitter->view, @@ -119,7 +119,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { furi_string_reset(model->preset_str); furi_string_reset(model->key_str); furi_string_reset(model->temp_button_id); - model->show_button = 0; + model->show_button = false; model->draw_temp_button = false; }, false); diff --git a/applications/main/subghz/views/transmitter.h b/applications/main/subghz/views/transmitter.h index 64bcbd1afa..06aae7c6bf 100644 --- a/applications/main/subghz/views/transmitter.h +++ b/applications/main/subghz/views/transmitter.h @@ -23,4 +23,4 @@ void subghz_view_transmitter_add_data_to_show( const char* key_str, const char* frequency_str, const char* preset_str, - uint8_t show_button); + bool show_button); From c36b788b2db733bfa96c3b2bdbad347feb90f81f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 5 May 2023 03:17:53 +0300 Subject: [PATCH 26/30] Use COUNT_OF in mouse jiggler --- applications/external/hid_app/views/hid_mouse_jiggler.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/applications/external/hid_app/views/hid_mouse_jiggler.c b/applications/external/hid_app/views/hid_mouse_jiggler.c index 120d5bc34c..09c14c6688 100644 --- a/applications/external/hid_app/views/hid_mouse_jiggler.c +++ b/applications/external/hid_app/views/hid_mouse_jiggler.c @@ -6,8 +6,6 @@ #define TAG "HidMouseJiggler" -#define LENGTH(x) (int)(sizeof(x) / sizeof((x)[0])) - struct HidMouseJiggler { View* view; Hid* hid; @@ -44,7 +42,7 @@ static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) { elements_multiline_text(canvas, AlignLeft, 26, "Interval (ms):"); canvas_set_font(canvas, FontSecondary); if(model->interval_idx != 0) canvas_draw_icon(canvas, 74, 19, &I_ButtonLeft_4x7); - if(model->interval_idx != LENGTH(intervals) - 1) + if(model->interval_idx != (int)COUNT_OF(intervals) - 1) canvas_draw_icon(canvas, 80, 19, &I_ButtonRight_4x7); FuriString* interval_str = furi_string_alloc_printf("%d", intervals[model->interval_idx]); elements_multiline_text(canvas, 91, 26, furi_string_get_cstr(interval_str)); @@ -116,7 +114,7 @@ static bool hid_mouse_jiggler_input_callback(InputEvent* event, void* context) { consumed = true; } if(event->type == InputTypePress && event->key == InputKeyRight && !model->running && - model->interval_idx < LENGTH(intervals) - 1) { + model->interval_idx < (int)COUNT_OF(intervals) - 1) { model->interval_idx++; consumed = true; } From b0b9e507e7b794e769866432cc07b1aa3faeeb42 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 5 May 2023 03:51:16 +0300 Subject: [PATCH 27/30] SubGHz combine FuriString allocs --- .../subghz/scenes/subghz_scene_decode_raw.c | 28 +++++---------- .../main/subghz/scenes/subghz_scene_delete.c | 10 ++---- .../subghz/scenes/subghz_scene_delete_raw.c | 7 ++-- .../subghz/scenes/subghz_scene_read_raw.c | 16 +++------ .../subghz/scenes/subghz_scene_receiver.c | 24 +++++-------- .../scenes/subghz_scene_receiver_info.c | 10 ++---- .../main/subghz/scenes/subghz_scene_rpc.c | 3 +- .../subghz/scenes/subghz_scene_save_name.c | 8 ++--- .../subghz/scenes/subghz_scene_transmitter.c | 9 ++--- applications/main/subghz/subghz_cli.c | 36 +++++++------------ applications/main/subghz/subghz_history.c | 3 +- applications/main/subghz/subghz_i.c | 22 ++++-------- applications/main/subghz/views/receiver.c | 3 +- 13 files changed, 59 insertions(+), 120 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index 5ac4fcccd5..b9f2d236bf 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -24,14 +24,10 @@ static void subghz_scene_receiver_update_statusbar(void* context) { SubGhz* subghz = context; - FuriString* history_stat_str; - history_stat_str = furi_string_alloc(); + FuriString* history_stat_str = furi_string_alloc(); if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); @@ -62,11 +58,9 @@ static void subghz_scene_add_to_history_callback( void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); uint16_t idx = subghz_history_get_item(subghz->txrx->history); - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { furi_string_reset(item_name); @@ -90,8 +84,7 @@ static void subghz_scene_add_to_history_callback( } bool subghz_scene_decode_raw_start(SubGhz* subghz) { - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); bool success = false; do { if(!flipper_format_rewind(subghz->txrx->fff_data)) { @@ -148,8 +141,7 @@ bool subghz_scene_decode_raw_next(SubGhz* subghz) { } // Update progress info - FuriString* progress_str; - progress_str = furi_string_alloc(); + FuriString* progress_str = furi_string_alloc(); subghz_file_encoder_worker_get_text_progress( subghz->decode_raw_file_worker_encoder, progress_str); @@ -164,10 +156,8 @@ bool subghz_scene_decode_raw_next(SubGhz* subghz) { void subghz_scene_decode_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock); subghz_view_receiver_set_mode(subghz->subghz_receiver, SubGhzViewReceiverModeFile); diff --git a/applications/main/subghz/scenes/subghz_scene_delete.c b/applications/main/subghz/scenes/subghz_scene_delete.c index 94814b1432..4cad14bbf0 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete.c +++ b/applications/main/subghz/scenes/subghz_scene_delete.c @@ -11,13 +11,9 @@ void subghz_scene_delete_callback(GuiButtonType result, InputType type, void* co void subghz_scene_delete_on_enter(void* context) { SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; - FuriString* text; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - text = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); + FuriString* text = furi_string_alloc(); subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); widget_add_string_element( diff --git a/applications/main/subghz/scenes/subghz_scene_delete_raw.c b/applications/main/subghz/scenes/subghz_scene_delete_raw.c index fa4fc6f642..ee7983dfd3 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_delete_raw.c @@ -15,11 +15,8 @@ void subghz_scene_delete_raw_callback(GuiButtonType result, InputType type, void void subghz_scene_delete_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); char delete_str[SUBGHZ_MAX_LEN_NAME + 16]; FuriString* file_name; diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 0c692e000d..6a881cba44 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -12,8 +12,7 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { bool ret = false; //set the path to read the file - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); do { if(!flipper_format_rewind(subghz->txrx->fff_data)) { FURI_LOG_E(TAG, "Rewind error"); @@ -38,11 +37,8 @@ static void subghz_scene_read_raw_update_statusbar(void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); #ifdef SUBGHZ_EXT_PRESET_NAME subghz_get_frequency_modulation(subghz, frequency_str, NULL); @@ -74,8 +70,7 @@ void subghz_scene_read_raw_callback_end_tx(void* context) { void subghz_scene_read_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); switch(subghz->txrx->rx_key_state) { case SubGhzRxKeyStateBack: @@ -293,8 +288,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz_protocol_raw_save_to_file_stop( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); furi_string_printf( temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION); subghz_protocol_raw_gen_fff_data( diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index b17a0700b4..fd8d9b70ec 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -39,14 +39,10 @@ const NotificationSequence subghz_sequence_rx_locked = { static void subghz_scene_receiver_update_statusbar(void* context) { SubGhz* subghz = context; - FuriString* history_stat_str; - history_stat_str = furi_string_alloc(); + FuriString* history_stat_str = furi_string_alloc(); if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); #ifdef SUBGHZ_EXT_PRESET_NAME if(subghz_history_get_last_index(subghz->txrx->history) > 0) { @@ -90,12 +86,12 @@ static void subghz_scene_add_to_history_callback( SubGhzProtocolDecoderBase* decoder_base, void* context) { furi_assert(context); + SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; + + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); uint16_t idx = subghz_history_get_item(subghz->txrx->history); - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { furi_string_reset(item_name); @@ -122,10 +118,8 @@ static void subghz_scene_add_to_history_callback( void subghz_scene_receiver_on_enter(void* context) { SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) { subghz_preset_init(subghz, "AM650", subghz->last_settings->frequency, NULL, 0); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 58e4287850..a108132c0d 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -49,13 +49,9 @@ static bool subghz_scene_receiver_info_update_parser(void* context) { void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) { if(subghz_scene_receiver_info_update_parser(subghz)) { - FuriString* frequency_str; - FuriString* modulation_str; - FuriString* text; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - text = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); + FuriString* text = furi_string_alloc(); subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); widget_add_string_element( diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index 9172f67c2c..8140f69a23 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -72,8 +72,7 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateLoaded); furi_string_set(subghz->file_path, arg); result = true; - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); path_extract_filename(subghz->file_path, file_name, true); snprintf( diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index d3f5474beb..2bb13f1844 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -51,10 +51,8 @@ void subghz_scene_save_name_on_enter(void* context) { TextInput* text_input = subghz->text_input; bool dev_name_empty = false; - FuriString* file_name; - FuriString* dir_name; - file_name = furi_string_alloc(); - dir_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); + FuriString* dir_name = furi_string_alloc(); if(!subghz_path_is_file(subghz->file_path)) { char file_name_buf[SUBGHZ_MAX_LEN_NAME] = {0}; @@ -109,7 +107,7 @@ void subghz_scene_save_name_on_enter(void* context) { subghz_scene_save_name_text_input_callback, subghz, subghz->file_name_tmp, - MAX_TEXT_INPUT_LEN, // buffer size + MAX_TEXT_INPUT_LEN, dev_name_empty); ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index f20d039cb9..d1fafd8ff8 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -16,13 +16,10 @@ bool subghz_scene_transmitter_update_data_show(void* context) { SubGhz* subghz = context; bool ret = false; if(subghz->txrx->decoder_result) { - FuriString* key_str; - FuriString* frequency_str; - FuriString* modulation_str; + FuriString* key_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); - key_str = furi_string_alloc(); - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); bool show_button = false; if(subghz_protocol_decoder_base_deserialize( diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index c047a32b3e..f30578fb28 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -215,8 +215,7 @@ static void subghz_cli_command_rx_callback( SubGhzCliCommandRx* instance = context; instance->packet_count++; - FuriString* text; - text = furi_string_alloc(); + FuriString* text = furi_string_alloc(); subghz_protocol_decoder_base_get_string(decoder_base, text); subghz_receiver_reset(receiver); printf("%s", furi_string_get_cstr(text)); @@ -384,14 +383,12 @@ void subghz_cli_command_rx_raw(Cli* cli, FuriString* args, void* context) { } void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) { UNUSED(context); - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); furi_string_set(file_name, ANY_PATH("subghz/test.sub")); Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t temp_data32; bool check_file = false; @@ -526,10 +523,8 @@ static void subghz_cli_command_encrypt_keeloq(Cli* cli, FuriString* args) { UNUSED(cli); uint8_t iv[16]; - FuriString* source; - FuriString* destination; - source = furi_string_alloc(); - destination = furi_string_alloc(); + FuriString* source = furi_string_alloc(); + FuriString* destination = furi_string_alloc(); SubGhzKeystore* keystore = subghz_keystore_alloc(); @@ -569,10 +564,8 @@ static void subghz_cli_command_encrypt_raw(Cli* cli, FuriString* args) { UNUSED(cli); uint8_t iv[16]; - FuriString* source; - FuriString* destination; - source = furi_string_alloc(); - destination = furi_string_alloc(); + FuriString* source = furi_string_alloc(); + FuriString* destination = furi_string_alloc(); do { if(!args_read_string_and_trim(args, source)) { @@ -645,14 +638,10 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args) { size_t message_max_len = 64; uint8_t message[64] = {0}; - FuriString* input; - input = furi_string_alloc(); - FuriString* name; - name = furi_string_alloc(); - FuriString* output; - output = furi_string_alloc(); - FuriString* sysmsg; - sysmsg = furi_string_alloc(); + FuriString* input = furi_string_alloc(); + FuriString* name = furi_string_alloc(); + FuriString* output = furi_string_alloc(); + FuriString* sysmsg = furi_string_alloc(); bool exit = false; SubGhzChatEvent chat_event; @@ -785,8 +774,7 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args) { } static void subghz_cli_command(Cli* cli, FuriString* args, void* context) { - FuriString* cmd; - cmd = furi_string_alloc(); + FuriString* cmd = furi_string_alloc(); do { if(!args_read_string_and_trim(args, cmd)) { diff --git a/applications/main/subghz/subghz_history.c b/applications/main/subghz/subghz_history.c index 3c018ec8bb..396e284210 100644 --- a/applications/main/subghz/subghz_history.c +++ b/applications/main/subghz/subghz_history.c @@ -197,8 +197,7 @@ bool subghz_history_add_to_history( instance->code_last_hash_data = subghz_protocol_decoder_base_get_hash_data(decoder_base); instance->last_update_timestamp = furi_get_tick(); - FuriString* text; - text = furi_string_alloc(); + FuriString* text = furi_string_alloc(); SubGhzHistoryItem* item = SubGhzHistoryItemArray_push_raw(instance->history->data); item->preset = malloc(sizeof(SubGhzRadioPreset)); item->type = decoder_base->protocol->type; diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index dd01602133..77eba42fbb 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -145,8 +145,7 @@ bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) { furi_assert(subghz); bool ret = false; - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t repeat = 200; do { if(!flipper_format_rewind(flipper_format)) { @@ -254,8 +253,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); SubGhzLoadKeyState load_key_state = SubGhzLoadKeyStateParseErr; - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t temp_data32; do { @@ -393,13 +391,9 @@ bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) { furi_assert(subghz); Storage* storage = furi_record_open(RECORD_STORAGE); - FuriString* temp_str; - FuriString* file_name; - FuriString* file_path; - - temp_str = furi_string_alloc(); - file_name = furi_string_alloc(); - file_path = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); + FuriString* file_path = furi_string_alloc(); bool res = false; @@ -446,8 +440,7 @@ bool subghz_save_protocol_to_file( Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); bool saved = false; - FuriString* file_dir; - file_dir = furi_string_alloc(); + FuriString* file_dir = furi_string_alloc(); path_extract_dirname(dev_file_name, file_dir); do { @@ -478,8 +471,7 @@ bool subghz_save_protocol_to_file( bool subghz_load_protocol_from_file(SubGhz* subghz) { furi_assert(subghz); - FuriString* file_path; - file_path = furi_string_alloc(); + FuriString* file_path = furi_string_alloc(); DialogsFileBrowserOptions browser_options; dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px); diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index d48ff8b967..811a466988 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -239,8 +239,7 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { } bool scrollbar = model->history_item > 4; - FuriString* str_buff; - str_buff = furi_string_alloc(); + FuriString* str_buff = furi_string_alloc(); SubGhzReceiverMenuItem* item_menu; From 914129a0d90a75952662f4c717d1d98ffe90fccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Fri, 5 May 2023 21:40:55 +0900 Subject: [PATCH 28/30] [FL-3289] Various Furi/FuriHal bug fixes and improvements (#2637) * Furi: properly handle thread free before TCB scrapping, add furi_free - more invasive version of free to memmgr. FuriHal: add DWT comparator api to cortex. Updater, RPC: refactor various thread shanenigans. Code cleanup. * Rollback free macros and related changes --- applications/services/loader/loader.c | 1 + applications/services/rpc/rpc.c | 48 +++++++------ .../services/storage/storage_external_api.c | 1 + .../services/storage/storages/storage_ext.c | 1 + .../power_settings_app/views/battery_info.c | 4 +- applications/system/updater/cli/updater_cli.c | 26 ++----- .../updater/util/update_task_worker_flasher.c | 6 +- firmware/targets/f18/api_symbols.csv | 7 +- firmware/targets/f7/api_symbols.csv | 7 +- .../targets/f7/furi_hal/furi_hal_cortex.c | 72 ++++++++++++++++++- .../furi_hal_include/furi_hal_cortex.h | 47 ++++++++++++ furi/core/thread.c | 28 ++++---- furi/core/thread.h | 8 +-- furi/core/timer.c | 10 +++ furi/core/timer.h | 4 ++ 15 files changed, 202 insertions(+), 68 deletions(-) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index be16e5091f..f385efdf95 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -248,6 +248,7 @@ static void loader_do_app_closed(Loader* loader) { free(loader->app.name); loader->app.name = NULL; + furi_thread_join(loader->app.thread); furi_thread_free(loader->app.thread); loader->app.thread = NULL; } diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index 5b09e9b517..a759a12a9c 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -326,31 +326,35 @@ static int32_t rpc_session_worker(void* context) { return 0; } -static void rpc_session_free_callback(FuriThreadState thread_state, void* context) { - furi_assert(context); - +static void rpc_session_thread_pending_callback(void* context, uint32_t arg) { + UNUSED(arg); RpcSession* session = (RpcSession*)context; - if(thread_state == FuriThreadStateStopped) { - for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) { - if(rpc_systems[i].free) { - rpc_systems[i].free(session->system_contexts[i]); - } - } - free(session->system_contexts); - free(session->decoded_message); - RpcHandlerDict_clear(session->handlers); - furi_stream_buffer_free(session->stream); - - furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever); - if(session->terminated_callback) { - session->terminated_callback(session->context); + for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) { + if(rpc_systems[i].free) { + (rpc_systems[i].free)(session->system_contexts[i]); } - furi_mutex_release(session->callbacks_mutex); + } + free(session->system_contexts); + free(session->decoded_message); + RpcHandlerDict_clear(session->handlers); + furi_stream_buffer_free(session->stream); - furi_mutex_free(session->callbacks_mutex); - furi_thread_free(session->thread); - free(session); + furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever); + if(session->terminated_callback) { + session->terminated_callback(session->context); + } + furi_mutex_release(session->callbacks_mutex); + + furi_mutex_free(session->callbacks_mutex); + furi_thread_join(session->thread); + furi_thread_free(session->thread); + free(session); +} + +static void rpc_session_thread_state_callback(FuriThreadState thread_state, void* context) { + if(thread_state == FuriThreadStateStopped) { + furi_timer_pending_callback(rpc_session_thread_pending_callback, context, 0); } } @@ -385,7 +389,7 @@ RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner) { session->thread = furi_thread_alloc_ex("RpcSessionWorker", 3072, rpc_session_worker, session); furi_thread_set_state_context(session->thread, session); - furi_thread_set_state_callback(session->thread, rpc_session_free_callback); + furi_thread_set_state_callback(session->thread, rpc_session_thread_state_callback); furi_thread_start(session->thread); diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index ffc3da4bc4..bf474bc9d0 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -803,6 +803,7 @@ void storage_file_free(File* file) { } FuriPubSub* storage_get_pubsub(Storage* storage) { + furi_assert(storage); return storage->pubsub; } diff --git a/applications/services/storage/storages/storage_ext.c b/applications/services/storage/storages/storage_ext.c index d802d6e9f6..15a355dc25 100644 --- a/applications/services/storage/storages/storage_ext.c +++ b/applications/services/storage/storages/storage_ext.c @@ -337,6 +337,7 @@ static bool storage_ext_file_close(void* ctx, File* file) { file->internal_error_id = f_close(file_data); file->error_id = storage_ext_parse_error(file->internal_error_id); free(file_data); + storage_set_storage_file_data(file, NULL, storage); return (file->error_id == FSE_OK); } diff --git a/applications/settings/power_settings_app/views/battery_info.c b/applications/settings/power_settings_app/views/battery_info.c index 0956cae4f5..d56dfc6285 100644 --- a/applications/settings/power_settings_app/views/battery_info.c +++ b/applications/settings/power_settings_app/views/battery_info.c @@ -53,7 +53,9 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { (uint32_t)(data->vbus_voltage), (uint32_t)(data->vbus_voltage * 10) % 10, current); - } else if(current < 0) { + } else if(current < -5) { + // Often gauge reports anything in the range 1~5ma as 5ma + // That brings confusion, so we'll treat it as Napping snprintf( emote, sizeof(emote), diff --git a/applications/system/updater/cli/updater_cli.c b/applications/system/updater/cli/updater_cli.c index 2bf6dab26e..659c431f70 100644 --- a/applications/system/updater/cli/updater_cli.c +++ b/applications/system/updater/cli/updater_cli.c @@ -85,22 +85,10 @@ static void updater_cli_ep(Cli* cli, FuriString* args, void* context) { updater_cli_help(args); } -static int32_t updater_spawner_thread_worker(void* arg) { +static void updater_start_app(void* context, uint32_t arg) { + UNUSED(context); UNUSED(arg); - Loader* loader = furi_record_open(RECORD_LOADER); - loader_start(loader, "UpdaterApp", NULL); - furi_record_close(RECORD_LOADER); - return 0; -} -static void updater_spawner_thread_cleanup(FuriThreadState state, void* context) { - FuriThread* thread = context; - if(state == FuriThreadStateStopped) { - furi_thread_free(thread); - } -} - -static void updater_start_app() { FuriHalRtcBootMode mode = furi_hal_rtc_get_boot_mode(); if((mode != FuriHalRtcBootModePreUpdate) && (mode != FuriHalRtcBootModePostUpdate)) { return; @@ -110,11 +98,9 @@ static void updater_start_app() { * inside loader process, at startup. * So, accessing its record would cause a deadlock */ - FuriThread* thread = - furi_thread_alloc_ex("UpdateAppSpawner", 768, updater_spawner_thread_worker, NULL); - furi_thread_set_state_callback(thread, updater_spawner_thread_cleanup); - furi_thread_set_state_context(thread, thread); - furi_thread_start(thread); + Loader* loader = furi_record_open(RECORD_LOADER); + loader_start(loader, "UpdaterApp", NULL); + furi_record_close(RECORD_LOADER); } void updater_on_system_start() { @@ -126,7 +112,7 @@ void updater_on_system_start() { UNUSED(updater_cli_ep); #endif #ifndef FURI_RAM_EXEC - updater_start_app(); + furi_timer_pending_callback(updater_start_app, NULL, 0); #else UNUSED(updater_start_app); #endif diff --git a/applications/system/updater/util/update_task_worker_flasher.c b/applications/system/updater/util/update_task_worker_flasher.c index 63024ced9c..5d24774646 100644 --- a/applications/system/updater/util/update_task_worker_flasher.c +++ b/applications/system/updater/util/update_task_worker_flasher.c @@ -346,7 +346,11 @@ int32_t update_task_worker_flash_writer(void* context) { furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePostUpdate); // Format LFS before restoring backup on next boot furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset); - +#ifdef FURI_NDEBUG + // Production + furi_hal_rtc_set_log_level(FuriLogLevelDefault); + furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); +#endif update_task_set_progress(update_task, UpdateTaskStageCompleted, 100); success = true; } while(false); diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index bc6844d350..f83f6405be 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,24.0,, +Version,+,26.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -892,6 +892,8 @@ Function,+,furi_hal_console_puts,void,const char* Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*" Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t" Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t" +Function,+,furi_hal_cortex_comp_enable,void,"FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize" +Function,+,furi_hal_cortex_comp_reset,void,FuriHalCortexComp Function,+,furi_hal_cortex_delay_us,void,uint32_t Function,-,furi_hal_cortex_init_early,void, Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t, @@ -1278,7 +1280,7 @@ Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" -Function,+,furi_thread_set_stdout_callback,_Bool,FuriThreadStdoutWriteCallback +Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback Function,+,furi_thread_start,void,FuriThread* Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" @@ -1287,6 +1289,7 @@ Function,+,furi_thread_yield,void, Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" Function,+,furi_timer_free,void,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer* +Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t" Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" Function,+,furi_timer_stop,FuriStatus,FuriTimer* Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 1c8424fe8c..8a4e06303f 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,24.0,, +Version,+,26.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1073,6 +1073,8 @@ Function,+,furi_hal_console_puts,void,const char* Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*" Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t" Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t" +Function,+,furi_hal_cortex_comp_enable,void,"FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize" +Function,+,furi_hal_cortex_comp_reset,void,FuriHalCortexComp Function,+,furi_hal_cortex_delay_us,void,uint32_t Function,-,furi_hal_cortex_init_early,void, Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t, @@ -1562,7 +1564,7 @@ Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" -Function,+,furi_thread_set_stdout_callback,_Bool,FuriThreadStdoutWriteCallback +Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback Function,+,furi_thread_start,void,FuriThread* Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" @@ -1571,6 +1573,7 @@ Function,+,furi_thread_yield,void, Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" Function,+,furi_timer_free,void,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer* +Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t" Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" Function,+,furi_timer_stop,FuriStatus,FuriTimer* Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" diff --git a/firmware/targets/f7/furi_hal/furi_hal_cortex.c b/firmware/targets/f7/furi_hal/furi_hal_cortex.c index d0bce50381..3fbe384e3c 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_cortex.c +++ b/firmware/targets/f7/furi_hal/furi_hal_cortex.c @@ -1,11 +1,12 @@ #include +#include #include #define FURI_HAL_CORTEX_INSTRUCTIONS_PER_MICROSECOND (SystemCoreClock / 1000000) void furi_hal_cortex_init_early() { - CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + CoreDebug->DEMCR |= (CoreDebug_DEMCR_TRCENA_Msk | CoreDebug_DEMCR_MON_EN_Msk); DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; DWT->CYCCNT = 0U; @@ -38,4 +39,71 @@ bool furi_hal_cortex_timer_is_expired(FuriHalCortexTimer cortex_timer) { void furi_hal_cortex_timer_wait(FuriHalCortexTimer cortex_timer) { while(!furi_hal_cortex_timer_is_expired(cortex_timer)) ; -} \ No newline at end of file +} + +// Duck ST +#undef COMP0 +#undef COMP1 +#undef COMP2 +#undef COMP3 + +void furi_hal_cortex_comp_enable( + FuriHalCortexComp comp, + FuriHalCortexCompFunction function, + uint32_t value, + uint32_t mask, + FuriHalCortexCompSize size) { + uint32_t function_reg = (uint32_t)function | ((uint32_t)size << 10); + + switch(comp) { + case FuriHalCortexComp0: + (DWT->COMP0) = value; + (DWT->MASK0) = mask; + (DWT->FUNCTION0) = function_reg; + break; + case FuriHalCortexComp1: + (DWT->COMP1) = value; + (DWT->MASK1) = mask; + (DWT->FUNCTION1) = function_reg; + break; + case FuriHalCortexComp2: + (DWT->COMP2) = value; + (DWT->MASK2) = mask; + (DWT->FUNCTION2) = function_reg; + break; + case FuriHalCortexComp3: + (DWT->COMP3) = value; + (DWT->MASK3) = mask; + (DWT->FUNCTION3) = function_reg; + break; + default: + furi_crash("Invalid parameter"); + } +} + +void furi_hal_cortex_comp_reset(FuriHalCortexComp comp) { + switch(comp) { + case FuriHalCortexComp0: + (DWT->COMP0) = 0; + (DWT->MASK0) = 0; + (DWT->FUNCTION0) = 0; + break; + case FuriHalCortexComp1: + (DWT->COMP1) = 0; + (DWT->MASK1) = 0; + (DWT->FUNCTION1) = 0; + break; + case FuriHalCortexComp2: + (DWT->COMP2) = 0; + (DWT->MASK2) = 0; + (DWT->FUNCTION2) = 0; + break; + case FuriHalCortexComp3: + (DWT->COMP3) = 0; + (DWT->MASK3) = 0; + (DWT->FUNCTION3) = 0; + break; + default: + furi_crash("Invalid parameter"); + } +} diff --git a/firmware/targets/furi_hal_include/furi_hal_cortex.h b/firmware/targets/furi_hal_include/furi_hal_cortex.h index 91596ffe3f..ebabbabfd8 100644 --- a/firmware/targets/furi_hal_include/furi_hal_cortex.h +++ b/firmware/targets/furi_hal_include/furi_hal_cortex.h @@ -56,6 +56,53 @@ bool furi_hal_cortex_timer_is_expired(FuriHalCortexTimer cortex_timer); */ void furi_hal_cortex_timer_wait(FuriHalCortexTimer cortex_timer); +typedef enum { + FuriHalCortexComp0, + FuriHalCortexComp1, + FuriHalCortexComp2, + FuriHalCortexComp3, +} FuriHalCortexComp; + +typedef enum { + FuriHalCortexCompSizeWord = 0b10, + FuriHalCortexCompSizeHalfWord = 0b01, + FuriHalCortexCompSizeByte = 0b00, +} FuriHalCortexCompSize; + +typedef enum { + FuriHalCortexCompFunctionPC = 0b100, + FuriHalCortexCompFunctionRead = 0b101, + FuriHalCortexCompFunctionWrite = 0b110, + FuriHalCortexCompFunctionReadWrite = 0b110, +} FuriHalCortexCompFunction; + +/** Enable DWT comparator + * + * Allows to programmatically set instruction/data breakpoints. + * + * More details on how it works can be found in armv7m official documentation: + * https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/The-DWT-comparators + * https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/Comparator-Function-registers--DWT-FUNCTIONn + * + * @param[in] comp The Comparator + * @param[in] function The Comparator Function to use + * @param[in] value The value + * @param[in] mask The mask + * @param[in] size The size + */ +void furi_hal_cortex_comp_enable( + FuriHalCortexComp comp, + FuriHalCortexCompFunction function, + uint32_t value, + uint32_t mask, + FuriHalCortexCompSize size); + +/** Reset DWT comparator + * + * @param[in] comp The Comparator + */ +void furi_hal_cortex_comp_reset(FuriHalCortexComp comp); + #ifdef __cplusplus } #endif diff --git a/furi/core/thread.c b/furi/core/thread.c index d78070d61d..facbcb4117 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -164,10 +164,13 @@ FuriThread* furi_thread_alloc_ex( void furi_thread_free(FuriThread* thread) { furi_assert(thread); + + // Ensure that use join before free furi_assert(thread->state == FuriThreadStateStopped); + furi_assert(thread->task_handle == NULL); - if(thread->name) free((void*)thread->name); - if(thread->appid) free((void*)thread->appid); + if(thread->name) free(thread->name); + if(thread->appid) free(thread->appid); furi_string_free(thread->output.buffer); free(thread); @@ -176,14 +179,14 @@ void furi_thread_free(FuriThread* thread) { void furi_thread_set_name(FuriThread* thread, const char* name) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); - if(thread->name) free((void*)thread->name); + if(thread->name) free(thread->name); thread->name = name ? strdup(name) : NULL; } void furi_thread_set_appid(FuriThread* thread, const char* appid) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); - if(thread->appid) free((void*)thread->appid); + if(thread->appid) free(thread->appid); thread->appid = appid ? strdup(appid) : NULL; } @@ -276,7 +279,7 @@ void furi_thread_cleanup_tcb_event(TaskHandle_t task) { if(thread) { // clear thread local storage vTaskSetThreadLocalStoragePointer(task, 0, NULL); - + furi_assert(thread->task_handle == task); thread->task_handle = NULL; } } @@ -332,7 +335,6 @@ FuriThreadId furi_thread_get_current_id() { FuriThread* furi_thread_get_current() { FuriThread* thread = pvTaskGetThreadLocalStoragePointer(NULL, 0); - furi_assert(thread != NULL); return thread; } @@ -579,24 +581,22 @@ static int32_t __furi_thread_stdout_flush(FuriThread* thread) { return 0; } -bool furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) { +void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) { FuriThread* thread = furi_thread_get_current(); - + furi_assert(thread); __furi_thread_stdout_flush(thread); thread->output.write_callback = callback; - - return true; } FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback() { FuriThread* thread = furi_thread_get_current(); - + furi_assert(thread); return thread->output.write_callback; } size_t furi_thread_stdout_write(const char* data, size_t size) { FuriThread* thread = furi_thread_get_current(); - + furi_assert(thread); if(size == 0 || data == NULL) { return __furi_thread_stdout_flush(thread); } else { @@ -619,7 +619,9 @@ size_t furi_thread_stdout_write(const char* data, size_t size) { } int32_t furi_thread_stdout_flush() { - return __furi_thread_stdout_flush(furi_thread_get_current()); + FuriThread* thread = furi_thread_get_current(); + furi_assert(thread); + return __furi_thread_stdout_flush(thread); } void furi_thread_suspend(FuriThreadId thread_id) { diff --git a/furi/core/thread.h b/furi/core/thread.h index b11a225b58..022894ee8f 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -233,7 +233,7 @@ FuriThreadId furi_thread_get_current_id(); /** Get FuriThread instance for current thread * - * @return FuriThread* + * @return pointer to FuriThread or NULL if this thread doesn't belongs to Furi */ FuriThread* furi_thread_get_current(); @@ -288,12 +288,10 @@ uint32_t furi_thread_get_stack_space(FuriThreadId thread_id); FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(); /** Set STDOUT callback for thread - * + * * @param callback callback or NULL to clear - * - * @return true on success, otherwise fail */ -bool furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback); +void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback); /** Write data to buffered STDOUT * diff --git a/furi/core/timer.c b/furi/core/timer.c index 4b6ccecba5..7743ffe701 100644 --- a/furi/core/timer.c +++ b/furi/core/timer.c @@ -124,3 +124,13 @@ uint32_t furi_timer_is_running(FuriTimer* instance) { /* Return 0: not running, 1: running */ return (uint32_t)xTimerIsTimerActive(hTimer); } + +void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context, uint32_t arg) { + BaseType_t ret = pdFAIL; + if(furi_kernel_is_irq_or_masked()) { + ret = xTimerPendFunctionCallFromISR(callback, context, arg, NULL); + } else { + ret = xTimerPendFunctionCall(callback, context, arg, FuriWaitForever); + } + furi_check(ret == pdPASS); +} \ No newline at end of file diff --git a/furi/core/timer.h b/furi/core/timer.h index e79c1868d9..3f43de5fd9 100644 --- a/furi/core/timer.h +++ b/furi/core/timer.h @@ -56,6 +56,10 @@ FuriStatus furi_timer_stop(FuriTimer* instance); */ uint32_t furi_timer_is_running(FuriTimer* instance); +typedef void (*FuriTimerPendigCallback)(void* context, uint32_t arg); + +void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context, uint32_t arg); + #ifdef __cplusplus } #endif From 7ddde7e6ca333e63f6ec3073cadfa0f9ee6c8f83 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 5 May 2023 16:09:06 +0300 Subject: [PATCH 29/30] Fuzzers remove excessive free's thanks to @Willy-JL --- applications/external/flipfrid/flipfrid.c | 3 --- applications/external/ibtn_fuzzer/ibtnfuzzer.c | 3 --- 2 files changed, 6 deletions(-) diff --git a/applications/external/flipfrid/flipfrid.c b/applications/external/flipfrid/flipfrid.c index 4608bab165..1cf7be8652 100644 --- a/applications/external/flipfrid/flipfrid.c +++ b/applications/external/flipfrid/flipfrid.c @@ -118,9 +118,6 @@ void flipfrid_free(FlipFridState* flipfrid) { furi_string_free(flipfrid->main_menu_proto_items[i]); } - free(flipfrid->data); - free(flipfrid->payload); - // The rest free(flipfrid); } diff --git a/applications/external/ibtn_fuzzer/ibtnfuzzer.c b/applications/external/ibtn_fuzzer/ibtnfuzzer.c index d385a22d26..825a555607 100644 --- a/applications/external/ibtn_fuzzer/ibtnfuzzer.c +++ b/applications/external/ibtn_fuzzer/ibtnfuzzer.c @@ -120,9 +120,6 @@ void ibtnfuzzer_free(iBtnFuzzerState* ibtnfuzzer) { furi_string_free(ibtnfuzzer->main_menu_proto_items[i]); } - free(ibtnfuzzer->data); - free(ibtnfuzzer->payload); - // The rest free(ibtnfuzzer); } From 1feb876a32efa8c2de59e4c218312e8a1533c160 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 5 May 2023 17:58:58 +0300 Subject: [PATCH 30/30] update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 37c6260e04..459a9d6c28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,14 @@ ### New changes +* If you have copied any apps manually into `apps` folder - remove `apps` folder or that specific apps you copied on your microSD before installing this release to avoid issues! +* Plugins: RFID and iButton Fuzzer remove excessive free's (thanks @Willy-JL) +* Plugins: Use COUNT_OF in mouse jiggler * Plugins: Added Numpad keyboard to HID app (by @clipboard1 | PR #452) +* About: Don't show 00 on about screens +* SubGHz: Combine FuriString allocs and other small changes * Infrared: Updated universal remote assets (by @amec0e | PR #454) * Update slideshow: Replace QR code with good old link +* OFW: Various Furi/FuriHal bug fixes and improvements -> **Breaking API change, api was changed from 24.x to 26.x** +* OFW: Loader refactoring, part 1 -> **Breaking API change, api was changed from 23.x to 24.x** **(this will make your manually copied plugins not work, update them in same way you installed them, or delete `apps` folder and then install firmware, if you using extra pack builds (with `e` in version) all apps in _Extra will be updated automatically)** * OFW: Dolphin builder in ufbt; minor ufbt/fbt improvements * OFW: Added API version to device info * OFW: Gui: relax some asserts in view