From 5681016dceaff960718ccd9433c92ef28069a91b Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 17 Nov 2022 02:05:14 +0300 Subject: [PATCH 1/9] SubGHz: Fix starline encoder o_O --- ReadMe.md | 2 +- lib/subghz/protocols/star_line.c | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index fc1c5f911..4a2a88603 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -59,7 +59,7 @@ Also check changelog in releases for latest updates! - FAAC SLH (Spa) [External seed calculation required (For info contact me in Discord: Nano#8998)] - BFT Mitto [External seed calculation required (For info contact me in Discord: Nano#8998)] - Security+ v1 & v2 -- Star Line (saving only) +- Star Line ## Support us so we can buy equipment and develop new features * Boosty: https://boosty.to/mmxdev diff --git a/lib/subghz/protocols/star_line.c b/lib/subghz/protocols/star_line.c index 0b794a6ae..182aa2136 100644 --- a/lib/subghz/protocols/star_line.c +++ b/lib/subghz/protocols/star_line.c @@ -77,7 +77,7 @@ const SubGhzProtocol subghz_protocol_star_line = { .name = SUBGHZ_PROTOCOL_STAR_LINE_NAME, .type = SubGhzProtocolTypeDynamic, .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | - SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save, + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, .decoder = &subghz_protocol_star_line_decoder, .encoder = &subghz_protocol_star_line_encoder, @@ -236,7 +236,7 @@ static bool subghz_protocol_encoder_star_line_get_upload( } size_t index = 0; - size_t size_upload = 6 * 2 + (instance->generic.data_count_bit * 2) + 4; + size_t size_upload = 6 * 2 + (instance->generic.data_count_bit * 2); if(size_upload > instance->encoder.size_upload) { FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); return false; @@ -763,8 +763,7 @@ void subghz_protocol_decoder_star_line_get_string(void* context, FuriString* out "Key:%08lX%08lX\r\n" "Fix:0x%08lX Cnt:%04lX\r\n" "Hop:0x%08lX Btn:%02X\r\n" - "MF:%s\r\n" - "Sn:0x%07lX \r\n", + "MF:%s\r\n", instance->generic.protocol_name, instance->generic.data_count_bit, code_found_hi, @@ -773,6 +772,5 @@ void subghz_protocol_decoder_star_line_get_string(void* context, FuriString* out instance->generic.cnt, code_found_reverse_lo, instance->generic.btn, - instance->manufacture_name, - instance->generic.serial); + instance->manufacture_name); } From a1b368abda1c5e17b79aeb0ea7610cf78fc41c31 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 17 Nov 2022 22:30:25 +0300 Subject: [PATCH 2/9] Update i2c tools https://github.com/NaejEL/flipperzero-i2ctools --- .../plugins/flipper_i2ctools/i2csniffer.c | 2 + .../plugins/flipper_i2ctools/i2csniffer.h | 1 + .../plugins/flipper_i2ctools/i2ctools.c | 52 +++++++++++-- .../images/i2ctools_main_76x59.png | Bin 0 -> 1058 bytes .../images/passport_bad3_46x49.png | Bin 1304 -> 0 bytes .../images/passport_happy2_46x49.png | Bin 1328 -> 0 bytes .../images/passport_happy3_46x49.png | Bin 1348 -> 0 bytes .../flipper_i2ctools/views/main_view.c | 9 +-- .../flipper_i2ctools/views/main_view.h | 12 +-- .../flipper_i2ctools/views/scanner_view.c | 32 +++----- .../flipper_i2ctools/views/scanner_view.h | 4 +- .../flipper_i2ctools/views/sender_view.c | 56 +++++++++----- .../flipper_i2ctools/views/sender_view.h | 4 +- .../flipper_i2ctools/views/sniffer_view.c | 70 +++++++++++------- .../flipper_i2ctools/views/sniffer_view.h | 4 +- .../scenes/wifi_marauder_scene_start.c | 10 ++- 16 files changed, 163 insertions(+), 93 deletions(-) create mode 100644 applications/plugins/flipper_i2ctools/images/i2ctools_main_76x59.png delete mode 100644 applications/plugins/flipper_i2ctools/images/passport_bad3_46x49.png delete mode 100644 applications/plugins/flipper_i2ctools/images/passport_happy2_46x49.png delete mode 100644 applications/plugins/flipper_i2ctools/images/passport_happy3_46x49.png diff --git a/applications/plugins/flipper_i2ctools/i2csniffer.c b/applications/plugins/flipper_i2ctools/i2csniffer.c index b737a2be9..6a633cfaf 100644 --- a/applications/plugins/flipper_i2ctools/i2csniffer.c +++ b/applications/plugins/flipper_i2ctools/i2csniffer.c @@ -86,6 +86,8 @@ void SCLcallback(void* _i2c_sniffer) { i2cSniffer* i2c_sniffer_alloc() { i2cSniffer* i2c_sniffer = malloc(sizeof(i2cSniffer)); i2c_sniffer->started = false; + i2c_sniffer->row_index = 0; + i2c_sniffer->menu_index = 0; clear_sniffer_buffers(i2c_sniffer); return i2c_sniffer; } diff --git a/applications/plugins/flipper_i2ctools/i2csniffer.h b/applications/plugins/flipper_i2ctools/i2csniffer.h index 908e91031..eef26bea3 100644 --- a/applications/plugins/flipper_i2ctools/i2csniffer.h +++ b/applications/plugins/flipper_i2ctools/i2csniffer.h @@ -33,6 +33,7 @@ typedef struct { i2cFrame frames[MAX_RECORDS]; uint8_t frame_index; uint8_t menu_index; + uint8_t row_index; } i2cSniffer; void clear_sniffer_buffers(i2cSniffer* i2c_sniffer); diff --git a/applications/plugins/flipper_i2ctools/i2ctools.c b/applications/plugins/flipper_i2ctools/i2ctools.c index 2641601c5..9d73a73b8 100644 --- a/applications/plugins/flipper_i2ctools/i2ctools.c +++ b/applications/plugins/flipper_i2ctools/i2ctools.c @@ -68,6 +68,7 @@ int32_t i2ctools_app(void* p) { i2ctools->sender->scanner = i2ctools->scanner; while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) { + // Back if(event.key == InputKeyBack && event.type == InputTypeRelease) { if(i2ctools->main_view->current_view == MAIN_VIEW) { break; @@ -79,7 +80,9 @@ int32_t i2ctools_app(void* p) { } i2ctools->main_view->current_view = MAIN_VIEW; } - } else if(event.key == InputKeyUp && event.type == InputTypeRelease) { + } + // Up + else if(event.key == InputKeyUp && event.type == InputTypeRelease) { if(i2ctools->main_view->current_view == MAIN_VIEW) { if((i2ctools->main_view->menu_index > SCAN_VIEW)) { i2ctools->main_view->menu_index--; @@ -88,41 +91,76 @@ int32_t i2ctools_app(void* p) { if(i2ctools->scanner->menu_index > 0) { i2ctools->scanner->menu_index--; } + } else if(i2ctools->main_view->current_view == SNIFF_VIEW) { + if(i2ctools->sniffer->row_index > 0) { + i2ctools->sniffer->row_index--; + } } else if(i2ctools->main_view->current_view == SEND_VIEW) { if(i2ctools->sender->value < 0xFF) { i2ctools->sender->value++; i2ctools->sender->sended = false; } } - } else if( + } + // Long Up + else if( event.key == InputKeyUp && (event.type == InputTypeLong || event.type == InputTypeRepeat)) { - if(i2ctools->main_view->current_view == SEND_VIEW) { + if(i2ctools->main_view->current_view == SCAN_VIEW) { + if(i2ctools->scanner->menu_index > 5) { + i2ctools->scanner->menu_index -= 5; + } + } else if(i2ctools->main_view->current_view == SEND_VIEW) { if(i2ctools->sender->value < 0xF9) { i2ctools->sender->value += 5; i2ctools->sender->sended = false; } + } else if(i2ctools->main_view->current_view == SNIFF_VIEW) { + if(i2ctools->sniffer->row_index > 5) { + i2ctools->sniffer->row_index -= 5; + } else { + i2ctools->sniffer->row_index = 0; + } } - } else if(event.key == InputKeyDown && event.type == InputTypeRelease) { + } + // Down + else if(event.key == InputKeyDown && event.type == InputTypeRelease) { if(i2ctools->main_view->current_view == MAIN_VIEW) { - if(i2ctools->main_view->menu_index < 3) { + if(i2ctools->main_view->menu_index < MENU_SIZE - 1) { i2ctools->main_view->menu_index++; } } else if(i2ctools->main_view->current_view == SCAN_VIEW) { if(i2ctools->scanner->menu_index < ((int)i2ctools->scanner->nb_found / 3)) { i2ctools->scanner->menu_index++; } + } else if(i2ctools->main_view->current_view == SNIFF_VIEW) { + if((i2ctools->sniffer->row_index + 3) < + (int)i2ctools->sniffer->frames[i2ctools->sniffer->menu_index].data_index) { + i2ctools->sniffer->row_index++; + } } else if(i2ctools->main_view->current_view == SEND_VIEW) { if(i2ctools->sender->value > 0x00) { i2ctools->sender->value--; i2ctools->sender->sended = false; } } - } else if(event.key == InputKeyDown && event.type == InputTypeLong) { + } + // Long Down + else if( + event.key == InputKeyDown && + (event.type == InputTypeLong || event.type == InputTypeRepeat)) { if(i2ctools->main_view->current_view == SEND_VIEW) { if(i2ctools->sender->value > 0x05) { i2ctools->sender->value -= 5; i2ctools->sender->sended = false; + } else { + i2ctools->sender->value = 0; + i2ctools->sender->sended = false; + } + } else if(i2ctools->main_view->current_view == SNIFF_VIEW) { + if((i2ctools->sniffer->row_index + 8) < + (int)i2ctools->sniffer->frames[i2ctools->sniffer->menu_index].data_index) { + i2ctools->sniffer->row_index += 5; } } @@ -153,6 +191,7 @@ int32_t i2ctools_app(void* p) { } else if(i2ctools->main_view->current_view == SNIFF_VIEW) { if(i2ctools->sniffer->menu_index < i2ctools->sniffer->frame_index) { i2ctools->sniffer->menu_index++; + i2ctools->sniffer->row_index = 0; } } } else if(event.key == InputKeyLeft && event.type == InputTypeRelease) { @@ -164,6 +203,7 @@ int32_t i2ctools_app(void* p) { } else if(i2ctools->main_view->current_view == SNIFF_VIEW) { if(i2ctools->sniffer->menu_index > 0) { i2ctools->sniffer->menu_index--; + i2ctools->sniffer->row_index = 0; } } } diff --git a/applications/plugins/flipper_i2ctools/images/i2ctools_main_76x59.png b/applications/plugins/flipper_i2ctools/images/i2ctools_main_76x59.png new file mode 100644 index 0000000000000000000000000000000000000000..a0b2a8983ceea3dec4a6f9e39db3551214cbcb4f GIT binary patch literal 1058 zcmV+-1l{|IP)EX>4Tx04R}tkv&MmKp2MKrb?w&9PA*XkfC<6i;6hbDionYs1;guFuC*(nlvOW zE{=k0!NH%!s)LKOt`4q(Aov5~=;Wm6A|-y86k5c1$8itueecWNcYx5WFwN?T1Dakl z)5(OG&8>=oSM<{iB8oAYS;m|srQkWf?&0J6U5saW*ZnyL)V#$2pGX{MhFK%tAfDN* z8Jzct!>lB$#OK5lCS8#Dk?V@fZ=8z`3p_JyX43P-VPdh^#Yz{mlBp3-6Gv1{r+gvn zvdVdjvsS6I_C5IvLwS8=nd`Jhk;EdFAVGwJI?AY^h8XQSDHhUnp78LGIDUy-3c1Q) z0{s+H%YZay@-K00HCj!mF1w0ImhB3d)wE{|8cNb7XJpCN*2_GaJ`eYotmLlW z8cL2Nu1Q=IuustnYus5i5}YG|q7nd?I9|`$B7!~&#){VG4j4i?dZ6^`#LodHfrS>? zZwAmEFs|gF)L7yeYN^X+N$FUpB>;5cXbmXMX+4VSTA1fa1p4t_)+V{KJ7Ah!x45e( zaMsO5YRaE@Oaa!5MVeiq=0SjnD%3+P%mSA5K^D-S^0Xl_j8b9&4B1@|%NgaiWR~=d zS<;P-NAi%$D{4I+E?G1I(6TUUfnM`VH$_dSr*1KZJqh|8NsY+Bqj)5gB_oRSXoen@ zB~L3qi6XIY*OO=ZO35SY1S|ndz!IVhO-t@58`1m^Qv~YfKzf6rOfXRcytG#ws-q!wyIYd^)Aa|e~?ZxbMHO( zobP<+HBWaY+c(tQQG+1JhWO@43a(!GQrCIlclUh%18}+Bjb_{~Gw0?d8z3RolmQyo zr5=z1l3E=68Uzr;Gp?mGZYI$oDyHt0$~xYHZb54V3A7e0N$CeJDuW))2x5z~pJ1q_ z2C;4~K_;v)=+!ol*r019nN~*n6+y*X??VFx5d!GImC%AdU^rqSh%MoYa93L+BC!H&ILn!WIU@>^MNnRn(Dia)OWKZ`0{_!kRoh7yEkLAzV-DF0 zEJ&`gY7CQibw_1I$VPn7)?ihnfrzOL>A-N~kstYg#DHcuBM=At{3xdkwyy^ov($CUN4u)T`SFcE4rB9&*hGA9N zhziB$IG^IfB?{zlN?;k>FDn3-c#`wyI9_EL5+fi*qTD%GbW&9W+q1k~84P$>87*MI zd9vZ)@P{U!fJ3*gvm+fXl}d2?(A=r*2(o5lJQ7M5zJ2AT_}b6V^`7a{=!f+aKwW#{ zK#*+ubL{$0C$8n$k^m}!+ z4aqGxKUFwYO9kHiYvbahk39Cg+BCCo%lQ|M%n6$g@0tAQ^Oob^{JwL>IUGgu*GwPc zUM;p;E48 fV|H=hUc`f(xyf_n$$93k^1mt`O-5$gvSa@Nx4y<4 diff --git a/applications/plugins/flipper_i2ctools/images/passport_happy2_46x49.png b/applications/plugins/flipper_i2ctools/images/passport_happy2_46x49.png deleted file mode 100644 index f64e770e5a038162d1ceae38d04ff043319ed581..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1328 zcmaJ>Yitx%6rNHagjluO2sA~8L5mM&=dm-pJCklnyW7Xw?z-8ow1|+-+_|%zwDWLg z*4=JQ4T2E_{h_2)G0`ZMkTi{u5Qw0Lw#J|dQHh8c!L(6Iq@h|9+oV|Uw%y7P!Xz{I z-gD1)&Uaq3Cmw4kSy8?M!?2P_V>p3U4|IFeIR98utqxMUo{T%Nuc)W*Lg+D25|xTJ#Dc$Ki_)f!x`O zDkj49i_Xv~NOZWaB~nx-lksG{9@9=yj35XU%~C8&A`Q~%He4x78qWHHg)nr0ty!*S z8hGBKB%5hBNFb^UG3Zt_x@6dJ7Bhu%Mr9?7VmvgZ>-oUuwH-GB|EFWHw{0D zm3rIM@%c21+AS#f6e!CaDz?C?EXi>^AO%6;Nx$NQDjnchuZqH7z$-VUZ=p|-1chN0 z*oc7ftGo~RNQr?e$q1a649EbIlAq=SD(_b~FHKO0B9-r)n>wi=LhYH~E)51cER7a4 z&^*~_aK^uDI){etu6T2@Zfd*YjtfxXp%eGRQg&lXYD z>C^k^p0%q=)2sVF6f4_;?|fQ5nD}e+WMi(s`rs$KPR)#LId=cV_R~+^*cMxxJJdgV zw0&8_+g)6A`PQ$~Hy$Y)&plLe;h6CKop*03e)#I^J9|&;h*gA2hyRHmn118qjZ-DT zYs5z{4S%Iqzp~Og+&k7g_(c1f%Bs?t%uxEZ{r1o=vmcyD_N6DLe{8kRrvkelywvq; z`Q^g{dk0@NX5Y;``_suk`^t}iYXe6{)aRPFZu@fLk9C(o@0F3?Ce_;EL2>Mdvm3V0 z_HUjky{>&ex-K?+CR4f6soHSh^7(%sEv3pv->1q>-LVRrpo*u*!||g0KP*xg3lG+| Gzx*E~RoOxS diff --git a/applications/plugins/flipper_i2ctools/images/passport_happy3_46x49.png b/applications/plugins/flipper_i2ctools/images/passport_happy3_46x49.png deleted file mode 100644 index 7aef17674336e71cb1cdf323c1fb039e0e627d33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1348 zcmaJ>eQXnD7{7&~lejEf6dZ`TCJQE*5i}V=Gtg{i3Pxj)$VR4uj%5Br(2>QcxJ9tO-PXw;3zyuz@B6&Z z?|FXD*S*$I_h|8o)hiGLDGt_15x6?wOBF4H-?y&BYT;6D`y1`erf#QY3m{(2Q~(-` z%S|8xWUYP2H^7Y`%eswdqum$|iK-cQ$T=NHCZ2?71aWW5BxN-QY*YbFM#6(l4~<}` zp?R>UxG)(``arW$(_w+l9d%K)Bc=)(wrL~k&WO-J9N03NiMJ$DV#b5b*%jeFCnhj- zPQ{LSuz6CA;Re)aS^(u86t0paiSmL&lNDK2lnp3N(iB0m1jXVcDKdh{vgpEtL3fs> zixDZX;0&HTShH;>MS@7D(~dObFs&wn5(I%DX@aJ4sDY>26Skbe6RGui3ld1FmXWj# zGlAwT%8J=)doW0KK8AQQ99}e>NG)Uv=8VY5NrG~aL_D4gY)(66N5KCymefu~+mnEZ zfRx#4sjwjW`aBpW@Ai&zija+1ZyB&Ea*JfDt#OdBgOUe>HxA9vM4bc*$0-`F0Gh{H zMo@8?BRQPYR8HkN!AUA=-p*2ZUSj9~!%3{G+DlP>pNr)J66584924*d=;}N+m`K@j zLIru>2K2pv_1zXL`Ya&ZrWG~KmV6sDG@G`WYBrN7%{WN(p|GqPiJYV|SEc!&C14qC zKnqxA9Gy$EXe>d&sR2b{VX*~Tr*W3$R9p}=4(Bx|&`B3dGdc`^9{kf_iiuqr*cMf-r|D(OMvukwvy8`o1`tw&u9$(pU5#95~ z%oTI>8uxp$)MLN!$|u8Ts>&uiuO7ZWBpiL98lP5}6NArIJQJ=spqB+Br+<8N>Vw_S z_Y<{yCf_|@e7Vx~+0Lm4rC5)>;nUic6RxqR?aGg??}}}We<5Oh`o+G7&-IS&?LRe} z-r_uRFyy2dJyS4Wz?o~hpirfB!b{SC`cogKU3Sa;{l$NW9Rh4&#f XzZTxR@26EIx&Kmenu_index) { case SCAN_VIEW: @@ -15,7 +14,7 @@ void draw_main_view(Canvas* canvas, i2cMainView* main_view) { canvas, SNIFF_MENU_X, SNIFF_MENU_Y, AlignLeft, AlignTop, SNIFF_MENU_TEXT); canvas_draw_str_aligned( canvas, SEND_MENU_X, SEND_MENU_Y, AlignLeft, AlignTop, SEND_MENU_TEXT); - canvas_draw_rbox(canvas, 60, SCAN_MENU_Y - 2, 60, 13, 3); + canvas_draw_rbox(canvas, 80, SCAN_MENU_Y - 2, 43, 13, 3); canvas_set_color(canvas, ColorWhite); canvas_draw_str_aligned( canvas, SCAN_MENU_X, SCAN_MENU_Y, AlignLeft, AlignTop, SCAN_MENU_TEXT); @@ -27,7 +26,7 @@ void draw_main_view(Canvas* canvas, i2cMainView* main_view) { canvas, SCAN_MENU_X, SCAN_MENU_Y, AlignLeft, AlignTop, SCAN_MENU_TEXT); canvas_draw_str_aligned( canvas, SEND_MENU_X, SEND_MENU_Y, AlignLeft, AlignTop, SEND_MENU_TEXT); - canvas_draw_rbox(canvas, 60, SNIFF_MENU_Y - 2, 60, 13, 3); + canvas_draw_rbox(canvas, 80, SNIFF_MENU_Y - 2, 43, 13, 3); canvas_set_color(canvas, ColorWhite); canvas_draw_str_aligned( canvas, SNIFF_MENU_X, SNIFF_MENU_Y, AlignLeft, AlignTop, SNIFF_MENU_TEXT); @@ -39,7 +38,7 @@ void draw_main_view(Canvas* canvas, i2cMainView* main_view) { canvas, SCAN_MENU_X, SCAN_MENU_Y, AlignLeft, AlignTop, SCAN_MENU_TEXT); canvas_draw_str_aligned( canvas, SNIFF_MENU_X, SNIFF_MENU_Y, AlignLeft, AlignTop, SNIFF_MENU_TEXT); - canvas_draw_rbox(canvas, 60, SEND_MENU_Y - 2, 60, 13, 3); + canvas_draw_rbox(canvas, 80, SEND_MENU_Y - 2, 43, 13, 3); canvas_set_color(canvas, ColorWhite); canvas_draw_str_aligned( canvas, SEND_MENU_X, SEND_MENU_Y, AlignLeft, AlignTop, SEND_MENU_TEXT); diff --git a/applications/plugins/flipper_i2ctools/views/main_view.h b/applications/plugins/flipper_i2ctools/views/main_view.h index 3a9211529..050e41130 100644 --- a/applications/plugins/flipper_i2ctools/views/main_view.h +++ b/applications/plugins/flipper_i2ctools/views/main_view.h @@ -5,16 +5,16 @@ #define APP_NAME "I2C Tools" #define SCAN_MENU_TEXT "Scan" -#define SCAN_MENU_X 75 -#define SCAN_MENU_Y 6 +#define SCAN_MENU_X 90 +#define SCAN_MENU_Y 13 #define SNIFF_MENU_TEXT "Sniff" -#define SNIFF_MENU_X 75 -#define SNIFF_MENU_Y 20 +#define SNIFF_MENU_X 90 +#define SNIFF_MENU_Y 27 #define SEND_MENU_TEXT "Send" -#define SEND_MENU_X 75 -#define SEND_MENU_Y 34 +#define SEND_MENU_X 90 +#define SEND_MENU_Y 41 // Menu typedef enum { diff --git a/applications/plugins/flipper_i2ctools/views/scanner_view.c b/applications/plugins/flipper_i2ctools/views/scanner_view.c index 346f82590..f8bea6f40 100644 --- a/applications/plugins/flipper_i2ctools/views/scanner_view.c +++ b/applications/plugins/flipper_i2ctools/views/scanner_view.c @@ -4,15 +4,12 @@ void draw_scanner_view(Canvas* canvas, i2cScanner* i2c_scanner) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); canvas_draw_rframe(canvas, 0, 0, 128, 64, 3); - canvas_draw_icon(canvas, 2, 13, &I_passport_happy3_46x49); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, SCAN_MENU_TEXT); char count_text[46]; - char count_text_fmt[] = "Found: %d"; + char count_text_fmt[] = "Peripherals Found: %d"; canvas_set_font(canvas, FontSecondary); snprintf(count_text, sizeof(count_text), count_text_fmt, (int)i2c_scanner->nb_found); - canvas_draw_str_aligned(canvas, 50, 3, AlignLeft, AlignTop, count_text); + canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, count_text); uint8_t x_pos = 0; uint8_t y_pos = 0; uint8_t idx_to_print = 0; @@ -23,21 +20,16 @@ void draw_scanner_view(Canvas* canvas, i2cScanner* i2c_scanner) { } snprintf( count_text, sizeof(count_text), "0x%02x ", (int)i2c_scanner->addresses[idx_to_print]); - if(i < 3) { - x_pos = 50 + (i * 26); + const uint8_t x_start = 3; + if(i < 4) { + x_pos = x_start + (i * 26); y_pos = 15; - } else if(i < 6) { - x_pos = 50 + ((i - 3) * 26); + } else if(i < 8) { + x_pos = x_start + ((i - 4) * 26); y_pos = 25; - } else if(i < 9) { - x_pos = 50 + ((i - 6) * 26); - y_pos = 35; } else if(i < 12) { - x_pos = 50 + ((i - 9) * 26); - y_pos = 45; - } else if(i < 15) { - x_pos = 50 + ((i - 12) * 26); - y_pos = 55; + x_pos = x_start + ((i - 8) * 26); + y_pos = 35; } else { break; } @@ -48,8 +40,8 @@ void draw_scanner_view(Canvas* canvas, i2cScanner* i2c_scanner) { canvas_draw_rbox(canvas, 125, y_pos, 3, 10, 1); // Button - canvas_draw_rbox(canvas, 70, 48, 45, 13, 3); + canvas_draw_rbox(canvas, 45, 48, 45, 13, 3); canvas_set_color(canvas, ColorWhite); - canvas_draw_icon(canvas, 75, 50, &I_Ok_btn_9x9); - canvas_draw_str_aligned(canvas, 85, 51, AlignLeft, AlignTop, "Scan"); + canvas_draw_icon(canvas, 50, 50, &I_Ok_btn_9x9); + canvas_draw_str_aligned(canvas, 62, 51, AlignLeft, AlignTop, "Scan"); } \ No newline at end of file diff --git a/applications/plugins/flipper_i2ctools/views/scanner_view.h b/applications/plugins/flipper_i2ctools/views/scanner_view.h index 53aee33f2..02bc8fb1c 100644 --- a/applications/plugins/flipper_i2ctools/views/scanner_view.h +++ b/applications/plugins/flipper_i2ctools/views/scanner_view.h @@ -4,8 +4,6 @@ #include #include "../i2cscanner.h" -#define SCAN_MENU_TEXT "Scan" -#define SCAN_MENU_X 75 -#define SCAN_MENU_Y 6 +#define SCAN_TEXT "SCAN" void draw_scanner_view(Canvas* canvas, i2cScanner* i2c_scanner); \ No newline at end of file diff --git a/applications/plugins/flipper_i2ctools/views/sender_view.c b/applications/plugins/flipper_i2ctools/views/sender_view.c index a48e9b5dc..216220209 100644 --- a/applications/plugins/flipper_i2ctools/views/sender_view.c +++ b/applications/plugins/flipper_i2ctools/views/sender_view.c @@ -4,9 +4,6 @@ void draw_sender_view(Canvas* canvas, i2cSender* i2c_sender) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); canvas_draw_rframe(canvas, 0, 0, 128, 64, 3); - canvas_draw_icon(canvas, 2, 13, &I_passport_happy2_46x49); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, SEND_MENU_TEXT); if(!i2c_sender->scanner->scanned) { scan_i2c_bus(i2c_sender->scanner); @@ -14,39 +11,60 @@ void draw_sender_view(Canvas* canvas, i2cSender* i2c_sender) { canvas_set_font(canvas, FontSecondary); if(i2c_sender->scanner->nb_found <= 0) { - canvas_draw_str_aligned(canvas, 60, 5, AlignLeft, AlignTop, "No peripherals"); - canvas_draw_str_aligned(canvas, 60, 15, AlignLeft, AlignTop, "Found"); + canvas_draw_str_aligned(canvas, 20, 5, AlignLeft, AlignTop, "No peripherals found"); return; } - canvas_draw_rbox(canvas, 70, 48, 45, 13, 3); + // Send Button + canvas_draw_rbox(canvas, 45, 48, 45, 13, 3); canvas_set_color(canvas, ColorWhite); - canvas_draw_icon(canvas, 75, 50, &I_Ok_btn_9x9); - canvas_draw_str_aligned(canvas, 85, 51, AlignLeft, AlignTop, "Send"); + canvas_draw_icon(canvas, 50, 50, &I_Ok_btn_9x9); + canvas_draw_str_aligned(canvas, 62, 51, AlignLeft, AlignTop, "Send"); + // Addr canvas_set_color(canvas, ColorBlack); - canvas_draw_str_aligned(canvas, 50, 5, AlignLeft, AlignTop, "Addr: "); - canvas_draw_icon(canvas, 80, 5, &I_ButtonLeft_4x7); - canvas_draw_icon(canvas, 115, 5, &I_ButtonRight_4x7); + canvas_draw_str_aligned(canvas, 3, 5, AlignLeft, AlignTop, "Addr: "); + canvas_draw_icon(canvas, 33, 5, &I_ButtonLeft_4x7); + canvas_draw_icon(canvas, 68, 5, &I_ButtonRight_4x7); char addr_text[8]; snprintf( addr_text, sizeof(addr_text), "0x%02x", (int)i2c_sender->scanner->addresses[i2c_sender->address_idx]); - canvas_draw_str_aligned(canvas, 90, 5, AlignLeft, AlignTop, addr_text); - canvas_draw_str_aligned(canvas, 50, 15, AlignLeft, AlignTop, "Value: "); - - canvas_draw_icon(canvas, 80, 17, &I_ButtonUp_7x4); - canvas_draw_icon(canvas, 115, 17, &I_ButtonDown_7x4); + canvas_draw_str_aligned(canvas, 43, 5, AlignLeft, AlignTop, addr_text); + // Value + canvas_draw_str_aligned(canvas, 3, 15, AlignLeft, AlignTop, "Value: "); + canvas_draw_icon(canvas, 33, 17, &I_ButtonUp_7x4); + canvas_draw_icon(canvas, 68, 17, &I_ButtonDown_7x4); snprintf(addr_text, sizeof(addr_text), "0x%02x", (int)i2c_sender->value); - canvas_draw_str_aligned(canvas, 90, 15, AlignLeft, AlignTop, addr_text); + canvas_draw_str_aligned(canvas, 43, 15, AlignLeft, AlignTop, addr_text); if(i2c_sender->must_send) { i2c_send(i2c_sender); } - canvas_draw_str_aligned(canvas, 50, 25, AlignLeft, AlignTop, "Result: "); + // Result + canvas_draw_str_aligned(canvas, 3, 25, AlignLeft, AlignTop, "Result: "); if(i2c_sender->sended) { + uint8_t row = 1; + uint8_t column = 1; + const uint8_t x_min = 3; + const uint8_t y_min = 25; + uint8_t x_pos = 0; + uint8_t y_pos = 0; for(uint8_t i = 0; i < sizeof(i2c_sender->recv); i++) { + x_pos = x_min + (column - 1) * 35; + if(row == 1) { + x_pos += 40; + } + y_pos = y_min + (row - 1) * 10; snprintf(addr_text, sizeof(addr_text), "0x%02x", (int)i2c_sender->recv[i]); - canvas_draw_str_aligned(canvas, 90, 25 + (i * 10), AlignLeft, AlignTop, addr_text); + canvas_draw_str_aligned(canvas, x_pos, y_pos, AlignLeft, AlignTop, addr_text); + column++; + if((row > 1 && column > 3) || (row == 1 && column > 2)) { + column = 1; + row++; + } + if(row > 2) { + break; + } } } } \ No newline at end of file diff --git a/applications/plugins/flipper_i2ctools/views/sender_view.h b/applications/plugins/flipper_i2ctools/views/sender_view.h index 96cc28fbc..5f48081dd 100644 --- a/applications/plugins/flipper_i2ctools/views/sender_view.h +++ b/applications/plugins/flipper_i2ctools/views/sender_view.h @@ -4,8 +4,6 @@ #include #include "../i2csender.h" -#define SEND_MENU_TEXT "Send" -#define SEND_MENU_X 75 -#define SEND_MENU_Y 34 +#define SEND_TEXT "SEND" void draw_sender_view(Canvas* canvas, i2cSender* i2c_sender); \ No newline at end of file diff --git a/applications/plugins/flipper_i2ctools/views/sniffer_view.c b/applications/plugins/flipper_i2ctools/views/sniffer_view.c index dbed3e4c9..a05873930 100644 --- a/applications/plugins/flipper_i2ctools/views/sniffer_view.c +++ b/applications/plugins/flipper_i2ctools/views/sniffer_view.c @@ -4,73 +4,89 @@ void draw_sniffer_view(Canvas* canvas, i2cSniffer* i2c_sniffer) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); canvas_draw_rframe(canvas, 0, 0, 128, 64, 3); - canvas_draw_icon(canvas, 2, 13, &I_passport_happy2_46x49); - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, SNIFF_MENU_TEXT); canvas_set_font(canvas, FontSecondary); // Button - canvas_draw_rbox(canvas, 70, 48, 45, 13, 3); + canvas_draw_rbox(canvas, 40, 48, 45, 13, 3); canvas_set_color(canvas, ColorWhite); - canvas_draw_icon(canvas, 75, 50, &I_Ok_btn_9x9); + canvas_draw_icon(canvas, 45, 50, &I_Ok_btn_9x9); if(!i2c_sniffer->started) { - canvas_draw_str_aligned(canvas, 85, 51, AlignLeft, AlignTop, "Start"); + canvas_draw_str_aligned(canvas, 57, 51, AlignLeft, AlignTop, "Start"); } else { - canvas_draw_str_aligned(canvas, 85, 51, AlignLeft, AlignTop, "Stop"); + canvas_draw_str_aligned(canvas, 57, 51, AlignLeft, AlignTop, "Stop"); } canvas_set_color(canvas, ColorBlack); if(i2c_sniffer->first) { - canvas_draw_str_aligned(canvas, 50, 3, AlignLeft, AlignTop, "Nothing Recorded"); + canvas_draw_str_aligned(canvas, 30, 3, AlignLeft, AlignTop, "Nothing Recorded"); return; } - char text_buffer[8]; + char text_buffer[10]; // nbFrame text - canvas_draw_str_aligned(canvas, 50, 3, AlignLeft, AlignTop, "Frame: "); - snprintf(text_buffer, sizeof(text_buffer), "%d", (int)i2c_sniffer->menu_index + 1); - canvas_draw_str_aligned(canvas, 85, 3, AlignLeft, AlignTop, text_buffer); - canvas_draw_str_aligned(canvas, 100, 3, AlignLeft, AlignTop, "/"); - snprintf(text_buffer, sizeof(text_buffer), "%d", (int)i2c_sniffer->frame_index + 1); - canvas_draw_str_aligned(canvas, 110, 3, AlignLeft, AlignTop, text_buffer); + canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, "Frame: "); + snprintf( + text_buffer, + sizeof(text_buffer), + "%d/%d", + (int)i2c_sniffer->menu_index + 1, + (int)i2c_sniffer->frame_index + 1); + canvas_draw_str_aligned(canvas, 38, 3, AlignLeft, AlignTop, text_buffer); // Address text snprintf( text_buffer, sizeof(text_buffer), "0x%02x", (int)(i2c_sniffer->frames[i2c_sniffer->menu_index].data[0] >> 1)); - canvas_draw_str_aligned(canvas, 50, 13, AlignLeft, AlignTop, "Addr: "); - canvas_draw_str_aligned(canvas, 75, 13, AlignLeft, AlignTop, text_buffer); + canvas_draw_str_aligned(canvas, 3, 13, AlignLeft, AlignTop, "Addr: "); + canvas_draw_str_aligned(canvas, 30, 13, AlignLeft, AlignTop, text_buffer); // R/W if((int)(i2c_sniffer->frames[i2c_sniffer->menu_index].data[0]) % 2 == 0) { - canvas_draw_str_aligned(canvas, 105, 13, AlignLeft, AlignTop, "W"); + canvas_draw_str_aligned(canvas, 58, 13, AlignLeft, AlignTop, "Write"); } else { - canvas_draw_str_aligned(canvas, 105, 13, AlignLeft, AlignTop, "R"); + canvas_draw_str_aligned(canvas, 58, 13, AlignLeft, AlignTop, "Read"); + } + // ACK + if(i2c_sniffer->frames[i2c_sniffer->menu_index].ack[0]) { + canvas_draw_str_aligned(canvas, 90, 13, AlignLeft, AlignTop, "ACK"); + } else { + canvas_draw_str_aligned(canvas, 90, 13, AlignLeft, AlignTop, "NACK"); } // Frames content - const uint8_t x_min = 50; + const uint8_t x_min = 3; const uint8_t y_min = 23; uint8_t x_pos = 0; uint8_t y_pos = 0; uint8_t row = 1; uint8_t column = 1; - for(uint8_t i = 1; i < i2c_sniffer->frames[i2c_sniffer->menu_index].data_index; i++) { + uint8_t frame_size = i2c_sniffer->frames[i2c_sniffer->menu_index].data_index; + uint8_t offset = i2c_sniffer->row_index; + if(i2c_sniffer->row_index > 0) { + offset += 1; + } + canvas_draw_str_aligned(canvas, x_min, y_min, AlignLeft, AlignTop, "Data:"); + for(uint8_t i = 1 + offset; i < frame_size; i++) { snprintf( text_buffer, sizeof(text_buffer), "0x%02x", (int)i2c_sniffer->frames[i2c_sniffer->menu_index].data[i]); x_pos = x_min + (column - 1) * 35; - y_pos = y_min + (row - 1) * 10; - column++; - if(column > 2) { - column = 1; - row++; + if(row == 1) { + x_pos += 30; } + y_pos = y_min + (row - 1) * 10; canvas_draw_str_aligned(canvas, x_pos, y_pos, AlignLeft, AlignTop, text_buffer); if(i2c_sniffer->frames[i2c_sniffer->menu_index].ack[i]) { canvas_draw_str_aligned(canvas, x_pos + 24, y_pos, AlignLeft, AlignTop, "A"); } else { canvas_draw_str_aligned(canvas, x_pos + 24, y_pos, AlignLeft, AlignTop, "N"); } + column++; + if((row > 1 && column > 3) || (row == 1 && column > 2)) { + column = 1; + row++; + } + if(row > 2) { + break; + } } } \ No newline at end of file diff --git a/applications/plugins/flipper_i2ctools/views/sniffer_view.h b/applications/plugins/flipper_i2ctools/views/sniffer_view.h index 3fe1839a1..80c92f7fc 100644 --- a/applications/plugins/flipper_i2ctools/views/sniffer_view.h +++ b/applications/plugins/flipper_i2ctools/views/sniffer_view.h @@ -4,8 +4,6 @@ #include #include "../i2csniffer.h" -#define SNIFF_MENU_TEXT "Sniff" -#define SNIFF_MENU_X 75 -#define SNIFF_MENU_Y 20 +#define SNIFF_TEXT "SNIFF" void draw_sniffer_view(Canvas* canvas, i2cSniffer* i2c_sniffer); \ No newline at end of file diff --git a/applications/plugins/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c b/applications/plugins/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c index 136f66f80..029614c5d 100644 --- a/applications/plugins/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c +++ b/applications/plugins/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c @@ -60,7 +60,15 @@ const WifiMarauderItem items[NUM_MENU_ITEMS] = { {"Sniff", {"beacon", "deauth", "esp", "pmkid", "probe", "pwn", "raw", "bt", "skim"}, 9, - {"sniffbeacon", "sniffdeauth", "sniffesp", "sniffpmkid", "sniffprobe", "sniffpwn", "sniffraw", "sniffbt", "sniffskim"}, + {"sniffbeacon", + "sniffdeauth", + "sniffesp", + "sniffpmkid", + "sniffprobe", + "sniffpwn", + "sniffraw", + "sniffbt", + "sniffskim"}, NO_ARGS, FOCUS_CONSOLE_END, SHOW_STOPSCAN_TIP}, From a0dc770b98f47abbba0822483aaae60c53c20c7c Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 17 Nov 2022 22:33:31 +0300 Subject: [PATCH 3/9] Update TOTP https://github.com/akopachov/flipper-zero_authenticator --- .../scenes/app_settings/totp_app_settings.c | 2 +- .../totp_scene_generate_token.c | 2 +- .../plugins/totp/scenes/scene_director.h | 34 ++++ .../scenes/token_menu/totp_scene_token_menu.c | 13 +- .../plugins/totp/scenes/totp_scenes_enum.h | 26 +++ .../plugins/totp/services/base32/base32.c | 2 - .../plugins/totp/services/base32/base32.h | 10 +- applications/plugins/totp/services/cli/cli.c | 5 + .../totp/services/cli/commands/add/add.c | 2 + .../totp/services/cli/commands/help/help.c | 4 + .../totp/services/cli/commands/move/move.c | 164 ++++++++++++++++++ .../totp/services/cli/commands/move/move.h | 12 ++ .../plugins/totp/services/config/config.h | 59 +++++++ .../plugins/totp/services/crypto/crypto.h | 30 ++++ .../plugins/totp/services/crypto/memset_s.h | 9 +- .../totp/services/hid_worker/hid_worker.c | 14 +- .../plugins/totp/services/hmac/byteswap.h | 11 ++ .../plugins/totp/services/list/list.c | 59 ++++++- .../plugins/totp/services/list/list.h | 80 +++++++-- .../totp/services/roll_value/roll_value.h | 41 ++++- .../services/timezone_utils/timezone_utils.h | 12 ++ .../plugins/totp/services/totp/totp.c | 63 +++---- .../plugins/totp/services/totp/totp.h | 54 +++--- .../plugins/totp/services/ui/ui_controls.h | 28 +++ .../plugins/totp/types/plugin_state.h | 60 +++++++ applications/plugins/totp/types/token_info.h | 81 ++++++++- 26 files changed, 780 insertions(+), 97 deletions(-) create mode 100644 applications/plugins/totp/services/cli/commands/move/move.c create mode 100644 applications/plugins/totp/services/cli/commands/move/move.h diff --git a/applications/plugins/totp/scenes/app_settings/totp_app_settings.c b/applications/plugins/totp/scenes/app_settings/totp_app_settings.c index 63db2e46b..84f749159 100644 --- a/applications/plugins/totp/scenes/app_settings/totp_app_settings.c +++ b/applications/plugins/totp/scenes/app_settings/totp_app_settings.c @@ -101,7 +101,7 @@ bool totp_scene_app_settings_handle_event( } SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; - if(event->input.type != InputTypePress) { + if(event->input.type != InputTypePress && event->input.type != InputTypeRepeat) { return true; } diff --git a/applications/plugins/totp/scenes/generate_token/totp_scene_generate_token.c b/applications/plugins/totp/scenes/generate_token/totp_scene_generate_token.c index e2d264cae..266c04736 100644 --- a/applications/plugins/totp/scenes/generate_token/totp_scene_generate_token.c +++ b/applications/plugins/totp/scenes/generate_token/totp_scene_generate_token.c @@ -293,7 +293,7 @@ bool totp_scene_generate_token_handle_event( return true; } - if(event->input.type != InputTypePress) { + if(event->input.type != InputTypePress && event->input.type != InputTypeRepeat) { return true; } diff --git a/applications/plugins/totp/scenes/scene_director.h b/applications/plugins/totp/scenes/scene_director.h index cc06029d3..541a63f1c 100644 --- a/applications/plugins/totp/scenes/scene_director.h +++ b/applications/plugins/totp/scenes/scene_director.h @@ -5,12 +5,46 @@ #include "../types/plugin_event.h" #include "totp_scenes_enum.h" +/** + * @brief Activates scene + * @param plugin_state application state + * @param scene scene to be activated + * @param context scene context to be passed to the scene activation method + */ void totp_scene_director_activate_scene( PluginState* const plugin_state, Scene scene, const void* context); + +/** + * @brief Deactivate current scene + * @param plugin_state application state + */ void totp_scene_director_deactivate_active_scene(PluginState* const plugin_state); + +/** + * @brief Initializes all the available scenes + * @param plugin_state application state + */ void totp_scene_director_init_scenes(PluginState* const plugin_state); + +/** + * @brief Renders current scene + * @param canvas canvas to render at + * @param plugin_state application state + */ void totp_scene_director_render(Canvas* const canvas, PluginState* const plugin_state); + +/** + * @brief Disposes all the available scenes + * @param plugin_state application state + */ void totp_scene_director_dispose(const PluginState* const plugin_state); + +/** + * @brief Handles application event for the current scene + * @param event event to be handled + * @param plugin_state application state + * @return \c true if event handled and applilcation should continue; \c false if application should be closed + */ bool totp_scene_director_handle_event(PluginEvent* const event, PluginState* const plugin_state); diff --git a/applications/plugins/totp/scenes/token_menu/totp_scene_token_menu.c b/applications/plugins/totp/scenes/token_menu/totp_scene_token_menu.c index d936bf95f..d4a837a69 100644 --- a/applications/plugins/totp/scenes/token_menu/totp_scene_token_menu.c +++ b/applications/plugins/totp/scenes/token_menu/totp_scene_token_menu.c @@ -147,13 +147,14 @@ bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginSt dialog_message_free(message); if(dialog_result == DialogMessageButtonRight && !scene_state->current_token_index.is_null) { - ListNode* list_node = list_element_at( - plugin_state->tokens_list, scene_state->current_token_index.value); - - TokenInfo* tokenInfo = list_node->data; - token_info_free(tokenInfo); - plugin_state->tokens_list = list_remove(plugin_state->tokens_list, list_node); + TokenInfo* tokenInfo = NULL; + plugin_state->tokens_list = list_remove_at( + plugin_state->tokens_list, + scene_state->current_token_index.value, + (void**)&tokenInfo); plugin_state->tokens_count--; + furi_check(tokenInfo != NULL); + token_info_free(tokenInfo); totp_full_save_config_file(plugin_state); totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); diff --git a/applications/plugins/totp/scenes/totp_scenes_enum.h b/applications/plugins/totp/scenes/totp_scenes_enum.h index c2b153a02..c90f76bab 100644 --- a/applications/plugins/totp/scenes/totp_scenes_enum.h +++ b/applications/plugins/totp/scenes/totp_scenes_enum.h @@ -1,10 +1,36 @@ #pragma once +/** + * @brief TOTP application scenes + */ typedef enum { + /** + * @brief Empty scene which does nothing + */ TotpSceneNone, + + /** + * @brief Scene where user have to enter PIN to authenticate + */ TotpSceneAuthentication, + + /** + * @brief Scene where actual TOTP token is getting generated and displayed to the user + */ TotpSceneGenerateToken, + + /** + * @brief Scene where user can add new token + */ TotpSceneAddNewToken, + + /** + * @brief Scene with a menu for given token, allowing user to do multiple actions + */ TotpSceneTokenMenu, + + /** + * @brief Scene where user can change application settings + */ TotpSceneAppSettings } Scene; diff --git a/applications/plugins/totp/services/base32/base32.c b/applications/plugins/totp/services/base32/base32.c index 943da6b2a..9781c831f 100644 --- a/applications/plugins/totp/services/base32/base32.c +++ b/applications/plugins/totp/services/base32/base32.c @@ -15,8 +15,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include - #include "base32.h" int base32_decode(const uint8_t* encoded, uint8_t* result, int bufSize) { diff --git a/applications/plugins/totp/services/base32/base32.h b/applications/plugins/totp/services/base32/base32.h index 1d7736e81..dea1a1c81 100644 --- a/applications/plugins/totp/services/base32/base32.h +++ b/applications/plugins/totp/services/base32/base32.h @@ -29,5 +29,11 @@ #include -int base32_decode(const uint8_t* encoded, uint8_t* result, int bufSize) - __attribute__((visibility("hidden"))); +/** + * @brief Decodes Base-32 encoded bytes into plain bytes. + * @param encoded Base-32 encoded bytes + * @param[out] result result output buffer + * @param bufSize result output buffer size + * @return Decoded result length in bytes if successfully decoded; \c -1 otherwise + */ +int base32_decode(const uint8_t* encoded, uint8_t* result, int bufSize); diff --git a/applications/plugins/totp/services/cli/cli.c b/applications/plugins/totp/services/cli/cli.c index 76e58a02d..2cfae3f15 100644 --- a/applications/plugins/totp/services/cli/cli.c +++ b/applications/plugins/totp/services/cli/cli.c @@ -8,6 +8,7 @@ #include "commands/delete/delete.h" #include "commands/timezone/timezone.h" #include "commands/help/help.h" +#include "commands/move/move.h" static void totp_cli_print_unknown_command(const FuriString* unknown_command) { TOTP_CLI_PRINTF( @@ -44,6 +45,10 @@ static void totp_cli_handler(Cli* cli, FuriString* args, void* context) { furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_TIMEZONE) == 0 || furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_TIMEZONE_ALT) == 0) { totp_cli_command_timezone_handle(plugin_state, args, cli); + } else if( + furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_MOVE) == 0 || + furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_MOVE_ALT) == 0) { + totp_cli_command_move_handle(plugin_state, args, cli); } else { totp_cli_print_unknown_command(cmd); } diff --git a/applications/plugins/totp/services/cli/commands/add/add.c b/applications/plugins/totp/services/cli/commands/add/add.c index 2e8f22547..4b7aaf327 100644 --- a/applications/plugins/totp/services/cli/commands/add/add.c +++ b/applications/plugins/totp/services/cli/commands/add/add.c @@ -175,6 +175,8 @@ void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cl } else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_ADD_ARG_UNSECURE_PREFIX) == 0) { mask_user_input = false; parsed = true; + } else { + TOTP_CLI_PRINTF("Unknown argument \"%s\"\r\n", furi_string_get_cstr(temp_str)); } if(!parsed) { diff --git a/applications/plugins/totp/services/cli/commands/help/help.c b/applications/plugins/totp/services/cli/commands/help/help.c index ab592fbba..432f0ab71 100644 --- a/applications/plugins/totp/services/cli/commands/help/help.c +++ b/applications/plugins/totp/services/cli/commands/help/help.c @@ -4,6 +4,7 @@ #include "../delete/delete.h" #include "../list/list.h" #include "../timezone/timezone.h" +#include "../move/move.h" void totp_cli_command_help_docopt_commands() { TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_HELP ", " TOTP_CLI_COMMAND_HELP_ALT @@ -23,6 +24,7 @@ void totp_cli_command_help_handle() { totp_cli_command_add_docopt_usage(); totp_cli_command_delete_docopt_usage(); totp_cli_command_timezone_docopt_usage(); + totp_cli_command_move_docopt_usage(); cli_nl(); TOTP_CLI_PRINTF("Commands:\r\n"); totp_cli_command_help_docopt_commands(); @@ -30,6 +32,7 @@ void totp_cli_command_help_handle() { totp_cli_command_add_docopt_commands(); totp_cli_command_delete_docopt_commands(); totp_cli_command_timezone_docopt_commands(); + totp_cli_command_move_docopt_commands(); cli_nl(); TOTP_CLI_PRINTF("Arguments:\r\n"); totp_cli_command_add_docopt_arguments(); @@ -39,4 +42,5 @@ void totp_cli_command_help_handle() { TOTP_CLI_PRINTF("Options:\r\n"); totp_cli_command_add_docopt_options(); totp_cli_command_delete_docopt_options(); + totp_cli_command_move_docopt_options(); } \ No newline at end of file diff --git a/applications/plugins/totp/services/cli/commands/move/move.c b/applications/plugins/totp/services/cli/commands/move/move.c new file mode 100644 index 000000000..9ed0a604a --- /dev/null +++ b/applications/plugins/totp/services/cli/commands/move/move.c @@ -0,0 +1,164 @@ +#include "move.h" + +#include +#include +#include "../../../list/list.h" +#include "../../../../types/token_info.h" +#include "../../../config/config.h" +#include "../../cli_helpers.h" +#include "../../../../scenes/scene_director.h" + +#define TOTP_CLI_COMMAND_MOVE_ARG_INDEX "index" + +#define TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME "name" +#define TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME_PREFIX "-n" + +#define TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX "index" +#define TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX "-i" + +void totp_cli_command_move_docopt_commands() { + TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_MOVE ", " TOTP_CLI_COMMAND_MOVE_ALT + " Move\\rename token\r\n"); +} + +void totp_cli_command_move_docopt_usage() { + TOTP_CLI_PRINTF( + " " TOTP_CLI_COMMAND_NAME + " " DOCOPT_REQUIRED(TOTP_CLI_COMMAND_MOVE " | " TOTP_CLI_COMMAND_MOVE_ALT) " " DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_INDEX) " " DOCOPT_OPTIONAL( + DOCOPT_OPTION( + TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME_PREFIX, + DOCOPT_ARGUMENT( + TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME))) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX))) "\r\n"); +} + +void totp_cli_command_move_docopt_options() { + TOTP_CLI_PRINTF(" " DOCOPT_OPTION( + TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME_PREFIX, + DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME)) " New token name.\r\n"); + TOTP_CLI_PRINTF(" " DOCOPT_OPTION( + TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX, + DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX)) " New token index.\r\n"); +} + +void totp_cli_command_move_handle(PluginState* plugin_state, FuriString* args, Cli* cli) { + int token_index; + if(!args_read_int_and_trim(args, &token_index)) { + TOTP_CLI_PRINT_INVALID_ARGUMENTS(); + return; + } + + if(!totp_cli_ensure_authenticated(plugin_state, cli)) { + return; + } + + if(token_index < 1 || token_index > plugin_state->tokens_count) { + TOTP_CLI_PRINT_INVALID_ARGUMENTS(); + return; + } + + FuriString* temp_str = furi_string_alloc(); + + char* new_token_name = NULL; + int new_token_index = 0; + + while(args_read_string_and_trim(args, temp_str)) { + bool parsed = false; + if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME_PREFIX) == 0) { + if(!args_read_string_and_trim(args, temp_str)) { + TOTP_CLI_PRINTF( + "Missed value for argument \"" TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME_PREFIX + "\"\r\n"); + } else { + if(new_token_name != NULL) { + free(new_token_name); + } + + new_token_name = malloc(furi_string_size(temp_str) + 1); + if(new_token_name == NULL) { + furi_string_free(temp_str); + return; + } + + strlcpy( + new_token_name, + furi_string_get_cstr(temp_str), + furi_string_size(temp_str) + 1); + parsed = true; + } + } else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX) == 0) { + if(!args_read_int_and_trim(args, &new_token_index)) { + TOTP_CLI_PRINTF( + "Missed value for argument \"" TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX + "\"\r\n"); + } else if(new_token_index < 1 || new_token_index > plugin_state->tokens_count) { + TOTP_CLI_PRINTF( + "\"%" PRId16 + "\" is incorrect value for argument \"" TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX + "\"\r\n", + new_token_index); + } else { + parsed = true; + } + } else { + TOTP_CLI_PRINTF("Unknown argument \"%s\"\r\n", furi_string_get_cstr(temp_str)); + } + + if(!parsed) { + TOTP_CLI_PRINT_INVALID_ARGUMENTS(); + furi_string_free(temp_str); + if(new_token_name != NULL) { + free(new_token_name); + } + return; + } + } + + if(!totp_cli_ensure_authenticated(plugin_state, cli)) { + furi_string_free(temp_str); + if(new_token_name != NULL) { + free(new_token_name); + } + return; + } + + bool activate_generate_token_scene = false; + if(plugin_state->current_scene != TotpSceneAuthentication) { + totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL); + activate_generate_token_scene = true; + } + + bool token_updated = false; + TokenInfo* token_info = NULL; + if(new_token_index > 0) { + plugin_state->tokens_list = + list_remove_at(plugin_state->tokens_list, token_index - 1, (void**)&token_info); + furi_check(token_info != NULL); + plugin_state->tokens_list = + list_insert_at(plugin_state->tokens_list, new_token_index - 1, token_info); + token_updated = true; + } else { + token_info = list_element_at(plugin_state->tokens_list, token_index - 1)->data; + } + + if(new_token_name != NULL) { + free(token_info->name); + token_info->name = new_token_name; + token_updated = true; + } + + if(token_updated) { + totp_full_save_config_file(plugin_state); + } + + if(activate_generate_token_scene) { + totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); + } + + if(token_updated) { + TOTP_CLI_PRINTF("Token \"%s\" has been successfully updated\r\n", token_info->name); + } else { + TOTP_CLI_PRINT_INVALID_ARGUMENTS(); + } + + furi_string_free(temp_str); +} \ No newline at end of file diff --git a/applications/plugins/totp/services/cli/commands/move/move.h b/applications/plugins/totp/services/cli/commands/move/move.h new file mode 100644 index 000000000..b06a71679 --- /dev/null +++ b/applications/plugins/totp/services/cli/commands/move/move.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include "../../../../types/plugin_state.h" + +#define TOTP_CLI_COMMAND_MOVE "move" +#define TOTP_CLI_COMMAND_MOVE_ALT "mv" + +void totp_cli_command_move_handle(PluginState* plugin_state, FuriString* args, Cli* cli); +void totp_cli_command_move_docopt_commands(); +void totp_cli_command_move_docopt_usage(); +void totp_cli_command_move_docopt_options(); \ No newline at end of file diff --git a/applications/plugins/totp/services/config/config.h b/applications/plugins/totp/services/config/config.h index d452ad4b3..cf433f9e5 100644 --- a/applications/plugins/totp/services/config/config.h +++ b/applications/plugins/totp/services/config/config.h @@ -6,18 +6,77 @@ #include "../../types/token_info.h" #include "constants.h" +/** + * @brief Token loading results + */ typedef enum { + /** + * @brief All the tokens loaded successfully + */ TokenLoadingResultSuccess, + + /** + * @brief All the tokens loaded, but there are some warnings + */ TokenLoadingResultWarning, + + /** + * @brief Tokens not loaded because of error(s) + */ TokenLoadingResultError } TokenLoadingResult; +/** + * @brief Opens storage record + * @return Storage record + */ Storage* totp_open_storage(); + +/** + * @brief Closes storage record + */ void totp_close_storage(); + +/** + * @brief Opens or creates TOTP application standard config file + * @param storage storage record to use + * @return Config file reference + */ FlipperFormat* totp_open_config_file(Storage* storage); + +/** + * @brief Closes config file + * @param file config file reference + */ void totp_close_config_file(FlipperFormat* file); + +/** + * @brief Saves all the settings and tokens to an application config file + * @param plugin_state application state + */ void totp_full_save_config_file(const PluginState* const plugin_state); + +/** + * @brief Loads basic information from an application config file into application state without loading all the tokens + * @param plugin_state application state + */ void totp_config_file_load_base(PluginState* const plugin_state); + +/** + * @brief Loads tokens from an application config file into application state + * @param plugin_state application state + * @return Results of the loading + */ TokenLoadingResult totp_config_file_load_tokens(PluginState* const plugin_state); + +/** + * @brief Add new token to the end of the application config file + * @param token_info token information to be saved + */ void totp_config_file_save_new_token(const TokenInfo* token_info); + +/** + * @brief Updates timezone offset in an application config file + * @param new_timezone_offset new timezone offset to be set + */ void totp_config_file_update_timezone_offset(float new_timezone_offset); diff --git a/applications/plugins/totp/services/crypto/crypto.h b/applications/plugins/totp/services/crypto/crypto.h index f0a28f798..d39fe013b 100644 --- a/applications/plugins/totp/services/crypto/crypto.h +++ b/applications/plugins/totp/services/crypto/crypto.h @@ -2,15 +2,45 @@ #include "../../types/plugin_state.h" +/** + * @brief Encrypts plain data using built-in certificate and given initialization vector (IV) + * @param plain_data plain data to be encrypted + * @param plain_data_length plain data length + * @param iv initialization vector (IV) to be used to encrypt plain data + * @param[out] encrypted_data_length encrypted data length + * @return Encrypted data + */ uint8_t* totp_crypto_encrypt( const uint8_t* plain_data, const size_t plain_data_length, const uint8_t* iv, size_t* encrypted_data_length); + +/** + * @brief Decrypts encrypted data using built-in certificate and given initialization vector (IV) + * @param encrypted_data encrypted data to be decrypted + * @param encrypted_data_length encrypted data length + * @param iv initialization vector (IV) to be used to encrypt plain data + * @param[out] decrypted_data_length decrypted data length + * @return Decrypted data + */ uint8_t* totp_crypto_decrypt( const uint8_t* encrypted_data, const size_t encrypted_data_length, const uint8_t* iv, size_t* decrypted_data_length); + +/** + * @brief Seed initialization vector (IV) using user's PIN + * @param plugin_state application state + * @param pin user's PIN + * @param pin_length user's PIN length + */ void totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length); + +/** + * @brief Verifies whether cryptographic information (certificate + IV) is valid and can be used for encryption and decryption + * @param plugin_state application state + * @return \c true if cryptographic information is valid; \c false otherwise + */ bool totp_crypto_verify_key(const PluginState* plugin_state); \ No newline at end of file diff --git a/applications/plugins/totp/services/crypto/memset_s.h b/applications/plugins/totp/services/crypto/memset_s.h index 060c6642b..54628860d 100644 --- a/applications/plugins/totp/services/crypto/memset_s.h +++ b/applications/plugins/totp/services/crypto/memset_s.h @@ -2,7 +2,6 @@ #include #include -#include #ifndef _RSIZE_T_DECLARED typedef uint64_t rsize_t; @@ -13,4 +12,12 @@ typedef int16_t errno_t; //-V677 #define _ERRNOT_DECLARED #endif +/** + * @brief Copies the value \p c into each of the first \p n characters of the object pointed to by \p s. + * @param s pointer to the object to fill + * @param smax size of the destination object + * @param c fill byte + * @param n number of bytes to fill + * @return \c 0 on success; non-zero otherwise + */ errno_t memset_s(void* s, rsize_t smax, int c, rsize_t n); \ No newline at end of file diff --git a/applications/plugins/totp/services/hid_worker/hid_worker.c b/applications/plugins/totp/services/hid_worker/hid_worker.c index f57a64eb1..538fdbe97 100644 --- a/applications/plugins/totp/services/hid_worker/hid_worker.c +++ b/applications/plugins/totp/services/hid_worker/hid_worker.c @@ -1,6 +1,6 @@ #include "hid_worker.h" -const uint8_t hid_number_keys[10] = { +static const uint8_t hid_number_keys[10] = { HID_KEYBOARD_0, HID_KEYBOARD_1, HID_KEYBOARD_2, @@ -19,6 +19,10 @@ static void totp_hid_worker_restore_usb_mode(TotpHidWorkerTypeContext* context) } } +static inline bool totp_hid_worker_stop_requested() { + return furi_thread_flags_get() & TotpHidWorkerEvtStop; +} + static void totp_hid_worker_type_code(TotpHidWorkerTypeContext* context) { context->usb_mode_prev = furi_hal_usb_get_config(); furi_hal_usb_unlock(); @@ -27,11 +31,11 @@ static void totp_hid_worker_type_code(TotpHidWorkerTypeContext* context) { do { furi_delay_ms(500); i++; - } while(!furi_hal_hid_is_connected() && i < 50); - furi_delay_ms(500); + } while(!furi_hal_hid_is_connected() && i < 100 && !totp_hid_worker_stop_requested()); if(furi_hal_hid_is_connected() && furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) { + furi_delay_ms(500); i = 0; while(i < context->string_length && context->string[i] != 0) { uint8_t digit = context->string[i] - '0'; @@ -91,7 +95,7 @@ TotpHidWorkerTypeContext* totp_hid_worker_start() { } void totp_hid_worker_stop(TotpHidWorkerTypeContext* context) { - furi_assert(context); + furi_assert(context != NULL); furi_thread_flags_set(furi_thread_get_id(context->thread), TotpHidWorkerEvtStop); furi_thread_join(context->thread); furi_thread_free(context->thread); @@ -101,6 +105,6 @@ void totp_hid_worker_stop(TotpHidWorkerTypeContext* context) { } void totp_hid_worker_notify(TotpHidWorkerTypeContext* context, TotpHidWorkerEvtFlags event) { - furi_assert(context); + furi_assert(context != NULL); furi_thread_flags_set(furi_thread_get_id(context->thread), event); } \ No newline at end of file diff --git a/applications/plugins/totp/services/hmac/byteswap.h b/applications/plugins/totp/services/hmac/byteswap.h index 411f3d5c4..2e3f1743f 100644 --- a/applications/plugins/totp/services/hmac/byteswap.h +++ b/applications/plugins/totp/services/hmac/byteswap.h @@ -2,5 +2,16 @@ #include +/** + * @brief Swap bytes in 32-bit value + * @param val value to swap bytes in + * @return Value with bytes swapped + */ uint32_t swap_uint32(uint32_t val); + +/** + * @brief Swap bytes in 64-bit value + * @param val value to swap bytes in + * @return Value with bytes swapped + */ uint64_t swap_uint64(uint64_t val); diff --git a/applications/plugins/totp/services/list/list.c b/applications/plugins/totp/services/list/list.c index bc7307fdb..f7abb6c8e 100644 --- a/applications/plugins/totp/services/list/list.c +++ b/applications/plugins/totp/services/list/list.c @@ -29,7 +29,7 @@ ListNode* list_add(ListNode* head, void* data) { } ListNode* list_find(ListNode* head, const void* data) { - ListNode* it; + ListNode* it = NULL; for(it = head; it != NULL; it = it->next) if(it->data == data) break; @@ -67,6 +67,63 @@ ListNode* list_remove(ListNode* head, ListNode* ep) { return head; } +ListNode* list_remove_at(ListNode* head, uint16_t index, void** removed_node_data) { + if(head == NULL) { + return NULL; + } + + ListNode* it; + ListNode* prev = NULL; + + uint16_t i; + + for(it = head, i = 0; it != NULL && i < index; prev = it, it = it->next, i++) + ; + + if(it == NULL) return head; + + ListNode* new_head = head; + if(prev == NULL) { + new_head = it->next; + } else { + prev->next = it->next; + } + + if(removed_node_data != NULL) { + *removed_node_data = it->data; + } + + free(it); + + return new_head; +} + +ListNode* list_insert_at(ListNode* head, uint16_t index, void* data) { + if(index == 0 || head == NULL) { + ListNode* new_head = list_init_head(data); + if(new_head != NULL) { + new_head->next = head; + } + return new_head; + } + + ListNode* it; + ListNode* prev = NULL; + + uint16_t i; + + for(it = head, i = 0; it != NULL && i < index; prev = it, it = it->next, i++) + ; + + ListNode* new = malloc(sizeof(ListNode)); + if(new == NULL) return NULL; + new->data = data; + new->next = it; + prev->next = new; + + return head; +} + void list_free(ListNode* head) { ListNode* it = head; ListNode* tmp; diff --git a/applications/plugins/totp/services/list/list.h b/applications/plugins/totp/services/list/list.h index 7721b2522..715c74901 100644 --- a/applications/plugins/totp/services/list/list.h +++ b/applications/plugins/totp/services/list/list.h @@ -3,25 +3,85 @@ #include #include +/** + * @brief Single linked list node + */ typedef struct ListNode { + /** + * @brief Pointer to the data assigned to the current list node + */ void* data; + + /** + * @brief Pointer to the next list node + */ struct ListNode* next; } ListNode; +/** + * @brief Initializes a new list node head + * @param data data to be assigned to the head list node + * @return Head list node + */ ListNode* list_init_head(void* data); + +/** + * @brief Adds new list node to the end of the list + * @param head head list node + * @param data data to be assigned to the newly added list node + * @return Head list node + */ ListNode* list_add( ListNode* head, void* data); /* adds element with specified data to the end of the list and returns new head node. */ -ListNode* list_find( - ListNode* head, - const void* data); /* returns pointer of element with specified data in list. */ -ListNode* list_element_at( - ListNode* head, - uint16_t index); /* returns pointer of element with specified index in list. */ -ListNode* list_remove( - ListNode* head, - ListNode* ep); /* removes element from the list and returns new head node. */ -void list_free(ListNode* head); /* deletes all elements of the list. */ + +/** + * @brief Searches list node with the given assigned \p data in the list + * @param head head list node + * @param data data to be searched + * @return List node containing \p data if there is such a node in the list; \c NULL otherwise + */ +ListNode* list_find(ListNode* head, const void* data); + +/** + * @brief Searches list node with the given \p index in the list + * @param head head list node + * @param index desired list node index + * @return List node with the given \p index in the list if there is such a list node; \c NULL otherwise + */ +ListNode* list_element_at(ListNode* head, uint16_t index); + +/** + * @brief Removes list node from the list + * @param head head list node + * @param ep list node to be removed + * @return Head list node + */ +ListNode* list_remove(ListNode* head, ListNode* ep); + +/** + * @brief Removes list node with the given \p index in the list from the list + * @param head head list node + * @param index index of the node to be removed + * @param[out] removed_node_data data which was assigned to the removed list node + * @return Head list node + */ +ListNode* list_remove_at(ListNode* head, uint16_t index, void** removed_node_data); + +/** + * @brief Inserts new list node at the given index + * @param head head list node + * @param index index in the list where the new list node should be inserted + * @param data data to be assgned to the new list node + * @return Head list node + */ +ListNode* list_insert_at(ListNode* head, uint16_t index, void* data); + +/** + * @brief Disposes all the list nodes in the list + * @param head head list node + */ +void list_free(ListNode* head); #define TOTP_LIST_INIT_OR_ADD(head, item, assert) \ do { \ diff --git a/applications/plugins/totp/services/roll_value/roll_value.h b/applications/plugins/totp/services/roll_value/roll_value.h index 87337597f..bb8360c96 100644 --- a/applications/plugins/totp/services/roll_value/roll_value.h +++ b/applications/plugins/totp/services/roll_value/roll_value.h @@ -2,7 +2,17 @@ #include -typedef enum { RollOverflowBehaviorStop, RollOverflowBehaviorRoll } TotpRollValueOverflowBehavior; +typedef enum { + /** + * @brief Do not change value if it reached constraint + */ + RollOverflowBehaviorStop, + + /** + * @brief Set value to opposite constraint value if it reached constraint + */ + RollOverflowBehaviorRoll +} TotpRollValueOverflowBehavior; #define TOTP_ROLL_VALUE_FN_HEADER(type, step_type) \ void totp_roll_value_##type( \ @@ -12,6 +22,35 @@ typedef enum { RollOverflowBehaviorStop, RollOverflowBehaviorRoll } TotpRollValu type max, \ TotpRollValueOverflowBehavior overflow_behavior) +/** + * @brief Rolls \c int8_t \p value using \p min and \p max as an value constraints with \p step step. + * When value reaches constraint value \p overflow_behavior defines what to do next. + * @param[in,out] value value to roll + * @param step step to be used to change value + * @param min minimal possible value + * @param max maximum possible value + * @param overflow_behavior defines what to do when value reaches constraint value + */ TOTP_ROLL_VALUE_FN_HEADER(int8_t, int8_t); + +/** + * @brief Rolls \c uint8_t \p value using \p min and \p max as an value constraints with \p step step. + * When value reaches constraint value \p overflow_behavior defines what to do next. + * @param[in,out] value value to roll + * @param step step to be used to change value + * @param min minimal possible value + * @param max maximum possible value + * @param overflow_behavior defines what to do when value reaches constraint value + */ TOTP_ROLL_VALUE_FN_HEADER(uint8_t, int8_t); + +/** + * @brief Rolls \c uint16_t \p value using \p min and \p max as an value constraints with \p step step. + * When value reaches constraint value \p overflow_behavior defines what to do next. + * @param[in,out] value value to roll + * @param step step to be used to change value + * @param min minimal possible value + * @param max maximum possible value + * @param overflow_behavior defines what to do when value reaches constraint value + */ TOTP_ROLL_VALUE_FN_HEADER(uint16_t, int16_t); \ No newline at end of file diff --git a/applications/plugins/totp/services/timezone_utils/timezone_utils.h b/applications/plugins/totp/services/timezone_utils/timezone_utils.h index 0ae829d74..5bb3b8ead 100644 --- a/applications/plugins/totp/services/timezone_utils/timezone_utils.h +++ b/applications/plugins/totp/services/timezone_utils/timezone_utils.h @@ -2,5 +2,17 @@ #include +/** + * @brief Calculates timezone offset in seconds given timezone offset in hours. + * @param hours timezone offset in hours + * @return Timezone offset in seconds. + */ int32_t timezone_offset_from_hours(float hours); + +/** + * @brief Applies timezone offset to a given time. + * @param time time to apply offset to. + * @param offset timezone offset in seconds. + * @return Time with timezone offset applied. + */ uint64_t timezone_offset_apply(uint64_t time, int32_t offset); diff --git a/applications/plugins/totp/services/totp/totp.c b/applications/plugins/totp/services/totp/totp.c index 9e0672ea9..0816d1812 100644 --- a/applications/plugins/totp/services/totp/totp.c +++ b/applications/plugins/totp/services/totp/totp.c @@ -11,48 +11,43 @@ #include "../hmac/byteswap.h" #include "../timezone_utils/timezone_utils.h" -/* - Generates the timeblock for a time in seconds. - - Timeblocks are the amount of intervals in a given time. For example, - if 1,000,000 seconds has passed for 30 second intervals, you would get - 33,333 timeblocks (intervals), where timeblock++ is effectively +30 seconds. - - for_time is a time in seconds to get the current timeblocks - - Returns - timeblock given for_time, using data->interval - error, 0 -*/ +#define HMAC_MAX_SIZE 64 + +/** + * @brief Generates the timeblock for a time in seconds. + * Timeblocks are the amount of intervals in a given time. For example, + * if 1,000,000 seconds has passed for 30 second intervals, you would get + * 33,333 timeblocks (intervals), where timeblock++ is effectively +30 seconds. + * @param interval in seconds + * @param for_time a time in seconds to get the current timeblocks + * @return Timeblock given \p for_time using \p interval + */ uint64_t totp_timecode(uint8_t interval, uint64_t for_time) { return for_time / interval; } -/* - Generates an OTP (One Time Password). - - input is a number used to generate the OTP - out_str is the null-terminated output string already allocated - - Returns - OTP code if otp code was successfully generated - 0 otherwise -*/ +/** + * @brief Generates an OTP (One Time Password) + * @param algo hashing algorithm to be used + * @param digits desired TOTP code length + * @param plain_secret plain token secret + * @param plain_secret_length plain token secret length + * @param input input data for OTP code generation + * @return OTP code if code was successfully generated; 0 otherwise + */ uint32_t otp_generate( TOTP_ALGO algo, uint8_t digits, const uint8_t* plain_secret, size_t plain_secret_length, uint64_t input) { - uint8_t* hmac = malloc(64); - if(hmac == NULL) return OTP_ERROR; - memset(hmac, 0, 64); + uint8_t hmac[HMAC_MAX_SIZE] = {0}; uint64_t input_swapped = swap_uint64(input); - int hmac_len = (*algo)(plain_secret, plain_secret_length, (uint8_t*)&input_swapped, 8, hmac); + int hmac_len = + (*algo)(plain_secret, plain_secret_length, (uint8_t*)&input_swapped, 8, &hmac[0]); if(hmac_len == 0) { - free(hmac); return OTP_ERROR; } @@ -62,21 +57,9 @@ uint32_t otp_generate( (hmac[offset + 2] & 0xFF) << 8 | (hmac[offset + 3] & 0xFF)); i_code %= (uint64_t)pow(10, digits); - free(hmac); return i_code; } -/* - Generates a OTP key using the totp algorithm. - - for_time is the time the generated key will be created for - offset is a timeblock adjustment for the generated key - out_str is the null-terminated output string already allocated - - Returns - TOTP code if otp code was successfully generated - 0 otherwise -*/ uint32_t totp_at( TOTP_ALGO algo, uint8_t digits, diff --git a/applications/plugins/totp/services/totp/totp.h b/applications/plugins/totp/services/totp/totp.h index 431ca11aa..3f45a0223 100644 --- a/applications/plugins/totp/services/totp/totp.h +++ b/applications/plugins/totp/services/totp/totp.h @@ -5,16 +5,15 @@ #define OTP_ERROR (0) -/* - Must compute HMAC using passed arguments, - output as char array through output. - - key is secret key. - input is input number. - output is an output buffer of the resulting HMAC operation. - - Must return 0 if error, or the length in bytes of the HMAC operation. -*/ +/** + * @brief Must compute HMAC using passed arguments, output as char array through output. + * \p key is secret key buffer. + * \p key_length is secret key buffer length. + * \p input is input buffer. + * \p input_length is input buffer length. + * \p output is an output buffer of the resulting HMAC operation. + * Must return 0 if error, or the length in bytes of the HMAC operation. + */ typedef int (*TOTP_ALGO)( const uint8_t* key, size_t key_length, @@ -22,27 +21,32 @@ typedef int (*TOTP_ALGO)( size_t input_length, uint8_t* output); -/* - Computes HMAC using SHA1 -*/ +/** + * @brief Computes HMAC using SHA1 + */ extern const TOTP_ALGO TOTP_ALGO_SHA1; -/* - Computes HMAC using SHA256 -*/ +/** + * @brief Computes HMAC using SHA256 + */ extern const TOTP_ALGO TOTP_ALGO_SHA256; -/* - Computes HMAC using SHA512 -*/ +/** + * @brief Computes HMAC using SHA512 + */ extern const TOTP_ALGO TOTP_ALGO_SHA512; -/* - Computes TOTP token - Returns: - TOTP token on success - 0 otherwise -*/ +/** + * @brief Generates a OTP key using the totp algorithm. + * @param algo hashing algorithm to be used + * @param digits desired TOTP code length + * @param plain_secret plain token secret + * @param plain_secret_length plain token secret length + * @param for_time the time the generated key will be created for + * @param timezone UTC timezone adjustment for the generated key + * @param interval token lifetime in seconds + * @return TOTP code if code was successfully generated; 0 otherwise + */ uint32_t totp_at( TOTP_ALGO algo, uint8_t digits, diff --git a/applications/plugins/totp/services/ui/ui_controls.h b/applications/plugins/totp/services/ui/ui_controls.h index ef3af5f55..b97006a03 100644 --- a/applications/plugins/totp/services/ui/ui_controls.h +++ b/applications/plugins/totp/services/ui/ui_controls.h @@ -3,11 +3,29 @@ #include #include +/** + * @brief Renders TextBox control + * @param canvas canvas to render control at + * @param y vertical position of a control to be rendered at + * @param text text to be rendered inside control + * @param is_selected whether control should be rendered as focused or not + */ void ui_control_text_box_render( Canvas* const canvas, int16_t y, const char* text, bool is_selected); + +/** + * @brief Renders Button control + * @param canvas canvas to render control at + * @param x horizontal position of a control to be rendered at + * @param y vertical position of a control to be rendered at + * @param width control width + * @param height control height + * @param text text to be rendered inside control + * @param is_selected whether control should be rendered as focused or not + */ void ui_control_button_render( Canvas* const canvas, int16_t x, @@ -16,6 +34,16 @@ void ui_control_button_render( uint8_t height, const char* text, bool is_selected); + +/** + * @brief Renders Select control + * @param canvas canvas to render control at + * @param x horizontal position of a control to be rendered at + * @param y vertical position of a control to be rendered at + * @param width control width + * @param text text to be rendered inside control + * @param is_selected whether control should be rendered as focused or not + */ void ui_control_select_render( Canvas* const canvas, int16_t x, diff --git a/applications/plugins/totp/types/plugin_state.h b/applications/plugins/totp/types/plugin_state.h index 9b16d7d57..637f9916f 100644 --- a/applications/plugins/totp/types/plugin_state.h +++ b/applications/plugins/totp/types/plugin_state.h @@ -8,22 +8,82 @@ #define TOTP_IV_SIZE 16 +/** + * @brief Application state structure + */ typedef struct { + /** + * @brief Application current scene + */ Scene current_scene; + + /** + * @brief Application current scene state + */ void* current_scene_state; + + /** + * @brief Whether scene is changing now + */ bool changing_scene; + + /** + * @brief Reference to the firmware notification subsystem + */ NotificationApp* notification; + + /** + * @brief Reference to the firmware dialogs subsystem + */ DialogsApp* dialogs; + + /** + * @brief Reference to the firmware GUI subsystem + */ Gui* gui; + /** + * @brief Timezone UTC offset in hours + */ float timezone_offset; + + /** + * @brief Token list head node + */ ListNode* tokens_list; + + /** + * @brief Whether token list is loaded or not + */ bool token_list_loaded; + + /** + * @brief Tokens list length + */ uint16_t tokens_count; + /** + * @brief Encrypted well-known string data + */ uint8_t* crypto_verify_data; + + /** + * @brief Encrypted well-known string data length + */ size_t crypto_verify_data_length; + + /** + * @brief Whether PIN is set by user or not + */ bool pin_set; + + /** + * @brief Initialization vector (IV) to be used for encryption\decryption + */ uint8_t iv[TOTP_IV_SIZE]; + + /** + * @brief Basic randomly-generated initialization vector (IV) + */ uint8_t base_iv[TOTP_IV_SIZE]; } PluginState; diff --git a/applications/plugins/totp/types/token_info.h b/applications/plugins/totp/types/token_info.h index 6c55e095f..cbcf0ddef 100644 --- a/applications/plugins/totp/types/token_info.h +++ b/applications/plugins/totp/types/token_info.h @@ -2,25 +2,102 @@ #include -typedef enum { SHA1, SHA256, SHA512 } TokenHashAlgo; +/** + * @brief Hashing algorithm to be used to generate token + */ +typedef enum { + /** + * @brief SHA1 hashing algorithm + */ + SHA1, -typedef enum { TOTP_6_DIGITS, TOTP_8_DIGITS } TokenDigitsCount; + /** + * @brief SHA256 hashing algorithm + */ + SHA256, + + /** + * @brief SHA512 hashing algorithm + */ + SHA512 +} TokenHashAlgo; + +/** + * @brief Token digits count to be generated. + */ +typedef enum { + /** + * @brief 6 digits + */ + TOTP_6_DIGITS, + + /** + * @brief 8 digits + */ + TOTP_8_DIGITS +} TokenDigitsCount; #define TOTP_TOKEN_DIGITS_MAX_COUNT 8 +/** + * @brief TOTP token information + */ typedef struct { + /** + * @brief Encrypted token secret + */ uint8_t* token; + + /** + * @brief Encrypted token secret length + */ size_t token_length; + + /** + * @brief User-friendly token name + */ char* name; + + /** + * @brief Hashing algorithm + */ TokenHashAlgo algo; + + /** + * @brief Desired TOTP token length + */ TokenDigitsCount digits; } TokenInfo; +/** + * @brief Allocates a new instance of \c TokenInfo + * @return + */ TokenInfo* token_info_alloc(); + +/** + * @brief Disposes all the resources allocated by the given \c TokenInfo instance + * @param token_info instance to be disposed + */ void token_info_free(TokenInfo* token_info); + +/** + * @brief Encrypts & sets plain token secret to the given instance of \c TokenInfo + * @param token_info instance where secret should be updated + * @param base32_token_secret plain token secret in Base32 format + * @param token_secret_length plain token secret length + * @param iv initialization vecor (IV) to be used for encryption + * @return \c true if token successfully set; \c false otherwise + */ bool token_info_set_secret( TokenInfo* token_info, const char* base32_token_secret, size_t token_secret_length, const uint8_t* iv); + +/** + * @brief Gets token digits count as \c uint8_t type + * @param token_info instance which's desired digits count should be returned + * @return Token digits length as \c uint8_t type + */ uint8_t token_info_get_digits_count(const TokenInfo* token_info); From a6886b096ee91d9e711f39fe495d2326ca432c3c Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 17 Nov 2022 22:35:13 +0300 Subject: [PATCH 4/9] Update DTMF Dolphin https://github.com/litui/dtmf_dolphin --- .../plugins/dtmf_dolphin/dtmf_dolphin_data.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/applications/plugins/dtmf_dolphin/dtmf_dolphin_data.c b/applications/plugins/dtmf_dolphin/dtmf_dolphin_data.c index 1c2e1ce98..72386b83d 100644 --- a/applications/plugins/dtmf_dolphin/dtmf_dolphin_data.c +++ b/applications/plugins/dtmf_dolphin/dtmf_dolphin_data.c @@ -77,6 +77,16 @@ DTMFDolphinSceneData DTMFDolphinSceneDataRedboxUS = { {"Dollar", 1700.0, 2200.0, {3, 0, 5}, 1, 650, 0}, }}; +DTMFDolphinSceneData DTMFDolphinSceneDataRedboxCA = { + .name = "Redbox (CA)", + .block = DTMF_DOLPHIN_TONE_BLOCK_REDBOX_CA, + .tone_count = 3, + .tones = { + {"Nickel", 2200.0, 0.0, {0, 0, 5}, 1, 66, 0}, + {"Dime", 2200.0, 0.0, {1, 0, 5}, 2, 66, 66}, + {"Quarter", 2200.0, 0.0, {2, 0, 5}, 5, 33, 33}, + }}; + DTMFDolphinSceneData DTMFDolphinSceneDataRedboxUK = { .name = "Redbox (UK)", .block = DTMF_DOLPHIN_TONE_BLOCK_REDBOX_UK, @@ -109,6 +119,9 @@ void dtmf_dolphin_data_set_current_section(DTMFDolphinToneSection section) { case DTMF_DOLPHIN_TONE_BLOCK_REDBOX_US: current_scene_data = &DTMFDolphinSceneDataRedboxUS; break; + case DTMF_DOLPHIN_TONE_BLOCK_REDBOX_CA: + current_scene_data = &DTMFDolphinSceneDataRedboxCA; + break; case DTMF_DOLPHIN_TONE_BLOCK_REDBOX_UK: current_scene_data = &DTMFDolphinSceneDataRedboxUK; break; @@ -204,4 +217,4 @@ uint8_t dtmf_dolphin_get_tone_span(uint8_t row, uint8_t col) { } } return 0; -} \ No newline at end of file +} From 7e8bf03b25e0cd42e71811552b5a48d73b9c476b Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 17 Nov 2022 22:43:04 +0300 Subject: [PATCH 5/9] Fix DTMF Dolphin Add forgotten scene and menu item @litui check this commit --- applications/plugins/dtmf_dolphin/dtmf_dolphin_data.h | 1 + applications/plugins/dtmf_dolphin/dtmf_dolphin_event.h | 1 + applications/plugins/dtmf_dolphin/dtmf_dolphin_i.h | 1 + .../dtmf_dolphin/scenes/dtmf_dolphin_scene_dialer.c | 3 +++ .../plugins/dtmf_dolphin/scenes/dtmf_dolphin_scene_start.c | 7 +++++++ 5 files changed, 13 insertions(+) diff --git a/applications/plugins/dtmf_dolphin/dtmf_dolphin_data.h b/applications/plugins/dtmf_dolphin/dtmf_dolphin_data.h index 13350b14c..56ceaf03d 100644 --- a/applications/plugins/dtmf_dolphin/dtmf_dolphin_data.h +++ b/applications/plugins/dtmf_dolphin/dtmf_dolphin_data.h @@ -10,6 +10,7 @@ typedef enum { DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX, DTMF_DOLPHIN_TONE_BLOCK_REDBOX_US, DTMF_DOLPHIN_TONE_BLOCK_REDBOX_UK, + DTMF_DOLPHIN_TONE_BLOCK_REDBOX_CA, DTMF_DOLPHIN_TONE_BLOCK_MISC, } DTMFDolphinToneSection; diff --git a/applications/plugins/dtmf_dolphin/dtmf_dolphin_event.h b/applications/plugins/dtmf_dolphin/dtmf_dolphin_event.h index 75f5bb274..525d0eb04 100644 --- a/applications/plugins/dtmf_dolphin/dtmf_dolphin_event.h +++ b/applications/plugins/dtmf_dolphin/dtmf_dolphin_event.h @@ -8,6 +8,7 @@ typedef enum { DTMFDolphinEventStartBluebox, DTMFDolphinEventStartRedboxUS, DTMFDolphinEventStartRedboxUK, + DTMFDolphinEventStartRedboxCA, DTMFDolphinEventStartMisc, DTMFDolphinEventPlayTones, DTMFDolphinEventStopTones, diff --git a/applications/plugins/dtmf_dolphin/dtmf_dolphin_i.h b/applications/plugins/dtmf_dolphin/dtmf_dolphin_i.h index abdabd2b3..f8ae1530f 100644 --- a/applications/plugins/dtmf_dolphin/dtmf_dolphin_i.h +++ b/applications/plugins/dtmf_dolphin/dtmf_dolphin_i.h @@ -22,6 +22,7 @@ enum DTMFDolphinSceneState { DTMFDolphinSceneStateBluebox, DTMFDolphinSceneStateRedboxUS, DTMFDolphinSceneStateRedboxUK, + DTMFDolphinSceneStateRedboxCA, DTMFDolphinSceneStateMisc, }; diff --git a/applications/plugins/dtmf_dolphin/scenes/dtmf_dolphin_scene_dialer.c b/applications/plugins/dtmf_dolphin/scenes/dtmf_dolphin_scene_dialer.c index 9820f5c9a..06da595e0 100644 --- a/applications/plugins/dtmf_dolphin/scenes/dtmf_dolphin_scene_dialer.c +++ b/applications/plugins/dtmf_dolphin/scenes/dtmf_dolphin_scene_dialer.c @@ -17,6 +17,9 @@ void dtmf_dolphin_scene_dialer_on_enter(void* context) { case DTMFDolphinSceneStateRedboxUK: dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_REDBOX_UK); break; + case DTMFDolphinSceneStateRedboxCA: + dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_REDBOX_CA); + break; case DTMFDolphinSceneStateMisc: dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_MISC); break; diff --git a/applications/plugins/dtmf_dolphin/scenes/dtmf_dolphin_scene_start.c b/applications/plugins/dtmf_dolphin/scenes/dtmf_dolphin_scene_start.c index 65cacf5c6..484e9e8eb 100644 --- a/applications/plugins/dtmf_dolphin/scenes/dtmf_dolphin_scene_start.c +++ b/applications/plugins/dtmf_dolphin/scenes/dtmf_dolphin_scene_start.c @@ -17,6 +17,9 @@ static void dtmf_dolphin_scene_start_main_menu_enter_callback(void* context, uin cust_event = DTMFDolphinEventStartRedboxUK; break; case 4: + cust_event = DTMFDolphinEventStartRedboxCA; + break; + case 5: cust_event = DTMFDolphinEventStartMisc; break; default: @@ -38,6 +41,7 @@ void dtmf_dolphin_scene_start_on_enter(void* context) { variable_item_list_add(var_item_list, "Bluebox", 0, NULL, context); variable_item_list_add(var_item_list, "Redbox (US)", 0, NULL, context); variable_item_list_add(var_item_list, "Redbox (UK)", 0, NULL, context); + variable_item_list_add(var_item_list, "Redbox (CA)", 0, NULL, context); variable_item_list_add(var_item_list, "Misc", 0, NULL, context); variable_item_list_set_selected_item( @@ -67,6 +71,9 @@ bool dtmf_dolphin_scene_start_on_event(void* context, SceneManagerEvent event) { case DTMFDolphinEventStartRedboxUK: sc_state = DTMFDolphinSceneStateRedboxUK; break; + case DTMFDolphinEventStartRedboxCA: + sc_state = DTMFDolphinSceneStateRedboxCA; + break; case DTMFDolphinEventStartMisc: sc_state = DTMFDolphinSceneStateMisc; break; From 0adcaf75927293272b9b597788ea456fcb054b5d Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 18 Nov 2022 00:31:49 +0300 Subject: [PATCH 6/9] Update infrared assets by @Amec0e --- assets/resources/infrared/assets/ac.ir | 26 +++++++- assets/resources/infrared/assets/audio.ir | 40 +++++++++++- assets/resources/infrared/assets/fans.ir | 33 +++++++++- assets/resources/infrared/assets/tv.ir | 74 ++++++++++++++++++++++- 4 files changed, 169 insertions(+), 4 deletions(-) diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index 3fca38e91..8f1d8dad7 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -1,6 +1,30 @@ Filetype: IR library file Version: 1 -# Last Updated 30th Oct, 2022 +# Last Updated 14th Nov, 2022 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3480 1701 468 1248 467 1250 465 407 460 411 467 405 462 1255 460 412 466 405 462 1255 460 1257 468 404 463 1253 462 410 468 404 463 1253 462 1255 470 402 465 1252 463 1254 461 411 467 405 462 1254 461 411 467 405 462 1254 461 411 467 405 462 409 469 403 464 407 460 411 467 405 462 409 469 403 464 407 461 411 467 405 462 409 469 403 464 407 460 411 467 404 463 1254 461 410 468 404 463 1254 461 410 468 404 463 408 460 412 466 406 462 1255 460 412 466 406 461 410 468 404 463 1253 462 1255 470 1247 468 404 463 409 469 402 465 406 461 411 467 1250 465 407 460 1256 469 1248 467 1250 465 1252 463 410 468 403 464 408 460 412 466 406 461 410 468 404 463 408 460 412 466 406 461 410 468 404 463 408 459 412 466 405 462 409 469 403 464 407 460 411 467 405 462 409 469 403 464 407 460 411 467 405 462 409 469 402 465 407 460 411 467 404 463 1253 462 1255 470 402 465 406 461 1256 469 402 465 1252 463 408 470 1248 467 1250 465 407 460 1256 469 +# +name: TEMP+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3477 1704 465 1251 463 1254 460 411 467 405 462 410 468 1249 465 406 461 410 468 1249 465 1252 462 409 469 1248 466 406 461 410 468 1249 465 1252 462 409 469 1248 466 1251 463 408 470 402 465 1252 462 409 469 403 464 1253 461 410 468 404 463 408 470 402 465 407 460 411 467 405 462 409 469 403 464 407 460 412 466 405 462 410 468 404 463 408 459 412 465 406 461 1255 470 402 465 407 460 1256 469 403 464 407 460 411 467 405 462 410 468 1249 465 406 461 410 468 404 463 408 470 1248 466 1250 464 1252 462 410 468 1249 465 407 460 411 467 405 462 1255 459 412 466 1251 463 1254 460 1256 469 1248 466 406 461 410 468 404 463 409 469 403 464 407 460 411 467 405 462 409 469 403 464 407 460 412 466 405 462 410 468 404 463 408 459 412 466 406 461 410 468 404 463 408 470 402 465 406 461 411 467 404 463 409 469 402 465 407 460 411 467 405 462 1254 460 1256 469 403 464 407 460 1257 468 404 463 1254 460 411 467 405 462 409 469 1249 465 1251 463 +# +name: TEMP- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3477 1703 466 1251 463 1253 461 411 467 404 463 409 469 1248 466 405 462 409 469 1249 465 1251 463 408 470 1248 466 405 462 409 469 1248 466 1251 463 408 459 1258 467 1250 464 407 460 411 467 1251 463 408 459 412 466 1251 463 408 470 402 465 406 461 411 467 405 462 409 469 403 464 407 460 411 467 405 462 409 469 403 464 407 460 411 467 405 462 409 469 403 464 1252 462 409 469 403 464 1253 461 410 468 404 463 408 470 402 465 407 460 1256 469 402 465 407 460 411 467 405 462 1254 460 1257 468 1249 465 406 461 411 467 1250 464 407 460 412 466 1251 463 408 470 1247 467 1250 464 1252 462 1255 470 402 465 406 461 411 467 405 462 409 469 403 464 407 460 411 467 405 462 409 469 403 464 408 459 412 466 406 461 410 468 404 463 408 459 412 466 406 461 410 468 404 463 408 470 402 465 406 461 410 468 404 463 409 469 402 465 407 460 411 467 1250 464 1252 462 409 469 403 464 1253 461 410 468 1250 464 407 460 1256 469 403 464 1253 461 1256 469 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3484 1696 462 1254 460 1257 468 404 463 408 470 402 465 1252 462 410 468 404 463 1253 461 1256 469 403 464 1253 461 410 468 404 463 1254 460 1257 468 403 464 1253 461 1256 469 403 464 407 460 1257 468 404 463 408 470 1248 466 405 462 409 469 403 464 408 459 412 466 406 461 410 468 404 463 409 469 403 464 407 460 411 467 405 462 410 468 404 463 408 459 412 465 1251 463 408 470 402 465 1252 462 409 469 403 464 1253 461 1256 469 403 464 407 460 411 466 406 461 410 468 404 463 409 469 1248 466 405 462 1254 460 412 465 406 461 410 468 404 463 1254 460 411 467 1250 464 1253 461 1256 469 1248 466 405 462 410 468 404 463 409 469 403 464 407 460 411 467 405 462 410 468 403 464 408 459 412 466 406 461 410 468 404 463 408 459 412 466 406 461 411 467 405 462 409 469 403 464 407 460 411 466 405 462 410 468 404 463 408 459 412 466 406 461 1255 470 1247 467 405 462 409 469 1249 465 1251 463 409 469 402 465 1252 462 1255 470 402 465 1252 462 # # POWER_ON name: POWER diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index 9e2edf7ea..d37627982 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1,6 +1,37 @@ Filetype: IR library file Version: 1 -# Last Updated 20th Oct, 2022 +# Last Updated 14th Nov, 2022 +# +name: VOL+ +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 14 00 00 00 +# +name: VOL- +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 10 00 00 00 +# +# ON +name: POWER +type: parsed +protocol: RC5 +address: 10 00 00 00 +command: 0E 00 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 0C F3 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 09 F6 00 00 # name: POWER type: raw @@ -1568,3 +1599,10 @@ protocol: NECext address: 12 36 00 00 command: 01 FE 00 00 # +# OFF +name: POWER +type: parsed +protocol: RC5 +address: 10 00 00 00 +command: 0F 00 00 00 +# diff --git a/assets/resources/infrared/assets/fans.ir b/assets/resources/infrared/assets/fans.ir index d0e6884f0..d7582f8a8 100644 --- a/assets/resources/infrared/assets/fans.ir +++ b/assets/resources/infrared/assets/fans.ir @@ -1,6 +1,37 @@ Filetype: IR library file Version: 1 -# Last Updated 30th Oct, 2022 +# Last Updated 14th Nov, 2022 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2262 692 881 585 883 583 903 564 903 1294 882 584 881 584 882 559 820 673 895 1300 882 611 881 584 882 584 882 584 882 585 881 584 881 584 882 585 880 1317 879 586 829 1371 827 640 825 51208 2245 690 772 1424 831 50893 2240 691 772 1429 771 50906 2244 690 773 1400 772 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2264 668 770 721 745 694 772 694 796 1401 826 639 771 694 771 693 772 694 771 1426 798 668 769 1429 795 670 795 1404 794 672 794 1405 767 1431 767 1430 794 672 794 1404 794 1404 794 1404 766 50878 2261 645 817 1405 794 50857 2238 668 795 1428 769 +# +name: SPEED- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2264 642 823 669 797 643 822 644 822 1376 822 642 799 668 797 669 823 645 820 1401 796 670 794 1379 792 700 793 1381 790 1407 793 674 791 700 793 1406 792 673 793 673 792 673 793 673 792 50785 2262 666 796 1401 797 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2323 611 796 669 800 664 802 692 773 1424 774 691 801 664 774 691 774 692 773 1423 800 668 822 667 798 1376 769 1427 771 696 769 696 770 1429 795 1404 794 672 794 1404 794 671 795 1404 794 51269 2214 691 769 1427 796 +# +# ON/SPEED +name: POWER +type: parsed +protocol: NECext +address: 00 FC 00 00 +command: 84 7B 00 00 # name: POWER type: raw diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index 07188e626..b97b85bb6 100755 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -1,6 +1,78 @@ Filetype: IR library file Version: 1 -# Last Updated 15th Oct, 2022 +# Last Updated 14th Nov, 2022 +# +name: MUTE +type: parsed +protocol: NECext +address: 00 FB 00 00 +command: 0F F0 00 00 +# +name: POWER +type: parsed +protocol: NECext +address: 00 FB 00 00 +command: 0A F5 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: 00 FB 00 00 +command: 58 A7 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 00 FB 00 00 +command: 4B B4 00 00 +# +name: CH+ +type: parsed +protocol: NECext +address: 00 FB 00 00 +command: 1F E0 00 00 +# +name: CH- +type: parsed +protocol: NECext +address: 00 FB 00 00 +command: 1E E1 00 00 +# +name: POWER +type: parsed +protocol: NECext +address: 00 DF 00 00 +command: 1C E3 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: 00 DF 00 00 +command: 4B B4 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 00 DF 00 00 +command: 4F B0 00 00 +# +name: MUTE +type: parsed +protocol: NECext +address: 00 DF 00 00 +command: 08 F7 00 00 +# +name: CH+ +type: parsed +protocol: NECext +address: 00 DF 00 00 +command: 09 F6 00 00 +# +name: CH- +type: parsed +protocol: NECext +address: 00 DF 00 00 +command: 05 FA 00 00 # name: POWER type: raw From 8bbfadffe536eca661fcd1805f08259d50ceb8ff Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 22 Nov 2022 16:37:54 +0300 Subject: [PATCH 7/9] Remove not widely used frequency from hopper --- assets/resources/subghz/assets/setting_user | 1 - 1 file changed, 1 deletion(-) diff --git a/assets/resources/subghz/assets/setting_user b/assets/resources/subghz/assets/setting_user index 420977603..4f5dae64c 100644 --- a/assets/resources/subghz/assets/setting_user +++ b/assets/resources/subghz/assets/setting_user @@ -63,7 +63,6 @@ Frequency: 928000000 # Frequencies used for hopping mode (keep this list small or flipper will miss signal) - they added after default ones if enabled in Add_standard_frequencies Hopper_frequency: 310000000 Hopper_frequency: 315000000 -Hopper_frequency: 318000000 Hopper_frequency: 390000000 Hopper_frequency: 433920000 Hopper_frequency: 434420000 From 3da1c229bb5c6ab422dde37f7a70a2fd5b29a5c7 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 23 Nov 2022 17:56:51 +0300 Subject: [PATCH 8/9] CI/CD Improvements, dev builds --- .drone.yml | 187 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 165 insertions(+), 22 deletions(-) diff --git a/.drone.yml b/.drone.yml index 02d7e4662..11b49e3cb 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,6 +1,6 @@ kind: pipeline type: docker -name: "Build firmware" +name: "Release firmware" steps: - name: "Update submodules" @@ -11,19 +11,19 @@ steps: - git submodule foreach git config --local gc.auto 0 - git log -1 --format='%H' - - name: "Build default FW" + - name: "Build firmware" image: hfdj/fztools pull: never commands: - export DIST_SUFFIX=${DRONE_TAG} - - export WORKFLOW_BRANCH_OR_TAG=dev-cfw + - export WORKFLOW_BRANCH_OR_TAG=release-cfw - ./fbt COMPACT=1 DEBUG=0 updater_package - mkdir artifacts-default - mv dist/f7-C/* artifacts-default/ - ls -laS artifacts-default - ls -laS artifacts-default/f7-update-${DRONE_TAG} - sed -i 's/(version)/'${DRONE_TAG}'/g' CHANGELOG.md - - echo '# [Install via Web Updater](https://lab.flipper.net/?url=https://unleashedflip.com/builds/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=dev-cfw&version='${DRONE_TAG}')' >> CHANGELOG.md + - echo '# [Install via Web Updater](https://lab.flipper.net/?url=https://unleashedflip.com/fw/${DRONE_TAG}/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')' >> CHANGELOG.md environment: FBT_TOOLS_CUSTOM_LINK: from_secret: fbt_link @@ -34,15 +34,15 @@ steps: commands: - rm -f assets/dolphin/external/manifest.txt - cp .ci_files/anims_ofw.txt assets/dolphin/external/manifest.txt - - export DIST_SUFFIX=${DRONE_TAG} - - export WORKFLOW_BRANCH_OR_TAG=dev-cfw + - export DIST_SUFFIX=${DRONE_TAG}n + - export WORKFLOW_BRANCH_OR_TAG=no-custom-anims - ./fbt COMPACT=1 DEBUG=0 updater_package - mkdir artifacts-ofw-anims - mv dist/f7-C/* artifacts-ofw-anims/ - ls -laS artifacts-ofw-anims - - ls -laS artifacts-ofw-anims/f7-update-${DRONE_TAG} + - ls -laS artifacts-ofw-anims/f7-update-${DRONE_TAG}n - echo '' >> CHANGELOG.md - - echo '### [Version without custom animations - Install via Web Updater](https://lab.flipper.net/?url=https://unleashedflip.com/builds/flipper-z-f7-update-noanims-'${DRONE_TAG}'.tgz&channel=dev-cfw&version='${DRONE_TAG}')' >> CHANGELOG.md + - echo '### [Version without custom animations - Install via Web Updater](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)' >> CHANGELOG.md environment: FBT_TOOLS_CUSTOM_LINK: from_secret: fbt_link @@ -50,15 +50,17 @@ steps: - name: "Bundle self-update packages" image: kramos/alpine-zip commands: - - mv artifacts-ofw-anims/flipper-z-f7-update-${DRONE_TAG}.tgz artifacts-ofw-anims/flipper-z-f7-update-noanims-${DRONE_TAG}.tgz - - cp artifacts-ofw-anims/flipper-z-f7-update-noanims-${DRONE_TAG}.tgz . + - cp artifacts-ofw-anims/flipper-z-f7-update-${DRONE_TAG}n.tgz . - cp artifacts-default/flipper-z-f7-update-${DRONE_TAG}.tgz . - - zip -r artifacts-ofw-anims/flipper-z-f7-update-noanims-${DRONE_TAG}.zip artifacts-ofw-anims/f7-update-${DRONE_TAG} + - zip -r artifacts-ofw-anims/flipper-z-f7-update-${DRONE_TAG}n.zip artifacts-ofw-anims/f7-update-${DRONE_TAG}n - zip -r artifacts-default/flipper-z-f7-update-${DRONE_TAG}.zip artifacts-default/f7-update-${DRONE_TAG} + - tar czpf artifacts-default/flipper-z-any-scripts-${DRONE_TAG}.tgz scripts debug - rm -rf artifacts-ofw-anims/f7-update-${DRONE_TAG} - rm -rf artifacts-default/f7-update-${DRONE_TAG} - ls -laS artifacts-ofw-anims - ls -laS artifacts-default + - mv artifacts-default/ ${DRONE_TAG} + - ls -laS ${DRONE_TAG} - name: "Upload default to updates srv" image: appleboy/drone-scp @@ -72,8 +74,14 @@ steps: port: from_secret: dep_port target: - from_secret: dep_target - source: flipper-z-f7-update-${DRONE_TAG}.tgz + from_secret: dep_target_new + source: + - ${DRONE_TAG}/*.tgz + - ${DRONE_TAG}/*.zip + - ${DRONE_TAG}/*.json + - ${DRONE_TAG}/*.elf + - ${DRONE_TAG}/*.dfu + - ${DRONE_TAG}/*.bin - name: "Upload no-anims to updates srv" image: appleboy/drone-scp @@ -87,8 +95,19 @@ steps: port: from_secret: dep_port target: - from_secret: dep_target - source: flipper-z-f7-update-noanims-${DRONE_TAG}.tgz + from_secret: dep_target_noanim + source: flipper-z-f7-update-${DRONE_TAG}n.tgz + + - name: "Trigger update server reindex" + image: hfdj/fztools + pull: never + environment: + UPD_KEY: + from_secret: git_update_serv_token + UPD_URL: + from_secret: git_update_server_url + commands: + - curl -X POST -F 'key='$UPD_KEY'' $UPD_URL - name: "Do Github release" image: ddplugins/github-release @@ -100,8 +119,8 @@ steps: api_key: from_secret: github_apikey files: - - artifacts-default/*.tgz - - artifacts-default/*.zip + - ${DRONE_TAG}/*.tgz + - ${DRONE_TAG}/*.zip - artifacts-ofw-anims/*.tgz title: ${DRONE_TAG} note: CHANGELOG.md @@ -130,12 +149,12 @@ steps: [-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md) - [-Version without custom animations - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/builds/flipper-z-f7-update-noanims-${DRONE_TAG}.tgz&channel=dev-cfw&version=${DRONE_TAG}) + [-Version without custom animations - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-${DRONE_TAG}n.tgz&channel=release-cfw&version=${DRONE_TAG}n) - [-Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/builds/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=dev-cfw&version=${DRONE_TAG})" + [-Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/${DRONE_TAG}/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=release-cfw&version=${DRONE_TAG})" document: - - artifacts-default/flipper-z-f7-update-${DRONE_TAG}.tgz + - ${DRONE_TAG}/flipper-z-f7-update-${DRONE_TAG}.tgz - name: "Send discord notification" image: appleboy/drone-discord @@ -156,14 +175,138 @@ steps: [-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md) - [-Version without custom animations - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/builds/flipper-z-f7-update-noanims-${DRONE_TAG}.tgz&channel=dev-cfw&version=${DRONE_TAG}) + [-Version without custom animations - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-${DRONE_TAG}n.tgz&channel=release-cfw&version=${DRONE_TAG}n) - [-Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/builds/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=dev-cfw&version=${DRONE_TAG})" + [-Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/${DRONE_TAG}/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=release-cfw&version=${DRONE_TAG})" trigger: + branch: + - release event: - tag node: typ: haupt + +--- +kind: pipeline +type: docker +name: "Dev build" + +steps: + - name: "Update submodules" + image: alpine/git + commands: + - git submodule sync + - git -c protocol.version=2 submodule update --init --force --recursive + - git submodule foreach git config --local gc.auto 0 + - git log -1 --format='%H' + + - name: "Build dev FW" + image: hfdj/fztools + pull: never + commands: + - export DIST_SUFFIX=${DRONE_TAG} + - export WORKFLOW_BRANCH_OR_TAG=dev-cfw + - ./fbt COMPACT=1 DEBUG=0 updater_package + - mkdir artifacts-default + - mv dist/f7-C/* artifacts-default/ + - ls -laS artifacts-default + - ls -laS artifacts-default/f7-update-${DRONE_TAG} + environment: + FBT_TOOLS_CUSTOM_LINK: + from_secret: fbt_link + + - name: "Bundle self-update packages" + image: kramos/alpine-zip + commands: + - cp artifacts-default/flipper-z-f7-update-${DRONE_TAG}.tgz . + - rm -rf artifacts-default/f7-update-${DRONE_TAG} + - ls -laS artifacts-default + - mv artifacts-default/ dev + - ls -laS dev + + - name: "Clean dev folder" + image: appleboy/drone-ssh + settings: + host: + from_secret: dep_host + username: + from_secret: dep_user + password: + from_secret: dep_passwd + port: + from_secret: dep_port + command_timeout: 1m + script: + - cd web/unleashedflip.com/public_html/fw/dev + - ls -laS + - rm -f ./* + - ls -laS + + - name: "Upload default to updates srv" + image: appleboy/drone-scp + settings: + host: + from_secret: dep_host + username: + from_secret: dep_user + password: + from_secret: dep_passwd + port: + from_secret: dep_port + target: + from_secret: dep_target_new + source: + - dev/*.tgz + - dev/*.zip + - dev/*.json + - dev/*.elf + - dev/*.dfu + - dev/*.bin + + - name: "Trigger update server reindex" + image: hfdj/fztools + pull: never + environment: + UPD_KEY: + from_secret: git_update_serv_token + UPD_URL: + from_secret: git_update_server_url + commands: + - curl -X POST -F 'key='$UPD_KEY'' $UPD_URL + + - name: "Send files to telegram" + image: appleboy/drone-telegram + settings: + token: + from_secret: tgtoken + to: + from_secret: tgid_dev + format: markdown + message: "Unleashed firmware dev build successful! + + + Version: {{build.tag}} + + Build: {{build.number}} + + SHA: {{commit.sha}} + + + Commit: {{commit.message}} + + + [-Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/dev/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=dev-cfw&version=${DRONE_TAG})" + document: + - dev/flipper-z-f7-update-${DRONE_TAG}.tgz + +trigger: + branch: + - dev + event: + - push + +node: + typ: haupt From 37159c75066cf5fe06a2bc583d1dae1b6d17c2bb Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 23 Nov 2022 18:03:48 +0300 Subject: [PATCH 9/9] Fix dev builds --- .drone.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.drone.yml b/.drone.yml index 11b49e3cb..b5893575d 100644 --- a/.drone.yml +++ b/.drone.yml @@ -207,13 +207,13 @@ steps: image: hfdj/fztools pull: never commands: - - export DIST_SUFFIX=${DRONE_TAG} + - export DIST_SUFFIX=${DRONE_BUILD_NUMBER} - export WORKFLOW_BRANCH_OR_TAG=dev-cfw - ./fbt COMPACT=1 DEBUG=0 updater_package - mkdir artifacts-default - mv dist/f7-C/* artifacts-default/ - ls -laS artifacts-default - - ls -laS artifacts-default/f7-update-${DRONE_TAG} + - ls -laS artifacts-default/f7-update-${DRONE_BUILD_NUMBER} environment: FBT_TOOLS_CUSTOM_LINK: from_secret: fbt_link @@ -221,8 +221,8 @@ steps: - name: "Bundle self-update packages" image: kramos/alpine-zip commands: - - cp artifacts-default/flipper-z-f7-update-${DRONE_TAG}.tgz . - - rm -rf artifacts-default/f7-update-${DRONE_TAG} + - cp artifacts-default/flipper-z-f7-update-${DRONE_BUILD_NUMBER}.tgz . + - rm -rf artifacts-default/f7-update-${DRONE_BUILD_NUMBER} - ls -laS artifacts-default - mv artifacts-default/ dev - ls -laS dev @@ -288,8 +288,6 @@ steps: message: "Unleashed firmware dev build successful! - Version: {{build.tag}} - Build: {{build.number}} SHA: {{commit.sha}} @@ -298,9 +296,9 @@ steps: Commit: {{commit.message}} - [-Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/dev/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=dev-cfw&version=${DRONE_TAG})" + [-Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/dev/flipper-z-f7-update-${DRONE_BUILD_NUMBER}.tgz&channel=dev-cfw&version=${DRONE_BUILD_NUMBER})" document: - - dev/flipper-z-f7-update-${DRONE_TAG}.tgz + - dev/flipper-z-f7-update-${DRONE_BUILD_NUMBER}.tgz trigger: branch: